[
  {
    "path": ".github/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 contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment include:\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 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 address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at love@v2ray.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]\n\n[homepage]: http://contributor-covenant.org\n[version]: http://contributor-covenant.org/version/1/4/\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_cn.md",
    "content": "---\nname: V2Ray 程序问题\nabout: \"提交一个 V2Ray 的程序问题报告。\"\n---\n\n除非特殊情况，请完整填写所有问题。不按模板发的 issue 将直接被关闭。\n如果你遇到的问题不是 V2Ray 的 bug，比如你不清楚要如何配置，请使用[Discussion](https://github.com/v2fly/discussion/issues)进行讨论。\n\n1) 你正在使用哪个版本的 V2Ray？（如果服务器和客户端使用了不同版本，请注明）\n\n2) 你的使用场景是什么？比如使用 Chrome 通过 Socks/VMess 代理观看 YouTube 视频。\n\n3) 你看到的不正常的现象是什么？（请描述具体现象，比如访问超时，TLS 证书错误等）\n\n4) 你期待看到的正确表现是怎样的？\n\n5) 请附上你的配置（提交 Issue 前请隐藏服务器端IP地址）。\n\n服务器端配置:\n\n```javascript\n    // 在这里附上服务器端配置文件\n```\n\n客户端配置:\n\n```javascript\n    // 在这里附上客户端配置\n```\n\n6)  请附上出错时软件输出的错误日志。在 Linux 中，日志通常在 `/var/log/v2ray/error.log` 文件中。\n\n服务器端错误日志:\n\n```javascript\n    // 在这里附上服务器端日志\n```\n\n客户端错误日志:\n\n```javascript\n    // 在这里附上客户端日志\n```\n\n7) 请附上访问日志。在 Linux 中，日志通常在 `/var/log/v2ray/access.log` 文件中。\n\n```javascript\n    // 在这里附上服务器端日志\n```\n\n8) 其它相关的配置文件（如 Nginx）和相关日志。\n\n9) 如果 V2Ray 无法启动，请附上 `--test` 输出。\n\n通常的命令为 `/usr/bin/v2ray/v2ray --test --config /etc/v2ray/config.json`。请按实际情况修改。\n\n10) 如果 V2Ray 服务运行不正常，请附上 journal 日志。\n\n通常的命令为 `journalctl -u v2ray`。\n\n请预览一下你填的内容再提交。\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_en.md",
    "content": "---\nname: Bug report\nabout: \"Create a bug report to help us improve\"\n---\n\nPlease answer all the questions with enough information. All issues not following this template will be closed immediately.\nIf you are not sure if your question is truely a bug in V2Ray, please discuss it [here](https://github.com/v2fly/discussion/issues) first.\n\n1) What version of V2Ray are you using (If you deploy different version on server and client, please explicitly point out)?\n\n2) What's your scenario of using V2Ray? E.g., Watching YouTube videos in Chrome via Socks/VMess proxy.\n\n3) What did you see? (Please describe in detail, such as timeout, fake TLS certificate etc)\n\n4) What's your expectation?\n\n5) Please attach your configuration file (**Mask IP addresses before submit this issue**).\n\nServer configuration:\n\n```javascript\n    // Please attach your server configuration here.\n```\n\nClient configuration:\n\n```javascript\n    // Please attach your client configuration here.\n```\n\n6) Please attach error logs, especially the bottom lines if the file is large. Error log file is usually at `/var/log/v2ray/error.log` on Linux.\n\nServer error log:\n\n```javascript\n    // Please attach your server error log here.\n```\n\nClient error log:\n\n```javascript\n    // Please attach your client error log here.\n```\n\n7) Please attach access log. Access log is usually at '/var/log/v2ray/access.log' on Linux.\n\n```javascript\n    // Please attach your server access log here.\n```\n\n8) Other configurations (such as Nginx) and logs.\n\n9) If V2Ray doesn't run, please attach output from `--test`.\n\nThe command is usually `/usr/bin/v2ray/v2ray --test --config /etc/v2ray/config.json`, but may vary according to your scenario.\n\n10) If V2Ray service doesn't run, please attach journal log.\n\nUsual command is `journalctl -u v2ray`.\n\nPlease review your issue before submitting."
  },
  {
    "path": ".github/ISSUE_TEMPLATE/other_en.md",
    "content": "---\nname: Other\nabout: \"其它问题请使用 https://github.com/v2fly/discussion/issues 进行讨论 / Please discuss other issues at https://github.com/v2fly/discussion/issues\"\n---\n\n如果你遇到的问题不是 V2Ray 的 bug，比如你不清楚要如何配置，请使用[Discussion](https://github.com/v2fly/discussion/issues)进行讨论。\n\n此 Issue 会被立即关闭。\n\nIf you are not sure if your question is truely a bug in V2Ray, please discuss it [here](https://github.com/v2fly/discussion/issues) first.\n\nThis issue will be closed immediately.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "content": "如果你遇到的问题不是 V2Ray 的 bug，比如你不清楚要如何配置，请使用[Discussion](https://github.com/v2fly/discussion/issues)进行讨论。\n\n此 Issue 会被立即关闭。\n\nIf you are not sure if your question is truely a bug in V2Ray, please discuss it [here](https://github.com/v2fly/discussion/issues) first.\n\nThis issue will be closed immediately.\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://help.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    open-pull-requests-limit: 10\n\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\"\n    schedule:\n      interval: \"daily\"\n"
  },
  {
    "path": ".github/linters/.golangci.yml",
    "content": "run:\n  timeout: 5m\n  skip-files:\n    - generated.*\n\nissues:\n  new: true\n\nlinters:\n  enable:\n    - bodyclose\n    - depguard\n    - gocritic\n    - gofmt\n    - goimports\n    - golint\n    - goprintffuncname\n    - gosimple\n    - govet\n    - ineffassign\n    - misspell\n    - nakedret\n    - noctx\n    - nolintlint\n    - rowserrcheck\n    - scopelint\n    - staticcheck\n    - structcheck\n    - stylecheck\n    - typecheck\n    - unconvert\n    - unparam\n    - varcheck\n    - whitespace\n  disable:\n    - deadcode\n    - errcheck\n    - unused\n"
  },
  {
    "path": ".github/pull_request_template.md",
    "content": "Please Move to https://github.com/v2fly/v2ray-core/pulls\n"
  },
  {
    "path": ".github/workflows/codeql-analysis.yml",
    "content": "name: CodeQL\n\non:\n  push:\n    branches: [master]\n    paths:\n      - \"**/*.go\"\n  pull_request:\n    branches: [master]\n    types: [opened, synchronize, reopened]\n    paths:\n      - \"**/*.go\"\n  schedule:\n    - cron: '0 0 * * 1'\n\njobs:\n  analyze:\n    if: github.repository != 'v2ray/v2ray-core'\n    runs-on: ubuntu-latest\n    strategy:\n      fail-fast: false\n      matrix:\n        # Override automatic language detection by changing the below list\n        # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']\n        language: ['go']\n        # Learn more...\n        # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection\n\n    steps:\n    - name: Checkout repository\n      uses: actions/checkout@v2\n      with:\n        # We must fetch at least the immediate parents so that if this is\n        # a pull request then we can checkout the head.\n        fetch-depth: 2\n\n    # If this run was triggered by a pull request event, then checkout\n    # the head of the pull request instead of the merge commit.\n    - run: git checkout HEAD^2\n      if: ${{ github.event_name == 'pull_request' }}\n\n    # Initializes the CodeQL tools for scanning.\n    - name: Initialize CodeQL\n      uses: github/codeql-action/init@v1\n      with:\n        languages: ${{ matrix.language }}\n        # If you wish to specify custom queries, you can do so here or in a config file.\n        # By default, queries listed here will override any specified in a config file. \n        # Prefix the list here with \"+\" to use these queries and those in the config file.\n        # queries: ./path/to/local/query, your-org/your-repo/queries@main\n\n    # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).\n    # If this step fails, then you should remove it and run the build manually (see below)\n    - name: Autobuild\n      uses: github/codeql-action/autobuild@v1\n\n    # ℹ️ Command-line programs to run using the OS shell.\n    # 📚 https://git.io/JvXDl\n\n    # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines\n    #    and modify them (or add more) to build your code if your project\n    #    uses a compiled language\n\n    #- run: |\n    #   make bootstrap\n    #   make release\n\n    - name: Perform CodeQL Analysis\n      uses: github/codeql-action/analyze@v1\n"
  },
  {
    "path": ".github/workflows/coverage.yml",
    "content": "name: Coverage\n\non:\n  push:\n    branches: [master]\n    paths:\n      - \"**/*.go\"\n\njobs:\n  coverage:\n    if: github.repository != 'v2ray/v2ray-core'\n    runs-on: ubuntu-latest\n    steps:\n      - name: Set up Go 1.x\n        uses: actions/setup-go@v2\n        with:\n          go-version: ^1.15\n\n      - name: Checkout codebase\n        uses: actions/checkout@v2\n\n      - name: Cache go module\n        uses: actions/cache@v2\n        id: cache-gomodules\n        with:\n          path: ~/go/pkg/mod\n          key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}\n          restore-keys: |\n            ${{ runner.os }}-go-\n\n      - name: Get dependencies\n        if: steps.cache-gomodules.outputs.cache-hit != 'true'\n        run: |\n          go get -v -t -d ./...\n\n      - name: Run coverage\n        run: ./testing/coverage/coverall2\n\n      - name: Upload coverage to Codecov\n        uses: codecov/codecov-action@v1\n        with:\n          file: ./coverage.txt\n          fail_ci_if_error: true\n"
  },
  {
    "path": ".github/workflows/linter.yml",
    "content": "name: Linter\n\non:\n  push:\n    branches: [master]\n    paths:\n      - \"**/*.go\"\n  pull_request:\n    branches: [master]\n    types: [opened, synchronize, reopened]\n    paths:\n      - \"**/*.go\"\n\njobs:\n  lint:\n    if: github.repository != 'v2ray/v2ray-core'\n    runs-on: ubuntu-latest\n    steps:\n      - name: Set up Go 1.x\n        uses: actions/setup-go@v2\n        with:\n          go-version: ^1.15\n\n      - name: Checkout codebase\n        uses: actions/checkout@v2\n\n      - name: golangci-lint\n        uses: golangci/golangci-lint-action@v2\n        with:\n          version: v1.31\n          args: --config=.github/linters/.golangci.yml\n          only-new-issues: true\n"
  },
  {
    "path": ".github/workflows/sign.yml",
    "content": "name: Sign\n\non:\n  release:\n    types: [released]\n\njobs:\n  sign:\n    if: github.repository != 'v2ray/v2ray-core'\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout default branch\n        uses: actions/checkout@v2\n\n      - name: Grant it execution permission\n        run: |\n          chmod +x $GITHUB_WORKSPACE/release/requestsign_github.sh\n          chmod +x $GITHUB_WORKSPACE/release/requestsign.sh\n\n      - name: Invoke release signing\n        env:\n          SIGN_SERVICE_PASSWORD: ${{ secrets.SIGN_SERVICE_PASSWORD }}\n          SIGN_SERIVCE_URL: ${{ secrets.SIGN_SERIVCE_URL }}\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: $GITHUB_WORKSPACE/release/requestsign_github.sh\n"
  },
  {
    "path": ".github/workflows/stale.yml",
    "content": "name: Mark stale issues and pull requests\n\non:\n  schedule:\n    - cron: \"30 1 * * *\"\n\njobs:\n  stale:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/stale@v3.0.13\n        with:\n          repo-token: ${{ secrets.GITHUB_TOKEN }}\n          stale-issue-message: \"This issue is stale because it has been open 120 days with no activity. Remove stale label or comment or this will be closed in 5 days\"\n          stale-pr-message: 'It has been open 120 days with no activity. Remove stale label or comment or this will be closed in 5 days'\n          days-before-stale: 120\n          days-before-close: 5\n"
  },
  {
    "path": ".github/workflows/test.yml",
    "content": "name: Test\n\non:\n  push:\n    branches: [master]\n    paths:\n      - \"**/*.go\"\n      - \"go.mod\"\n      - \"go.sum\"\n  pull_request:\n    branches: [master]\n    types: [opened, synchronize, reopened]\n    paths:\n      - \"**/*.go\"\n      - \"go.mod\"\n      - \"go.sum\"\n\njobs:\n  test:\n    if: github.repository != 'v2ray/v2ray-core'\n    runs-on: ${{ matrix.os }}\n    strategy:\n      matrix:\n        os: [windows-latest, ubuntu-latest, macos-latest]\n    steps:\n      - name: Set up Go 1.x\n        uses: actions/setup-go@v2\n        with:\n          go-version: ^1.15\n\n      - name: Checkout codebase\n        uses: actions/checkout@v2\n\n      - name: Cache go module\n        uses: actions/cache@v2\n        with:\n          path: ~/go/pkg/mod\n          key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}\n          restore-keys: ${{ runner.os }}-go-\n\n      - name: Test\n        run: go test -timeout 1h -v ./...\n"
  },
  {
    "path": ".github/workflows/updateGeofile.yml",
    "content": "name: Update Geofiles\n\non:\n  schedule:\n    - cron: \"0 0 * * FRI\"\n\njobs:\n  update:\n    if: github.repository == 'v2fly/v2ray-core'\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout codebase\n        uses: actions/checkout@v2\n\n      - name: Download\n        run: |\n          curl -L -o release/config/geoip.dat \"https://github.com/v2fly/geoip/raw/release/geoip.dat\"\n          curl -L -o release/config/geosite.dat \"https://github.com/v2fly/domain-list-community/raw/release/dlc.dat\"\n\n      - name: push\n        run: |\n          git config --local user.email \"action@github.com\"\n          git config --local user.name \"GitHub Action\"\n          git commit -am \"update geoip, geosite\"\n          git push -v --progress\n"
  },
  {
    "path": ".gitignore",
    "content": "*.DS_Store\nbazel-*\n.idea"
  },
  {
    "path": "Dockerfile",
    "content": "############################\n# STEP 1 build executable binary\n############################\nFROM golang:alpine AS builder\n\nRUN apk update && apk add --no-cache git bash wget curl\nWORKDIR /build\nRUN git clone --progress https://github.com/v2fly/v2ray-core.git . && \\\n    bash ./release/user-package.sh nosource noconf codename=$(git describe --abbrev=0 --tags) buildname=docker-fly abpathtgz=/tmp/v2ray.tgz\n\n############################\n# STEP 2 build a small image\n############################\nFROM alpine\n\nLABEL maintainer \"V2Fly Community <admin@v2fly.org>\"\nCOPY --from=builder /tmp/v2ray.tgz /tmp\nRUN apk update && apk add ca-certificates && \\\n    mkdir -p /usr/bin/v2ray && \\\n    tar xvfz /tmp/v2ray.tgz -C /usr/bin/v2ray\n\n#ENTRYPOINT [\"/usr/bin/v2ray/v2ray\"]\nENV PATH /usr/bin/v2ray:$PATH\nCMD [\"v2ray\", \"-config=/etc/v2ray/config.json\"]\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015-2020 V2Fly Community\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "README.md",
    "content": "# Move To https://github.com/v2fly/v2ray-core\n\n***\n\n# Project V\n\n[![GitHub Test Badge][1]][2] [![codecov.io][3]][4] [![GoDoc][5]][6] [![codebeat][7]][8] [![Downloads][9]][10] [![Downloads][11]][12]\n\n[1]: https://github.com/v2fly/v2ray-core/workflows/Test/badge.svg \"GitHub Test Badge\"\n[2]: https://github.com/v2fly/v2ray-core/actions \"GitHub Actions Page\"\n[3]: https://codecov.io/gh/v2fly/v2ray-core/branch/master/graph/badge.svg?branch=master \"Coverage Badge\"\n[4]: https://codecov.io/gh/v2fly/v2ray-core?branch=master \"Codecov Status\"\n[5]: https://godoc.org/v2ray.com/core?status.svg \"GoDoc Badge\"\n[6]: https://godoc.org/v2ray.com/core \"GoDoc\"\n[7]: https://goreportcard.com/badge/github.com/v2fly/v2ray-core \"Goreportcard Badge\"\n[8]: https://goreportcard.com/report/github.com/v2fly/v2ray-core \"Goreportcard Result\"\n[9]: https://img.shields.io/github/downloads/v2ray/v2ray-core/total.svg \"v2ray/v2ray-core downloads count\"\n[10]: https://github.com/v2ray/v2ray-core/releases \"v2ray/v2ray-core release page\"\n[11]: https://img.shields.io/github/downloads/v2fly/v2ray-core/total.svg \"v2fly/v2ray-core downloads count\"\n[12]: https://github.com/v2fly/v2ray-core/releases \"v2fly/v2ray-core release page\"\n\nProject V is a set of network tools that help you to build your own computer network. It secures your network connections and thus protects your privacy. See [our website](https://www.v2fly.org/) for more information.\n\n## License\n\n[The MIT License (MIT)](https://raw.githubusercontent.com/v2fly/v2ray-core/master/LICENSE)\n\n## Credits\n\nThis repo relies on the following third-party projects:\n\n- In production:\n  - [gorilla/websocket](https://github.com/gorilla/websocket)\n  - [gRPC](https://google.golang.org/grpc)\n- For testing only:\n  - [miekg/dns](https://github.com/miekg/dns)\n  - [h12w/socks](https://github.com/h12w/socks)\n"
  },
  {
    "path": "SECURITY.md",
    "content": "# 安全策略 Security Policy\n\n## 受支持的版本 Supported Versions\n\n目前 v2ray-core 项目由 [V2Fly 社区](https://github.com/v2fly) 继续提供代码维护，由于精力有限且项目复杂度较高，只维护主线代码的功能和安全性完整。原则上主页的兼容性保证继续遵循，\n如有例外另行说明。\n\nCurrently v2ray-core project is maintained by [V2Fly community](https://github.com/v2fly). Feature and security guarantee may only be limited to the\nmaster branch, though we would still try our best to follow the compatiblity claims listed on the official website.\n\n\n## 汇报安全风险 Reporting a Vulnerability\n\n使用邮箱: security |at| v2fly.org。\n\nReport to email: security |at| v2fly.org.\n\nGPG public key:\n\n```\npub   rsa4096 2020-06-02 [SC] [有效至：2022-01-02]\n      E2E35E27914FB007C0D4B6DDB117BA3BE8B494A7\nuid           [ 绝对 ] V2Fly Developers <dev@v2fly.org>\nsub   rsa4096 2020-06-02 [E] [有效至：2022-01-02]\nsub   rsa4096 2020-11-08 [S] [有效至：2022-01-02] // 用于 Debian / Ubuntu 签名\n\n\n-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBF7V7pQBEACozcw4/BlPgFWaz4AdN8HKSrCDLlN+/g7m4AKZIo13fAnDh+sJ\n2H4NrWNr0xxgovbco5Xw4OSSwY1BuUhnb4AmIyxbwqUQD2UADe5xD6gMBwNiJTP4\n02VCHhh7DnWTeLbAsUgRotxUCxsWVvd2F08SYGfJggOVftOnG+VNnwzTOvHWFVEw\n1Pv1DaY7bKSA0voACerRbAPCYqhmElAGJHYNjBMaxqCaWFJWpAFfBxkvS1FDVyZk\nBsABhn6sOcGJn8EYSHUIXhWwqtkQCjBB4OOik+Jn+S2DFGyk5l1NrGRQtX8C0BYn\nnc7VaxtFOp5fnJ4y0GNd4AM9KO0/Ojosi6b64l407Fj9i9OXznmZUACQw2u+VcL3\nqNy768hsTmka3pXzpRHZwYcOLOEr3jGHmLOtXgQ656OjF8Xd9DJ4cB42X8iBeqTp\niQchHIdBpnu27ZbBFy09OMak+STB5zA0JmxDaC8b48mVkc0BMRXdYl7wWXJsEJf1\nroAOr3RCBKiE840w0PLOTnUljfqazPYTwzs91oP+SeZjBmGOpaAh7bh5BVOpzPSE\nbdA61/n01GEb5bpOKpaTi9GviF3RCbfFnLKJnBq0vHvW9BqKTVFRPAKkBGuOPBdy\n8MBNY+VY/2aP3ukZUoYe8Ypl9Q7dVPRjnoWaH0sEMzftoh+3s7GSSgAylQARAQAB\ntCBWMkZseSBEZXZlbG9wZXJzIDxkZXZAdjJmbHkub3JnPokCVAQTAQgAPgIbAwUL\nCQgHAgYVCgkICwIEFgIDAQIeAQIXgBYhBOLjXieRT7AHwNS23bEXujvotJSnBQJf\np4leBQkC+1DKAAoJELEXujvotJSn124P/0swu9POvEQtxVlRzNh2VjAGHZ5NEDnl\npMrhfC5ryCYtlVS/kc2WwRhIRHKzr9nbamgSxUCiyLagfnIjhIvAohun49grYNzG\nMZWRURiuFrCnYbD7juJTvfbzZCzJk7LPsdnqHWr8fYcOZMTOZVzQiQB2jUx2KeRm\nyV8aV21Z8gMLqSGjs06a0UaRbKB0FSysTURm91/jFmiH43aG1s/LcB9/lKf5HpNl\n9or6LrEOrokAwtkMSBYTqm7Dp1j+cK0iOMw2CmMqmQZkV+i6msYrQRiX/X6YufiM\nwfMMSdOZOz9KG+k+C6N1swSbGeDMrJfnDUDbvrAXKhDjNgY7UBwbk69Abd7Y9aQz\n/jVmrFEWt4lisBxglBot60CRUTM2boK/uQS5zBCJhemeg14F9Q/FRiUTlS8jQoeK\nPWeK2lagYJS8lpJZLXkqe4xSpjCgoT0Z+lYSfTjx+T0AFF+xz5E243Lb5kDxwnR9\nY5CZt3vV6GWBYOt9MEL3pk7AnYyNT1y1KIiMyONh/Z1koUdHr4J9exllnsmAJQUa\nW/j0UtVsLsvUjFv9RTr9w5p/U0J0VLIN0YOpx4wYaBEwFIa8lsL+Ey1Vphkvvjfz\nuMRAHe4v+axWb1f1hVCBjtyCVyvzf+i9RTAYsBJ3MJ0C8cvvrm10N9B7MHh0JZA5\nPcJSilailp1TuQINBF7V7pQBEADkQdO75smeKnmPt0/aNNlb7JDOSWW5VY0kYgx3\n6Toh139JstIQ2xz0CLSGReizUFB6eR3DXmezLrmhkgN2Aq5A+hCtFAJwWKuKr1HS\nusvJ1el9h0oh7IO+tF8E/gNYwWfabjPX27FGVCHR1qG7ffN51Bghrnwi1T4YC98E\nR9EGU6N0Xs9DeIJL9WQPH/DF22251i/OAXkqKVGn3PNe2cBsp0yKxr9mlSyzjrha\nKXokPiPcvNqlnkiDCgfiRj7c2C2Lyl9PoEiGpsNZaCZYkMPgjM0xiLenQddwRyOU\nz2cLG3d8WdCTRyHSZd/YQtSi5R6AnkJEsVtUiDN5zwNFVpQlTq3jNHsVUpjFU2nK\nourTZVCCLbAC60VTdxLN6eFO0f+lS2WjyJ7uZ9SGbS6uP0jMNphH/QjVF848bWXs\n1CuZty5QQY7+MTNUAhSWWntrpTkdXYqT0zUqiOc1YNnkfg3hvC4d0dbnFTfcyZnB\nSg8e7/9n6+ms75/deYgnLuA6h7pkIcflm7pUMfVKXKz5Vlc8FC9ia0UtobeKBKqi\njObfiO/zmNL0HQBeX0e8GkJrCyv6ikD8cUqsmVtgw7jdxGsV0SL5CddDnGKsc68O\npGDmkAuRqR3QtXju/4r7a8IEVveGWc3rUvddYrtqbbCNWCN0JKX13PEvbNAm+2eD\nMGQtcQARAQABiQI8BBgBCAAmAhsMFiEE4uNeJ5FPsAfA1LbdsRe6O+i0lKcFAl+n\ndwcFCQL7PnMACgkQsRe6O+i0lKeWfxAApopL5I9p4btmkcLIg2lkA1n+czFekbdr\n2tjFKrBER4QWkyDCUE8QaVo/ECveTHmnxrTB/djW6xqPVS77PL8xOATIYTo6qU38\noTCB1T7/P2L9qI72BzcRY5f9ZPyJhCtrkvjCPzjUjw+ZIPIOgQcWgKHWnE+OyUKD\n0GkVEUME3QP5S4Nr3XGrgS7oxDAmD52u7pn0mSk5WmEcLW0oGwsVdc4aDXxpX+u/\ngkBZysmAuomPov7iXVosMakl+4rz30yPcrL9A81m1WAeB3PGkpaO3B++8Ql+FBCQ\nOrLtPn/nnIzEuAXB1Hd8vYzxtRM2CZvhRExM7xofnhkBJOtR/ddfbJa7H5+Aruc0\n4S0JIaqMCrC6tZezjTACAzrWULmZZGmrHbLrmXBuLk0huRkeIRnDzHP+DoE2UciL\n3hR9EGOHX9O/dGb3bb3y11LAf7GI28ZG7So1GeoFkEOga1IJnsBnXCqwM8vbDDWq\n/7aLb3/m0gT7DUfjeXKfWPJXcnaq8r4llHzDn2i6ax4Uq/brCOLj9ovVGIctZTbt\nyvsFOc1bVkSuUM+pMkCtBx80/sJSB2Nu94S6osdaUlRE+jaCcqEbPd+G68Yd0Khi\nCL8zF1a3dX1dpuVFTLNpXOgrviGBzXQmzFeil7mWFs0l+1XZOPz9nhmRrMn6wV3n\ni4KItRSJAXy5Ag0EX6d5hQEQAMsVyLTXdybeei2nWDb5jtzzC3AtSnPWtKG4B86C\nBXncaZpU43hKI3oduW2+42eM8n8KTvO11r9xv4zKATfaHBZq2hkKZdDQjuSstovr\na3hapHHknHeNVTg3yuiakKzpr6FK23W/GE1lJfhz254v9+dRV0KazWksXvpGEdgI\n+6sC4Nr5bKgJVEQibyrrL0gmzlVB/oQU/W4eGvk21zmgMlHri+edBLpVtlCmn7k/\n0t+2X9D1Pq2nkjMUurB9EJ1z24LMldmPOl6P7iJCx9kSUjcHrEg56q5VSZq50FAj\nDeSjAqsdussI8cdstCMktE9nhizxVKFXpbXifqoYfJwCo23wFqQJpyPgQqHIT12s\nGWRUa/MF6hRYg/5CyeadDmkmnKPTPjmQ2S2SFNXX7xs+dZKvIvXP30z4cpuVY8i8\nchZSRNb8K0L9T0Jme7CPm28F6lvDUkNDQ1WErXZruHbOKwQOfQBdXK3nedOiUpBt\n401HVlGUJSInfEb3JXU01tRqnnzI/y5z7cWCGEMEa6TeaCrMbVvl8xeAA1w/nw0y\nzHz6/Pnf4TITuCH22aa7+xfgpq8gRLhUUws89mbQT+9fd8tT65+Q8xcaLCyzrLAq\nzND5sVZ4/PwaYc8UNZcHjeQR7aYWI1xgr/IwY1wyDWZLbWgkk0HVxpvYdMEpJryD\nAyMdABEBAAGJBHIEGAEIACYWIQTi414nkU+wB8DUtt2xF7o76LSUpwUCX6d5hQIb\nAgUJAim2AAJACRCxF7o76LSUp8F0IAQZAQgAHRYhBK8FZLGpNMztuW02YbJOz+X/\nddOBBQJfp3mFAAoJELJOz+X/ddOBNKQP/0nwIC4R9gQhY53vME7VA7elIrBiSM6d\nVa26a7J1nrCcpDAE7Lp0TqzrDMqyen+IL4X5QK5sKTgenYTgjppEJIQn+Wup54ix\nI+YOQ8MVLfN6/3QPACWMngSPRF+UKDg4hyTCEL+/GCgTp58oXrl/YIO6Oqt5drog\nw4+4ufU1/eKTb2ruGULGl9jZvFSZpLdsvJ19xJB2kC1k8GVNu7MnUL+S2pU/9kO4\n5EZ/jEa1wT45zev+HdmzX5TYW6SLaI9HKHMqbQz2EHc3tRYIDaz3FE3s4VdMjqpp\ne42SvkOYaguc6cXToDbzBmU+iWGlXCTHfNhxwxoUYcKZlDEkEtvSYHJOb0k9eqbT\ngvMb5GjbAgqqwOBwtN3v790j8jEG+cdXR3qHcEx0bw3F2Bd18U7j946OxHLKE5Xk\n2sWEG422maVrE9o1DdeTV5oDFNNPBzqfjgGBZCCKrjkpldhDOHeoDU2aFMJ7yVqw\nZwKwJ5f8fdNS13UnQVwGsZ2BsW1cox5ZGZ/C5A7mfSF1WAgJcYIw4M2JQbDn4Yuw\nyqjyg53lT3OurBONbEZ7unnsLqpT9qKwZ1qCemqGRJieXXxJwl7G4gBgZbH0rBJR\n6dhbyt4c2JE8MMdC65mDWneltNM6pttC/j5jCuvIlZGACZ91UuLLediJJWAlOJ+1\nfBQ0m8TD6d8ZrakP/RFMLZrxh9WPaFB43sW/b1Fq2h933HQ29oSQFuXhsHsx1Vaq\nHTRTcBB7kywAr9+zMYsOsk0/WnoZNGoMkUWu/gFkb6CdUcsdEumgyZ8S24VoBCHB\nT1fD/8eOA5K82hwAFcKbPwuuTLtf9b9HB4/xsObfcczTeqIknzIPsGlgVz4w1c9a\nStSo4iI4bCSLL+/mqiXZ+ArXJ/z4Vejl92fNLWVOlOrjkBV+AY6iAFCCsxJ1O5ud\n5a5r1bUeBXd0BcQ1m/hpjawMC1y0SkIBTQCgxIQoPoxJ27hHNIN1R2nkqfY9vboQ\n7O0uIHF8fmuz93xg68ZTW0JHwOw4Mz88lGibE2laHApjKWZAtF/i+LlhbnewtESL\nEuGTT7gt7cSHgnBiDEIm5UJVEGeM0sMReztxy9V7glohH5DV8GpVK/GncKlsrh1K\nBuEuz7IrqKlBzhsDy0SrNZpX7EzsiU1uvoA6teT4EPey8qXH+7WR9B2ad1Zc5yE3\nzv4BpnWkkJp8qdYu4fdCs/mrmnBR5G1YdOAIlNWhU74Wdyq+W4HfTWMgvJHmElnZ\nUvQ9RDTWnw2+3n2ATeLf9ZwW1g4/Dqh55OaLtJZo5me8vU9W+vkm34xzfVfD/mus\nljogw5eiGyj8j3lUVjYWu28l/bz0zDUueWmHhV8E8z0Cn7OhrHPpUCHx2Aep\n=quYd\n-----END PGP PUBLIC KEY BLOCK-----\n\n```\n"
  },
  {
    "path": "WORKSPACE",
    "content": "workspace(name = \"v2ray_core\")\n"
  },
  {
    "path": "annotations.go",
    "content": "package core\n\n// Annotation is a concept in V2Ray. This struct is only for documentation. It is not used anywhere.\n// Annotations begin with \"v2ray:\" in comment, as metadata of functions or types.\ntype Annotation struct {\n\t// API is for types or functions that can be used in other libs. Possible values are:\n\t//\n\t// * v2ray:api:beta for types or functions that are ready for use, but maybe changed in the future.\n\t// * v2ray:api:stable for types or functions with guarantee of backward compatibility.\n\t// * v2ray:api:deprecated for types or functions that should not be used anymore.\n\t//\n\t// Types or functions without api annotation should not be used externally.\n\tAPI string\n}\n"
  },
  {
    "path": "app/app.go",
    "content": "// Package app contains feature implementations of V2Ray. The features may be enabled during runtime.\npackage app\n"
  },
  {
    "path": "app/commander/commander.go",
    "content": "// +build !confonly\n\npackage commander\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n\nimport (\n\t\"context\"\n\t\"net\"\n\t\"sync\"\n\n\t\"google.golang.org/grpc\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/signal/done\"\n\t\"v2ray.com/core/features/outbound\"\n)\n\n// Commander is a V2Ray feature that provides gRPC methods to external clients.\ntype Commander struct {\n\tsync.Mutex\n\tserver   *grpc.Server\n\tservices []Service\n\tohm      outbound.Manager\n\ttag      string\n}\n\n// NewCommander creates a new Commander based on the given config.\nfunc NewCommander(ctx context.Context, config *Config) (*Commander, error) {\n\tc := &Commander{\n\t\ttag: config.Tag,\n\t}\n\n\tcommon.Must(core.RequireFeatures(ctx, func(om outbound.Manager) {\n\t\tc.ohm = om\n\t}))\n\n\tfor _, rawConfig := range config.Service {\n\t\tconfig, err := rawConfig.GetInstance()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\trawService, err := common.CreateObject(ctx, config)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tservice, ok := rawService.(Service)\n\t\tif !ok {\n\t\t\treturn nil, newError(\"not a Service.\")\n\t\t}\n\t\tc.services = append(c.services, service)\n\t}\n\n\treturn c, nil\n}\n\n// Type implements common.HasType.\nfunc (c *Commander) Type() interface{} {\n\treturn (*Commander)(nil)\n}\n\n// Start implements common.Runnable.\nfunc (c *Commander) Start() error {\n\tc.Lock()\n\tc.server = grpc.NewServer()\n\tfor _, service := range c.services {\n\t\tservice.Register(c.server)\n\t}\n\tc.Unlock()\n\n\tlistener := &OutboundListener{\n\t\tbuffer: make(chan net.Conn, 4),\n\t\tdone:   done.New(),\n\t}\n\n\tgo func() {\n\t\tif err := c.server.Serve(listener); err != nil {\n\t\t\tnewError(\"failed to start grpc server\").Base(err).AtError().WriteToLog()\n\t\t}\n\t}()\n\n\tif err := c.ohm.RemoveHandler(context.Background(), c.tag); err != nil {\n\t\tnewError(\"failed to remove existing handler\").WriteToLog()\n\t}\n\n\treturn c.ohm.AddHandler(context.Background(), &Outbound{\n\t\ttag:      c.tag,\n\t\tlistener: listener,\n\t})\n}\n\n// Close implements common.Closable.\nfunc (c *Commander) Close() error {\n\tc.Lock()\n\tdefer c.Unlock()\n\n\tif c.server != nil {\n\t\tc.server.Stop()\n\t\tc.server = nil\n\t}\n\n\treturn nil\n}\n\nfunc init() {\n\tcommon.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, cfg interface{}) (interface{}, error) {\n\t\treturn NewCommander(ctx, cfg.(*Config))\n\t}))\n}\n"
  },
  {
    "path": "app/commander/config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: app/commander/config.proto\n\npackage commander\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n\tserial \"v2ray.com/core/common/serial\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\n// Config is the settings for Commander.\ntype Config struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Tag of the outbound handler that handles grpc connections.\n\tTag string `protobuf:\"bytes,1,opt,name=tag,proto3\" json:\"tag,omitempty\"`\n\t// Services that supported by this server. All services must implement Service\n\t// interface.\n\tService []*serial.TypedMessage `protobuf:\"bytes,2,rep,name=service,proto3\" json:\"service,omitempty\"`\n}\n\nfunc (x *Config) Reset() {\n\t*x = Config{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_commander_config_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Config) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Config) ProtoMessage() {}\n\nfunc (x *Config) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_commander_config_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Config.ProtoReflect.Descriptor instead.\nfunc (*Config) Descriptor() ([]byte, []int) {\n\treturn file_app_commander_config_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *Config) GetTag() string {\n\tif x != nil {\n\t\treturn x.Tag\n\t}\n\treturn \"\"\n}\n\nfunc (x *Config) GetService() []*serial.TypedMessage {\n\tif x != nil {\n\t\treturn x.Service\n\t}\n\treturn nil\n}\n\nvar File_app_commander_config_proto protoreflect.FileDescriptor\n\nvar file_app_commander_config_proto_rawDesc = []byte{\n\t0x0a, 0x1a, 0x61, 0x70, 0x70, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x65, 0x72, 0x2f,\n\t0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x18, 0x76, 0x32,\n\t0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x63, 0x6f, 0x6d,\n\t0x6d, 0x61, 0x6e, 0x64, 0x65, 0x72, 0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x73,\n\t0x65, 0x72, 0x69, 0x61, 0x6c, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73,\n\t0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x5c, 0x0a, 0x06, 0x43, 0x6f, 0x6e,\n\t0x66, 0x69, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,\n\t0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x40, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,\n\t0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,\n\t0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61,\n\t0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x07,\n\t0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x42, 0x59, 0x0a, 0x1c, 0x63, 0x6f, 0x6d, 0x2e, 0x76,\n\t0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x63, 0x6f,\n\t0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x65, 0x72, 0x50, 0x01, 0x5a, 0x1c, 0x76, 0x32, 0x72, 0x61, 0x79,\n\t0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x63, 0x6f,\n\t0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x65, 0x72, 0xaa, 0x02, 0x18, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e,\n\t0x43, 0x6f, 0x72, 0x65, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,\n\t0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_app_commander_config_proto_rawDescOnce sync.Once\n\tfile_app_commander_config_proto_rawDescData = file_app_commander_config_proto_rawDesc\n)\n\nfunc file_app_commander_config_proto_rawDescGZIP() []byte {\n\tfile_app_commander_config_proto_rawDescOnce.Do(func() {\n\t\tfile_app_commander_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_commander_config_proto_rawDescData)\n\t})\n\treturn file_app_commander_config_proto_rawDescData\n}\n\nvar file_app_commander_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)\nvar file_app_commander_config_proto_goTypes = []interface{}{\n\t(*Config)(nil),              // 0: v2ray.core.app.commander.Config\n\t(*serial.TypedMessage)(nil), // 1: v2ray.core.common.serial.TypedMessage\n}\nvar file_app_commander_config_proto_depIdxs = []int32{\n\t1, // 0: v2ray.core.app.commander.Config.service:type_name -> v2ray.core.common.serial.TypedMessage\n\t1, // [1:1] is the sub-list for method output_type\n\t1, // [1:1] is the sub-list for method input_type\n\t1, // [1:1] is the sub-list for extension type_name\n\t1, // [1:1] is the sub-list for extension extendee\n\t0, // [0:1] is the sub-list for field type_name\n}\n\nfunc init() { file_app_commander_config_proto_init() }\nfunc file_app_commander_config_proto_init() {\n\tif File_app_commander_config_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_app_commander_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Config); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_app_commander_config_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   1,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_app_commander_config_proto_goTypes,\n\t\tDependencyIndexes: file_app_commander_config_proto_depIdxs,\n\t\tMessageInfos:      file_app_commander_config_proto_msgTypes,\n\t}.Build()\n\tFile_app_commander_config_proto = out.File\n\tfile_app_commander_config_proto_rawDesc = nil\n\tfile_app_commander_config_proto_goTypes = nil\n\tfile_app_commander_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "app/commander/config.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.app.commander;\noption csharp_namespace = \"V2Ray.Core.App.Commander\";\noption go_package = \"v2ray.com/core/app/commander\";\noption java_package = \"com.v2ray.core.app.commander\";\noption java_multiple_files = true;\n\nimport \"common/serial/typed_message.proto\";\n\n// Config is the settings for Commander.\nmessage Config {\n  // Tag of the outbound handler that handles grpc connections.\n  string tag = 1;\n  // Services that supported by this server. All services must implement Service\n  // interface.\n  repeated v2ray.core.common.serial.TypedMessage service = 2;\n}\n"
  },
  {
    "path": "app/commander/errors.generated.go",
    "content": "package commander\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "app/commander/outbound.go",
    "content": "// +build !confonly\n\npackage commander\n\nimport (\n\t\"context\"\n\t\"sync\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/signal/done\"\n\t\"v2ray.com/core/transport\"\n)\n\n// OutboundListener is a net.Listener for listening gRPC connections.\ntype OutboundListener struct {\n\tbuffer chan net.Conn\n\tdone   *done.Instance\n}\n\nfunc (l *OutboundListener) add(conn net.Conn) {\n\tselect {\n\tcase l.buffer <- conn:\n\tcase <-l.done.Wait():\n\t\tconn.Close() // nolint: errcheck\n\tdefault:\n\t\tconn.Close() // nolint: errcheck\n\t}\n}\n\n// Accept implements net.Listener.\nfunc (l *OutboundListener) Accept() (net.Conn, error) {\n\tselect {\n\tcase <-l.done.Wait():\n\t\treturn nil, newError(\"listen closed\")\n\tcase c := <-l.buffer:\n\t\treturn c, nil\n\t}\n}\n\n// Close implement net.Listener.\nfunc (l *OutboundListener) Close() error {\n\tcommon.Must(l.done.Close())\nL:\n\tfor {\n\t\tselect {\n\t\tcase c := <-l.buffer:\n\t\t\tc.Close() // nolint: errcheck\n\t\tdefault:\n\t\t\tbreak L\n\t\t}\n\t}\n\treturn nil\n}\n\n// Addr implements net.Listener.\nfunc (l *OutboundListener) Addr() net.Addr {\n\treturn &net.TCPAddr{\n\t\tIP:   net.IP{0, 0, 0, 0},\n\t\tPort: 0,\n\t}\n}\n\n// Outbound is a outbound.Handler that handles gRPC connections.\ntype Outbound struct {\n\ttag      string\n\tlistener *OutboundListener\n\taccess   sync.RWMutex\n\tclosed   bool\n}\n\n// Dispatch implements outbound.Handler.\nfunc (co *Outbound) Dispatch(ctx context.Context, link *transport.Link) {\n\tco.access.RLock()\n\n\tif co.closed {\n\t\tcommon.Interrupt(link.Reader)\n\t\tcommon.Interrupt(link.Writer)\n\t\tco.access.RUnlock()\n\t\treturn\n\t}\n\n\tcloseSignal := done.New()\n\tc := net.NewConnection(net.ConnectionInputMulti(link.Writer), net.ConnectionOutputMulti(link.Reader), net.ConnectionOnClose(closeSignal))\n\tco.listener.add(c)\n\tco.access.RUnlock()\n\t<-closeSignal.Wait()\n}\n\n// Tag implements outbound.Handler.\nfunc (co *Outbound) Tag() string {\n\treturn co.tag\n}\n\n// Start implements common.Runnable.\nfunc (co *Outbound) Start() error {\n\tco.access.Lock()\n\tco.closed = false\n\tco.access.Unlock()\n\treturn nil\n}\n\n// Close implements common.Closable.\nfunc (co *Outbound) Close() error {\n\tco.access.Lock()\n\tdefer co.access.Unlock()\n\n\tco.closed = true\n\treturn co.listener.Close()\n}\n"
  },
  {
    "path": "app/commander/service.go",
    "content": "// +build !confonly\n\npackage commander\n\nimport (\n\t\"google.golang.org/grpc\"\n)\n\n// Service is a Commander service.\ntype Service interface {\n\t// Register registers the service itself to a gRPC server.\n\tRegister(*grpc.Server)\n}\n"
  },
  {
    "path": "app/dispatcher/config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: app/dispatcher/config.proto\n\npackage dispatcher\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype SessionConfig struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *SessionConfig) Reset() {\n\t*x = SessionConfig{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_dispatcher_config_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *SessionConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SessionConfig) ProtoMessage() {}\n\nfunc (x *SessionConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_dispatcher_config_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SessionConfig.ProtoReflect.Descriptor instead.\nfunc (*SessionConfig) Descriptor() ([]byte, []int) {\n\treturn file_app_dispatcher_config_proto_rawDescGZIP(), []int{0}\n}\n\ntype Config struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tSettings *SessionConfig `protobuf:\"bytes,1,opt,name=settings,proto3\" json:\"settings,omitempty\"`\n}\n\nfunc (x *Config) Reset() {\n\t*x = Config{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_dispatcher_config_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Config) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Config) ProtoMessage() {}\n\nfunc (x *Config) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_dispatcher_config_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Config.ProtoReflect.Descriptor instead.\nfunc (*Config) Descriptor() ([]byte, []int) {\n\treturn file_app_dispatcher_config_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *Config) GetSettings() *SessionConfig {\n\tif x != nil {\n\t\treturn x.Settings\n\t}\n\treturn nil\n}\n\nvar File_app_dispatcher_config_proto protoreflect.FileDescriptor\n\nvar file_app_dispatcher_config_proto_rawDesc = []byte{\n\t0x0a, 0x1b, 0x61, 0x70, 0x70, 0x2f, 0x64, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72,\n\t0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x19, 0x76,\n\t0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x69,\n\t0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x22, 0x15, 0x0a, 0x0d, 0x53, 0x65, 0x73, 0x73,\n\t0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x22,\n\t0x4e, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x44, 0x0a, 0x08, 0x73, 0x65, 0x74,\n\t0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x76, 0x32,\n\t0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x69, 0x73,\n\t0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43,\n\t0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x42,\n\t0x5c, 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72,\n\t0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72,\n\t0x50, 0x01, 0x5a, 0x1d, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f,\n\t0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x64, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65,\n\t0x72, 0xaa, 0x02, 0x19, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x41,\n\t0x70, 0x70, 0x2e, 0x44, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x62, 0x06, 0x70,\n\t0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_app_dispatcher_config_proto_rawDescOnce sync.Once\n\tfile_app_dispatcher_config_proto_rawDescData = file_app_dispatcher_config_proto_rawDesc\n)\n\nfunc file_app_dispatcher_config_proto_rawDescGZIP() []byte {\n\tfile_app_dispatcher_config_proto_rawDescOnce.Do(func() {\n\t\tfile_app_dispatcher_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_dispatcher_config_proto_rawDescData)\n\t})\n\treturn file_app_dispatcher_config_proto_rawDescData\n}\n\nvar file_app_dispatcher_config_proto_msgTypes = make([]protoimpl.MessageInfo, 2)\nvar file_app_dispatcher_config_proto_goTypes = []interface{}{\n\t(*SessionConfig)(nil), // 0: v2ray.core.app.dispatcher.SessionConfig\n\t(*Config)(nil),        // 1: v2ray.core.app.dispatcher.Config\n}\nvar file_app_dispatcher_config_proto_depIdxs = []int32{\n\t0, // 0: v2ray.core.app.dispatcher.Config.settings:type_name -> v2ray.core.app.dispatcher.SessionConfig\n\t1, // [1:1] is the sub-list for method output_type\n\t1, // [1:1] is the sub-list for method input_type\n\t1, // [1:1] is the sub-list for extension type_name\n\t1, // [1:1] is the sub-list for extension extendee\n\t0, // [0:1] is the sub-list for field type_name\n}\n\nfunc init() { file_app_dispatcher_config_proto_init() }\nfunc file_app_dispatcher_config_proto_init() {\n\tif File_app_dispatcher_config_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_app_dispatcher_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*SessionConfig); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_dispatcher_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Config); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_app_dispatcher_config_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   2,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_app_dispatcher_config_proto_goTypes,\n\t\tDependencyIndexes: file_app_dispatcher_config_proto_depIdxs,\n\t\tMessageInfos:      file_app_dispatcher_config_proto_msgTypes,\n\t}.Build()\n\tFile_app_dispatcher_config_proto = out.File\n\tfile_app_dispatcher_config_proto_rawDesc = nil\n\tfile_app_dispatcher_config_proto_goTypes = nil\n\tfile_app_dispatcher_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "app/dispatcher/config.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.app.dispatcher;\noption csharp_namespace = \"V2Ray.Core.App.Dispatcher\";\noption go_package = \"v2ray.com/core/app/dispatcher\";\noption java_package = \"com.v2ray.core.app.dispatcher\";\noption java_multiple_files = true;\n\nmessage SessionConfig {\n  reserved 1;\n}\n\nmessage Config {\n  SessionConfig settings = 1;\n}\n"
  },
  {
    "path": "app/dispatcher/default.go",
    "content": "// +build !confonly\n\npackage dispatcher\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n\nimport (\n\t\"context\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/log\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/session\"\n\t\"v2ray.com/core/features/outbound\"\n\t\"v2ray.com/core/features/policy\"\n\t\"v2ray.com/core/features/routing\"\n\trouting_session \"v2ray.com/core/features/routing/session\"\n\t\"v2ray.com/core/features/stats\"\n\t\"v2ray.com/core/transport\"\n\t\"v2ray.com/core/transport/pipe\"\n)\n\nvar (\n\terrSniffingTimeout = newError(\"timeout on sniffing\")\n)\n\ntype cachedReader struct {\n\tsync.Mutex\n\treader *pipe.Reader\n\tcache  buf.MultiBuffer\n}\n\nfunc (r *cachedReader) Cache(b *buf.Buffer) {\n\tmb, _ := r.reader.ReadMultiBufferTimeout(time.Millisecond * 100)\n\tr.Lock()\n\tif !mb.IsEmpty() {\n\t\tr.cache, _ = buf.MergeMulti(r.cache, mb)\n\t}\n\tb.Clear()\n\trawBytes := b.Extend(buf.Size)\n\tn := r.cache.Copy(rawBytes)\n\tb.Resize(0, int32(n))\n\tr.Unlock()\n}\n\nfunc (r *cachedReader) readInternal() buf.MultiBuffer {\n\tr.Lock()\n\tdefer r.Unlock()\n\n\tif r.cache != nil && !r.cache.IsEmpty() {\n\t\tmb := r.cache\n\t\tr.cache = nil\n\t\treturn mb\n\t}\n\n\treturn nil\n}\n\nfunc (r *cachedReader) ReadMultiBuffer() (buf.MultiBuffer, error) {\n\tmb := r.readInternal()\n\tif mb != nil {\n\t\treturn mb, nil\n\t}\n\n\treturn r.reader.ReadMultiBuffer()\n}\n\nfunc (r *cachedReader) ReadMultiBufferTimeout(timeout time.Duration) (buf.MultiBuffer, error) {\n\tmb := r.readInternal()\n\tif mb != nil {\n\t\treturn mb, nil\n\t}\n\n\treturn r.reader.ReadMultiBufferTimeout(timeout)\n}\n\nfunc (r *cachedReader) Interrupt() {\n\tr.Lock()\n\tif r.cache != nil {\n\t\tr.cache = buf.ReleaseMulti(r.cache)\n\t}\n\tr.Unlock()\n\tr.reader.Interrupt()\n}\n\n// DefaultDispatcher is a default implementation of Dispatcher.\ntype DefaultDispatcher struct {\n\tohm    outbound.Manager\n\trouter routing.Router\n\tpolicy policy.Manager\n\tstats  stats.Manager\n}\n\nfunc init() {\n\tcommon.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {\n\t\td := new(DefaultDispatcher)\n\t\tif err := core.RequireFeatures(ctx, func(om outbound.Manager, router routing.Router, pm policy.Manager, sm stats.Manager) error {\n\t\t\treturn d.Init(config.(*Config), om, router, pm, sm)\n\t\t}); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn d, nil\n\t}))\n}\n\n// Init initializes DefaultDispatcher.\nfunc (d *DefaultDispatcher) Init(config *Config, om outbound.Manager, router routing.Router, pm policy.Manager, sm stats.Manager) error {\n\td.ohm = om\n\td.router = router\n\td.policy = pm\n\td.stats = sm\n\treturn nil\n}\n\n// Type implements common.HasType.\nfunc (*DefaultDispatcher) Type() interface{} {\n\treturn routing.DispatcherType()\n}\n\n// Start implements common.Runnable.\nfunc (*DefaultDispatcher) Start() error {\n\treturn nil\n}\n\n// Close implements common.Closable.\nfunc (*DefaultDispatcher) Close() error { return nil }\n\nfunc (d *DefaultDispatcher) getLink(ctx context.Context) (*transport.Link, *transport.Link) {\n\topt := pipe.OptionsFromContext(ctx)\n\tuplinkReader, uplinkWriter := pipe.New(opt...)\n\tdownlinkReader, downlinkWriter := pipe.New(opt...)\n\n\tinboundLink := &transport.Link{\n\t\tReader: downlinkReader,\n\t\tWriter: uplinkWriter,\n\t}\n\n\toutboundLink := &transport.Link{\n\t\tReader: uplinkReader,\n\t\tWriter: downlinkWriter,\n\t}\n\n\tsessionInbound := session.InboundFromContext(ctx)\n\tvar user *protocol.MemoryUser\n\tif sessionInbound != nil {\n\t\tuser = sessionInbound.User\n\t}\n\n\tif user != nil && len(user.Email) > 0 {\n\t\tp := d.policy.ForLevel(user.Level)\n\t\tif p.Stats.UserUplink {\n\t\t\tname := \"user>>>\" + user.Email + \">>>traffic>>>uplink\"\n\t\t\tif c, _ := stats.GetOrRegisterCounter(d.stats, name); c != nil {\n\t\t\t\tinboundLink.Writer = &SizeStatWriter{\n\t\t\t\t\tCounter: c,\n\t\t\t\t\tWriter:  inboundLink.Writer,\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif p.Stats.UserDownlink {\n\t\t\tname := \"user>>>\" + user.Email + \">>>traffic>>>downlink\"\n\t\t\tif c, _ := stats.GetOrRegisterCounter(d.stats, name); c != nil {\n\t\t\t\toutboundLink.Writer = &SizeStatWriter{\n\t\t\t\t\tCounter: c,\n\t\t\t\t\tWriter:  outboundLink.Writer,\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn inboundLink, outboundLink\n}\n\nfunc shouldOverride(result SniffResult, domainOverride []string) bool {\n\tfor _, p := range domainOverride {\n\t\tif strings.HasPrefix(result.Protocol(), p) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// Dispatch implements routing.Dispatcher.\nfunc (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destination) (*transport.Link, error) {\n\tif !destination.IsValid() {\n\t\tpanic(\"Dispatcher: Invalid destination.\")\n\t}\n\tob := &session.Outbound{\n\t\tTarget: destination,\n\t}\n\tctx = session.ContextWithOutbound(ctx, ob)\n\n\tinbound, outbound := d.getLink(ctx)\n\tcontent := session.ContentFromContext(ctx)\n\tif content == nil {\n\t\tcontent = new(session.Content)\n\t\tctx = session.ContextWithContent(ctx, content)\n\t}\n\tsniffingRequest := content.SniffingRequest\n\tif destination.Network != net.Network_TCP || !sniffingRequest.Enabled {\n\t\tgo d.routedDispatch(ctx, outbound, destination)\n\t} else {\n\t\tgo func() {\n\t\t\tcReader := &cachedReader{\n\t\t\t\treader: outbound.Reader.(*pipe.Reader),\n\t\t\t}\n\t\t\toutbound.Reader = cReader\n\t\t\tresult, err := sniffer(ctx, cReader)\n\t\t\tif err == nil {\n\t\t\t\tcontent.Protocol = result.Protocol()\n\t\t\t}\n\t\t\tif err == nil && shouldOverride(result, sniffingRequest.OverrideDestinationForProtocol) {\n\t\t\t\tdomain := result.Domain()\n\t\t\t\tnewError(\"sniffed domain: \", domain).WriteToLog(session.ExportIDToError(ctx))\n\t\t\t\tdestination.Address = net.ParseAddress(domain)\n\t\t\t\tob.Target = destination\n\t\t\t}\n\t\t\td.routedDispatch(ctx, outbound, destination)\n\t\t}()\n\t}\n\treturn inbound, nil\n}\n\nfunc sniffer(ctx context.Context, cReader *cachedReader) (SniffResult, error) {\n\tpayload := buf.New()\n\tdefer payload.Release()\n\n\tsniffer := NewSniffer()\n\ttotalAttempt := 0\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil, ctx.Err()\n\t\tdefault:\n\t\t\ttotalAttempt++\n\t\t\tif totalAttempt > 2 {\n\t\t\t\treturn nil, errSniffingTimeout\n\t\t\t}\n\n\t\t\tcReader.Cache(payload)\n\t\t\tif !payload.IsEmpty() {\n\t\t\t\tresult, err := sniffer.Sniff(payload.Bytes())\n\t\t\t\tif err != common.ErrNoClue {\n\t\t\t\t\treturn result, err\n\t\t\t\t}\n\t\t\t}\n\t\t\tif payload.IsFull() {\n\t\t\t\treturn nil, errUnknownContent\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.Link, destination net.Destination) {\n\tvar handler outbound.Handler\n\n\tskipRoutePick := false\n\tif content := session.ContentFromContext(ctx); content != nil {\n\t\tskipRoutePick = content.SkipRoutePick\n\t}\n\n\tif d.router != nil && !skipRoutePick {\n\t\tif route, err := d.router.PickRoute(routing_session.AsRoutingContext(ctx)); err == nil {\n\t\t\ttag := route.GetOutboundTag()\n\t\t\tif h := d.ohm.GetHandler(tag); h != nil {\n\t\t\t\tnewError(\"taking detour [\", tag, \"] for [\", destination, \"]\").WriteToLog(session.ExportIDToError(ctx))\n\t\t\t\thandler = h\n\t\t\t} else {\n\t\t\t\tnewError(\"non existing tag: \", tag).AtWarning().WriteToLog(session.ExportIDToError(ctx))\n\t\t\t}\n\t\t} else {\n\t\t\tnewError(\"default route for \", destination).WriteToLog(session.ExportIDToError(ctx))\n\t\t}\n\t}\n\n\tif handler == nil {\n\t\thandler = d.ohm.GetDefaultHandler()\n\t}\n\n\tif handler == nil {\n\t\tnewError(\"default outbound handler not exist\").WriteToLog(session.ExportIDToError(ctx))\n\t\tcommon.Close(link.Writer)\n\t\tcommon.Interrupt(link.Reader)\n\t\treturn\n\t}\n\n\tif accessMessage := log.AccessMessageFromContext(ctx); accessMessage != nil {\n\t\tif tag := handler.Tag(); tag != \"\" {\n\t\t\taccessMessage.Detour = tag\n\t\t}\n\t\tlog.Record(accessMessage)\n\t}\n\n\thandler.Dispatch(ctx, link)\n}\n"
  },
  {
    "path": "app/dispatcher/dispatcher.go",
    "content": "// +build !confonly\n\npackage dispatcher\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n"
  },
  {
    "path": "app/dispatcher/errors.generated.go",
    "content": "package dispatcher\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "app/dispatcher/sniffer.go",
    "content": "// +build !confonly\n\npackage dispatcher\n\nimport (\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/protocol/bittorrent\"\n\t\"v2ray.com/core/common/protocol/http\"\n\t\"v2ray.com/core/common/protocol/tls\"\n)\n\ntype SniffResult interface {\n\tProtocol() string\n\tDomain() string\n}\n\ntype protocolSniffer func([]byte) (SniffResult, error)\n\ntype Sniffer struct {\n\tsniffer []protocolSniffer\n}\n\nfunc NewSniffer() *Sniffer {\n\treturn &Sniffer{\n\t\tsniffer: []protocolSniffer{\n\t\t\tfunc(b []byte) (SniffResult, error) { return http.SniffHTTP(b) },\n\t\t\tfunc(b []byte) (SniffResult, error) { return tls.SniffTLS(b) },\n\t\t\tfunc(b []byte) (SniffResult, error) { return bittorrent.SniffBittorrent(b) },\n\t\t},\n\t}\n}\n\nvar errUnknownContent = newError(\"unknown content\")\n\nfunc (s *Sniffer) Sniff(payload []byte) (SniffResult, error) {\n\tvar pendingSniffer []protocolSniffer\n\tfor _, s := range s.sniffer {\n\t\tresult, err := s(payload)\n\t\tif err == common.ErrNoClue {\n\t\t\tpendingSniffer = append(pendingSniffer, s)\n\t\t\tcontinue\n\t\t}\n\n\t\tif err == nil && result != nil {\n\t\t\treturn result, nil\n\t\t}\n\t}\n\n\tif len(pendingSniffer) > 0 {\n\t\ts.sniffer = pendingSniffer\n\t\treturn nil, common.ErrNoClue\n\t}\n\n\treturn nil, errUnknownContent\n}\n"
  },
  {
    "path": "app/dispatcher/stats.go",
    "content": "// +build !confonly\n\npackage dispatcher\n\nimport (\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/features/stats\"\n)\n\ntype SizeStatWriter struct {\n\tCounter stats.Counter\n\tWriter  buf.Writer\n}\n\nfunc (w *SizeStatWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {\n\tw.Counter.Add(int64(mb.Len()))\n\treturn w.Writer.WriteMultiBuffer(mb)\n}\n\nfunc (w *SizeStatWriter) Close() error {\n\treturn common.Close(w.Writer)\n}\n\nfunc (w *SizeStatWriter) Interrupt() {\n\tcommon.Interrupt(w.Writer)\n}\n"
  },
  {
    "path": "app/dispatcher/stats_test.go",
    "content": "package dispatcher_test\n\nimport (\n\t\"testing\"\n\n\t. \"v2ray.com/core/app/dispatcher\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n)\n\ntype TestCounter int64\n\nfunc (c *TestCounter) Value() int64 {\n\treturn int64(*c)\n}\n\nfunc (c *TestCounter) Add(v int64) int64 {\n\tx := int64(*c) + v\n\t*c = TestCounter(x)\n\treturn x\n}\n\nfunc (c *TestCounter) Set(v int64) int64 {\n\t*c = TestCounter(v)\n\treturn v\n}\n\nfunc TestStatsWriter(t *testing.T) {\n\tvar c TestCounter\n\twriter := &SizeStatWriter{\n\t\tCounter: &c,\n\t\tWriter:  buf.Discard,\n\t}\n\n\tmb := buf.MergeBytes(nil, []byte(\"abcd\"))\n\tcommon.Must(writer.WriteMultiBuffer(mb))\n\n\tmb = buf.MergeBytes(nil, []byte(\"efg\"))\n\tcommon.Must(writer.WriteMultiBuffer(mb))\n\n\tif c.Value() != 7 {\n\t\tt.Fatal(\"unexpected counter value. want 7, but got \", c.Value())\n\t}\n}\n"
  },
  {
    "path": "app/dns/config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: app/dns/config.proto\n\npackage dns\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n\trouter \"v2ray.com/core/app/router\"\n\tnet \"v2ray.com/core/common/net\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype DomainMatchingType int32\n\nconst (\n\tDomainMatchingType_Full      DomainMatchingType = 0\n\tDomainMatchingType_Subdomain DomainMatchingType = 1\n\tDomainMatchingType_Keyword   DomainMatchingType = 2\n\tDomainMatchingType_Regex     DomainMatchingType = 3\n)\n\n// Enum value maps for DomainMatchingType.\nvar (\n\tDomainMatchingType_name = map[int32]string{\n\t\t0: \"Full\",\n\t\t1: \"Subdomain\",\n\t\t2: \"Keyword\",\n\t\t3: \"Regex\",\n\t}\n\tDomainMatchingType_value = map[string]int32{\n\t\t\"Full\":      0,\n\t\t\"Subdomain\": 1,\n\t\t\"Keyword\":   2,\n\t\t\"Regex\":     3,\n\t}\n)\n\nfunc (x DomainMatchingType) Enum() *DomainMatchingType {\n\tp := new(DomainMatchingType)\n\t*p = x\n\treturn p\n}\n\nfunc (x DomainMatchingType) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (DomainMatchingType) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_app_dns_config_proto_enumTypes[0].Descriptor()\n}\n\nfunc (DomainMatchingType) Type() protoreflect.EnumType {\n\treturn &file_app_dns_config_proto_enumTypes[0]\n}\n\nfunc (x DomainMatchingType) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use DomainMatchingType.Descriptor instead.\nfunc (DomainMatchingType) EnumDescriptor() ([]byte, []int) {\n\treturn file_app_dns_config_proto_rawDescGZIP(), []int{0}\n}\n\ntype NameServer struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tAddress           *net.Endpoint                `protobuf:\"bytes,1,opt,name=address,proto3\" json:\"address,omitempty\"`\n\tPrioritizedDomain []*NameServer_PriorityDomain `protobuf:\"bytes,2,rep,name=prioritized_domain,json=prioritizedDomain,proto3\" json:\"prioritized_domain,omitempty\"`\n\tGeoip             []*router.GeoIP              `protobuf:\"bytes,3,rep,name=geoip,proto3\" json:\"geoip,omitempty\"`\n\tOriginalRules     []*NameServer_OriginalRule   `protobuf:\"bytes,4,rep,name=original_rules,json=originalRules,proto3\" json:\"original_rules,omitempty\"`\n}\n\nfunc (x *NameServer) Reset() {\n\t*x = NameServer{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_dns_config_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *NameServer) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*NameServer) ProtoMessage() {}\n\nfunc (x *NameServer) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_dns_config_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use NameServer.ProtoReflect.Descriptor instead.\nfunc (*NameServer) Descriptor() ([]byte, []int) {\n\treturn file_app_dns_config_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *NameServer) GetAddress() *net.Endpoint {\n\tif x != nil {\n\t\treturn x.Address\n\t}\n\treturn nil\n}\n\nfunc (x *NameServer) GetPrioritizedDomain() []*NameServer_PriorityDomain {\n\tif x != nil {\n\t\treturn x.PrioritizedDomain\n\t}\n\treturn nil\n}\n\nfunc (x *NameServer) GetGeoip() []*router.GeoIP {\n\tif x != nil {\n\t\treturn x.Geoip\n\t}\n\treturn nil\n}\n\nfunc (x *NameServer) GetOriginalRules() []*NameServer_OriginalRule {\n\tif x != nil {\n\t\treturn x.OriginalRules\n\t}\n\treturn nil\n}\n\ntype Config struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Nameservers used by this DNS. Only traditional UDP servers are support at\n\t// the moment. A special value 'localhost' as a domain address can be set to\n\t// use DNS on local system.\n\t//\n\t// Deprecated: Do not use.\n\tNameServers []*net.Endpoint `protobuf:\"bytes,1,rep,name=NameServers,proto3\" json:\"NameServers,omitempty\"`\n\t// NameServer list used by this DNS client.\n\tNameServer []*NameServer `protobuf:\"bytes,5,rep,name=name_server,json=nameServer,proto3\" json:\"name_server,omitempty\"`\n\t// Static hosts. Domain to IP.\n\t// Deprecated. Use static_hosts.\n\t//\n\t// Deprecated: Do not use.\n\tHosts map[string]*net.IPOrDomain `protobuf:\"bytes,2,rep,name=Hosts,proto3\" json:\"Hosts,omitempty\" protobuf_key:\"bytes,1,opt,name=key,proto3\" protobuf_val:\"bytes,2,opt,name=value,proto3\"`\n\t// Client IP for EDNS client subnet. Must be 4 bytes (IPv4) or 16 bytes\n\t// (IPv6).\n\tClientIp    []byte                `protobuf:\"bytes,3,opt,name=client_ip,json=clientIp,proto3\" json:\"client_ip,omitempty\"`\n\tStaticHosts []*Config_HostMapping `protobuf:\"bytes,4,rep,name=static_hosts,json=staticHosts,proto3\" json:\"static_hosts,omitempty\"`\n\t// Tag is the inbound tag of DNS client.\n\tTag string `protobuf:\"bytes,6,opt,name=tag,proto3\" json:\"tag,omitempty\"`\n}\n\nfunc (x *Config) Reset() {\n\t*x = Config{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_dns_config_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Config) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Config) ProtoMessage() {}\n\nfunc (x *Config) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_dns_config_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Config.ProtoReflect.Descriptor instead.\nfunc (*Config) Descriptor() ([]byte, []int) {\n\treturn file_app_dns_config_proto_rawDescGZIP(), []int{1}\n}\n\n// Deprecated: Do not use.\nfunc (x *Config) GetNameServers() []*net.Endpoint {\n\tif x != nil {\n\t\treturn x.NameServers\n\t}\n\treturn nil\n}\n\nfunc (x *Config) GetNameServer() []*NameServer {\n\tif x != nil {\n\t\treturn x.NameServer\n\t}\n\treturn nil\n}\n\n// Deprecated: Do not use.\nfunc (x *Config) GetHosts() map[string]*net.IPOrDomain {\n\tif x != nil {\n\t\treturn x.Hosts\n\t}\n\treturn nil\n}\n\nfunc (x *Config) GetClientIp() []byte {\n\tif x != nil {\n\t\treturn x.ClientIp\n\t}\n\treturn nil\n}\n\nfunc (x *Config) GetStaticHosts() []*Config_HostMapping {\n\tif x != nil {\n\t\treturn x.StaticHosts\n\t}\n\treturn nil\n}\n\nfunc (x *Config) GetTag() string {\n\tif x != nil {\n\t\treturn x.Tag\n\t}\n\treturn \"\"\n}\n\ntype NameServer_PriorityDomain struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tType   DomainMatchingType `protobuf:\"varint,1,opt,name=type,proto3,enum=v2ray.core.app.dns.DomainMatchingType\" json:\"type,omitempty\"`\n\tDomain string             `protobuf:\"bytes,2,opt,name=domain,proto3\" json:\"domain,omitempty\"`\n}\n\nfunc (x *NameServer_PriorityDomain) Reset() {\n\t*x = NameServer_PriorityDomain{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_dns_config_proto_msgTypes[2]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *NameServer_PriorityDomain) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*NameServer_PriorityDomain) ProtoMessage() {}\n\nfunc (x *NameServer_PriorityDomain) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_dns_config_proto_msgTypes[2]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use NameServer_PriorityDomain.ProtoReflect.Descriptor instead.\nfunc (*NameServer_PriorityDomain) Descriptor() ([]byte, []int) {\n\treturn file_app_dns_config_proto_rawDescGZIP(), []int{0, 0}\n}\n\nfunc (x *NameServer_PriorityDomain) GetType() DomainMatchingType {\n\tif x != nil {\n\t\treturn x.Type\n\t}\n\treturn DomainMatchingType_Full\n}\n\nfunc (x *NameServer_PriorityDomain) GetDomain() string {\n\tif x != nil {\n\t\treturn x.Domain\n\t}\n\treturn \"\"\n}\n\ntype NameServer_OriginalRule struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tRule string `protobuf:\"bytes,1,opt,name=rule,proto3\" json:\"rule,omitempty\"`\n\tSize uint32 `protobuf:\"varint,2,opt,name=size,proto3\" json:\"size,omitempty\"`\n}\n\nfunc (x *NameServer_OriginalRule) Reset() {\n\t*x = NameServer_OriginalRule{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_dns_config_proto_msgTypes[3]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *NameServer_OriginalRule) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*NameServer_OriginalRule) ProtoMessage() {}\n\nfunc (x *NameServer_OriginalRule) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_dns_config_proto_msgTypes[3]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use NameServer_OriginalRule.ProtoReflect.Descriptor instead.\nfunc (*NameServer_OriginalRule) Descriptor() ([]byte, []int) {\n\treturn file_app_dns_config_proto_rawDescGZIP(), []int{0, 1}\n}\n\nfunc (x *NameServer_OriginalRule) GetRule() string {\n\tif x != nil {\n\t\treturn x.Rule\n\t}\n\treturn \"\"\n}\n\nfunc (x *NameServer_OriginalRule) GetSize() uint32 {\n\tif x != nil {\n\t\treturn x.Size\n\t}\n\treturn 0\n}\n\ntype Config_HostMapping struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tType   DomainMatchingType `protobuf:\"varint,1,opt,name=type,proto3,enum=v2ray.core.app.dns.DomainMatchingType\" json:\"type,omitempty\"`\n\tDomain string             `protobuf:\"bytes,2,opt,name=domain,proto3\" json:\"domain,omitempty\"`\n\tIp     [][]byte           `protobuf:\"bytes,3,rep,name=ip,proto3\" json:\"ip,omitempty\"`\n\t// ProxiedDomain indicates the mapped domain has the same IP address on this\n\t// domain. V2Ray will use this domain for IP queries. This field is only\n\t// effective if ip is empty.\n\tProxiedDomain string `protobuf:\"bytes,4,opt,name=proxied_domain,json=proxiedDomain,proto3\" json:\"proxied_domain,omitempty\"`\n}\n\nfunc (x *Config_HostMapping) Reset() {\n\t*x = Config_HostMapping{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_dns_config_proto_msgTypes[5]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Config_HostMapping) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Config_HostMapping) ProtoMessage() {}\n\nfunc (x *Config_HostMapping) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_dns_config_proto_msgTypes[5]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Config_HostMapping.ProtoReflect.Descriptor instead.\nfunc (*Config_HostMapping) Descriptor() ([]byte, []int) {\n\treturn file_app_dns_config_proto_rawDescGZIP(), []int{1, 1}\n}\n\nfunc (x *Config_HostMapping) GetType() DomainMatchingType {\n\tif x != nil {\n\t\treturn x.Type\n\t}\n\treturn DomainMatchingType_Full\n}\n\nfunc (x *Config_HostMapping) GetDomain() string {\n\tif x != nil {\n\t\treturn x.Domain\n\t}\n\treturn \"\"\n}\n\nfunc (x *Config_HostMapping) GetIp() [][]byte {\n\tif x != nil {\n\t\treturn x.Ip\n\t}\n\treturn nil\n}\n\nfunc (x *Config_HostMapping) GetProxiedDomain() string {\n\tif x != nil {\n\t\treturn x.ProxiedDomain\n\t}\n\treturn \"\"\n}\n\nvar File_app_dns_config_proto protoreflect.FileDescriptor\n\nvar file_app_dns_config_proto_rawDesc = []byte{\n\t0x0a, 0x14, 0x61, 0x70, 0x70, 0x2f, 0x64, 0x6e, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,\n\t0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x12, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,\n\t0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x1a, 0x18, 0x63, 0x6f, 0x6d, 0x6d,\n\t0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x70,\n\t0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74,\n\t0x2f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f,\n\t0x74, 0x6f, 0x1a, 0x17, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2f, 0x63,\n\t0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xcb, 0x03, 0x0a, 0x0a,\n\t0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x39, 0x0a, 0x07, 0x61, 0x64,\n\t0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x76, 0x32,\n\t0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e,\n\t0x6e, 0x65, 0x74, 0x2e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x07, 0x61, 0x64,\n\t0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x5c, 0x0a, 0x12, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74,\n\t0x69, 0x7a, 0x65, 0x64, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28,\n\t0x0b, 0x32, 0x2d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61,\n\t0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65,\n\t0x72, 0x2e, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e,\n\t0x52, 0x11, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x7a, 0x65, 0x64, 0x44, 0x6f, 0x6d,\n\t0x61, 0x69, 0x6e, 0x12, 0x32, 0x0a, 0x05, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x03,\n\t0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,\n\t0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50,\n\t0x52, 0x05, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x12, 0x52, 0x0a, 0x0e, 0x6f, 0x72, 0x69, 0x67, 0x69,\n\t0x6e, 0x61, 0x6c, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32,\n\t0x2b, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70,\n\t0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e,\n\t0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x0d, 0x6f, 0x72,\n\t0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x1a, 0x64, 0x0a, 0x0e, 0x50,\n\t0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x3a, 0x0a,\n\t0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x76, 0x32,\n\t0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73,\n\t0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54,\n\t0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d,\n\t0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69,\n\t0x6e, 0x1a, 0x36, 0x0a, 0x0c, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c,\n\t0x65, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x75, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,\n\t0x04, 0x72, 0x75, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20,\n\t0x01, 0x28, 0x0d, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x22, 0xc3, 0x04, 0x0a, 0x06, 0x43, 0x6f,\n\t0x6e, 0x66, 0x69, 0x67, 0x12, 0x45, 0x0a, 0x0b, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76,\n\t0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x76, 0x32, 0x72, 0x61,\n\t0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65,\n\t0x74, 0x2e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0b,\n\t0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x12, 0x3f, 0x0a, 0x0b, 0x6e,\n\t0x61, 0x6d, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b,\n\t0x32, 0x1e, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70,\n\t0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72,\n\t0x52, 0x0a, 0x6e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x3f, 0x0a, 0x05,\n\t0x48, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x76, 0x32,\n\t0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73,\n\t0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x45, 0x6e, 0x74,\n\t0x72, 0x79, 0x42, 0x02, 0x18, 0x01, 0x52, 0x05, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x1b, 0x0a,\n\t0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c,\n\t0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x70, 0x12, 0x49, 0x0a, 0x0c, 0x73, 0x74,\n\t0x61, 0x74, 0x69, 0x63, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b,\n\t0x32, 0x26, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70,\n\t0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x48, 0x6f, 0x73,\n\t0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63,\n\t0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x06, 0x20, 0x01,\n\t0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x1a, 0x5b, 0x0a, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x73,\n\t0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,\n\t0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x37, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,\n\t0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,\n\t0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49,\n\t0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,\n\t0x3a, 0x02, 0x38, 0x01, 0x1a, 0x98, 0x01, 0x0a, 0x0b, 0x48, 0x6f, 0x73, 0x74, 0x4d, 0x61, 0x70,\n\t0x70, 0x69, 0x6e, 0x67, 0x12, 0x3a, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01,\n\t0x28, 0x0e, 0x32, 0x26, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,\n\t0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61,\n\t0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65,\n\t0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,\n\t0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x03,\n\t0x20, 0x03, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x70, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78,\n\t0x69, 0x65, 0x64, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09,\n\t0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x69, 0x65, 0x64, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2a,\n\t0x45, 0x0a, 0x12, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e,\n\t0x67, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x46, 0x75, 0x6c, 0x6c, 0x10, 0x00, 0x12,\n\t0x0d, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x10, 0x01, 0x12, 0x0b,\n\t0x0a, 0x07, 0x4b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x52,\n\t0x65, 0x67, 0x65, 0x78, 0x10, 0x03, 0x42, 0x47, 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32,\n\t0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73,\n\t0x50, 0x01, 0x5a, 0x16, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f,\n\t0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x64, 0x6e, 0x73, 0xaa, 0x02, 0x12, 0x56, 0x32, 0x52,\n\t0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x44, 0x6e, 0x73, 0x62,\n\t0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_app_dns_config_proto_rawDescOnce sync.Once\n\tfile_app_dns_config_proto_rawDescData = file_app_dns_config_proto_rawDesc\n)\n\nfunc file_app_dns_config_proto_rawDescGZIP() []byte {\n\tfile_app_dns_config_proto_rawDescOnce.Do(func() {\n\t\tfile_app_dns_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_dns_config_proto_rawDescData)\n\t})\n\treturn file_app_dns_config_proto_rawDescData\n}\n\nvar file_app_dns_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1)\nvar file_app_dns_config_proto_msgTypes = make([]protoimpl.MessageInfo, 6)\nvar file_app_dns_config_proto_goTypes = []interface{}{\n\t(DomainMatchingType)(0),           // 0: v2ray.core.app.dns.DomainMatchingType\n\t(*NameServer)(nil),                // 1: v2ray.core.app.dns.NameServer\n\t(*Config)(nil),                    // 2: v2ray.core.app.dns.Config\n\t(*NameServer_PriorityDomain)(nil), // 3: v2ray.core.app.dns.NameServer.PriorityDomain\n\t(*NameServer_OriginalRule)(nil),   // 4: v2ray.core.app.dns.NameServer.OriginalRule\n\tnil,                               // 5: v2ray.core.app.dns.Config.HostsEntry\n\t(*Config_HostMapping)(nil),        // 6: v2ray.core.app.dns.Config.HostMapping\n\t(*net.Endpoint)(nil),              // 7: v2ray.core.common.net.Endpoint\n\t(*router.GeoIP)(nil),              // 8: v2ray.core.app.router.GeoIP\n\t(*net.IPOrDomain)(nil),            // 9: v2ray.core.common.net.IPOrDomain\n}\nvar file_app_dns_config_proto_depIdxs = []int32{\n\t7,  // 0: v2ray.core.app.dns.NameServer.address:type_name -> v2ray.core.common.net.Endpoint\n\t3,  // 1: v2ray.core.app.dns.NameServer.prioritized_domain:type_name -> v2ray.core.app.dns.NameServer.PriorityDomain\n\t8,  // 2: v2ray.core.app.dns.NameServer.geoip:type_name -> v2ray.core.app.router.GeoIP\n\t4,  // 3: v2ray.core.app.dns.NameServer.original_rules:type_name -> v2ray.core.app.dns.NameServer.OriginalRule\n\t7,  // 4: v2ray.core.app.dns.Config.NameServers:type_name -> v2ray.core.common.net.Endpoint\n\t1,  // 5: v2ray.core.app.dns.Config.name_server:type_name -> v2ray.core.app.dns.NameServer\n\t5,  // 6: v2ray.core.app.dns.Config.Hosts:type_name -> v2ray.core.app.dns.Config.HostsEntry\n\t6,  // 7: v2ray.core.app.dns.Config.static_hosts:type_name -> v2ray.core.app.dns.Config.HostMapping\n\t0,  // 8: v2ray.core.app.dns.NameServer.PriorityDomain.type:type_name -> v2ray.core.app.dns.DomainMatchingType\n\t9,  // 9: v2ray.core.app.dns.Config.HostsEntry.value:type_name -> v2ray.core.common.net.IPOrDomain\n\t0,  // 10: v2ray.core.app.dns.Config.HostMapping.type:type_name -> v2ray.core.app.dns.DomainMatchingType\n\t11, // [11:11] is the sub-list for method output_type\n\t11, // [11:11] is the sub-list for method input_type\n\t11, // [11:11] is the sub-list for extension type_name\n\t11, // [11:11] is the sub-list for extension extendee\n\t0,  // [0:11] is the sub-list for field type_name\n}\n\nfunc init() { file_app_dns_config_proto_init() }\nfunc file_app_dns_config_proto_init() {\n\tif File_app_dns_config_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_app_dns_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*NameServer); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_dns_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Config); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_dns_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*NameServer_PriorityDomain); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_dns_config_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*NameServer_OriginalRule); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_dns_config_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Config_HostMapping); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_app_dns_config_proto_rawDesc,\n\t\t\tNumEnums:      1,\n\t\t\tNumMessages:   6,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_app_dns_config_proto_goTypes,\n\t\tDependencyIndexes: file_app_dns_config_proto_depIdxs,\n\t\tEnumInfos:         file_app_dns_config_proto_enumTypes,\n\t\tMessageInfos:      file_app_dns_config_proto_msgTypes,\n\t}.Build()\n\tFile_app_dns_config_proto = out.File\n\tfile_app_dns_config_proto_rawDesc = nil\n\tfile_app_dns_config_proto_goTypes = nil\n\tfile_app_dns_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "app/dns/config.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.app.dns;\noption csharp_namespace = \"V2Ray.Core.App.Dns\";\noption go_package = \"v2ray.com/core/app/dns\";\noption java_package = \"com.v2ray.core.app.dns\";\noption java_multiple_files = true;\n\nimport \"common/net/address.proto\";\nimport \"common/net/destination.proto\";\nimport \"app/router/config.proto\";\n\nmessage NameServer {\n  v2ray.core.common.net.Endpoint address = 1;\n\n  message PriorityDomain {\n    DomainMatchingType type = 1;\n    string domain = 2;\n  }\n\n  message OriginalRule {\n    string rule = 1;\n    uint32 size = 2;\n  }\n\n  repeated PriorityDomain prioritized_domain = 2;\n  repeated v2ray.core.app.router.GeoIP geoip = 3;\n  repeated OriginalRule original_rules = 4;\n}\n\nenum DomainMatchingType {\n  Full = 0;\n  Subdomain = 1;\n  Keyword = 2;\n  Regex = 3;\n}\n\nmessage Config {\n  // Nameservers used by this DNS. Only traditional UDP servers are support at\n  // the moment. A special value 'localhost' as a domain address can be set to\n  // use DNS on local system.\n  repeated v2ray.core.common.net.Endpoint NameServers = 1 [deprecated = true];\n\n  // NameServer list used by this DNS client.\n  repeated NameServer name_server = 5;\n\n  // Static hosts. Domain to IP.\n  // Deprecated. Use static_hosts.\n  map<string, v2ray.core.common.net.IPOrDomain> Hosts = 2 [deprecated = true];\n\n  // Client IP for EDNS client subnet. Must be 4 bytes (IPv4) or 16 bytes\n  // (IPv6).\n  bytes client_ip = 3;\n\n  message HostMapping {\n    DomainMatchingType type = 1;\n    string domain = 2;\n\n    repeated bytes ip = 3;\n\n    // ProxiedDomain indicates the mapped domain has the same IP address on this\n    // domain. V2Ray will use this domain for IP queries. This field is only\n    // effective if ip is empty.\n    string proxied_domain = 4;\n  }\n\n  repeated HostMapping static_hosts = 4;\n\n  // Tag is the inbound tag of DNS client.\n  string tag = 6;\n}\n"
  },
  {
    "path": "app/dns/dns.go",
    "content": "// Package dns is an implementation of core.DNS feature.\npackage dns\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n"
  },
  {
    "path": "app/dns/dnscommon.go",
    "content": "// +build !confonly\n\npackage dns\n\nimport (\n\t\"encoding/binary\"\n\t\"time\"\n\n\t\"golang.org/x/net/dns/dnsmessage\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/errors\"\n\t\"v2ray.com/core/common/net\"\n\tdns_feature \"v2ray.com/core/features/dns\"\n)\n\n// Fqdn normalize domain make sure it ends with '.'\nfunc Fqdn(domain string) string {\n\tif len(domain) > 0 && domain[len(domain)-1] == '.' {\n\t\treturn domain\n\t}\n\treturn domain + \".\"\n}\n\ntype record struct {\n\tA    *IPRecord\n\tAAAA *IPRecord\n}\n\n// IPRecord is a cacheable item for a resolved domain\ntype IPRecord struct {\n\tReqID  uint16\n\tIP     []net.Address\n\tExpire time.Time\n\tRCode  dnsmessage.RCode\n}\n\nfunc (r *IPRecord) getIPs() ([]net.Address, error) {\n\tif r == nil || r.Expire.Before(time.Now()) {\n\t\treturn nil, errRecordNotFound\n\t}\n\tif r.RCode != dnsmessage.RCodeSuccess {\n\t\treturn nil, dns_feature.RCodeError(r.RCode)\n\t}\n\treturn r.IP, nil\n}\n\nfunc isNewer(baseRec *IPRecord, newRec *IPRecord) bool {\n\tif newRec == nil {\n\t\treturn false\n\t}\n\tif baseRec == nil {\n\t\treturn true\n\t}\n\treturn baseRec.Expire.Before(newRec.Expire)\n}\n\nvar (\n\terrRecordNotFound = errors.New(\"record not found\")\n)\n\ntype dnsRequest struct {\n\treqType dnsmessage.Type\n\tdomain  string\n\tstart   time.Time\n\texpire  time.Time\n\tmsg     *dnsmessage.Message\n}\n\nfunc genEDNS0Options(clientIP net.IP) *dnsmessage.Resource {\n\tif len(clientIP) == 0 {\n\t\treturn nil\n\t}\n\n\tvar netmask int\n\tvar family uint16\n\n\tif len(clientIP) == 4 {\n\t\tfamily = 1\n\t\tnetmask = 24 // 24 for IPV4, 96 for IPv6\n\t} else {\n\t\tfamily = 2\n\t\tnetmask = 96\n\t}\n\n\tb := make([]byte, 4)\n\tbinary.BigEndian.PutUint16(b[0:], family)\n\tb[2] = byte(netmask)\n\tb[3] = 0\n\tswitch family {\n\tcase 1:\n\t\tip := clientIP.To4().Mask(net.CIDRMask(netmask, net.IPv4len*8))\n\t\tneedLength := (netmask + 8 - 1) / 8 // division rounding up\n\t\tb = append(b, ip[:needLength]...)\n\tcase 2:\n\t\tip := clientIP.Mask(net.CIDRMask(netmask, net.IPv6len*8))\n\t\tneedLength := (netmask + 8 - 1) / 8 // division rounding up\n\t\tb = append(b, ip[:needLength]...)\n\t}\n\n\tconst EDNS0SUBNET = 0x08\n\n\topt := new(dnsmessage.Resource)\n\tcommon.Must(opt.Header.SetEDNS0(1350, 0xfe00, true))\n\n\topt.Body = &dnsmessage.OPTResource{\n\t\tOptions: []dnsmessage.Option{\n\t\t\t{\n\t\t\t\tCode: EDNS0SUBNET,\n\t\t\t\tData: b,\n\t\t\t},\n\t\t},\n\t}\n\n\treturn opt\n}\n\nfunc buildReqMsgs(domain string, option IPOption, reqIDGen func() uint16, reqOpts *dnsmessage.Resource) []*dnsRequest {\n\tqA := dnsmessage.Question{\n\t\tName:  dnsmessage.MustNewName(domain),\n\t\tType:  dnsmessage.TypeA,\n\t\tClass: dnsmessage.ClassINET,\n\t}\n\n\tqAAAA := dnsmessage.Question{\n\t\tName:  dnsmessage.MustNewName(domain),\n\t\tType:  dnsmessage.TypeAAAA,\n\t\tClass: dnsmessage.ClassINET,\n\t}\n\n\tvar reqs []*dnsRequest\n\tnow := time.Now()\n\n\tif option.IPv4Enable {\n\t\tmsg := new(dnsmessage.Message)\n\t\tmsg.Header.ID = reqIDGen()\n\t\tmsg.Header.RecursionDesired = true\n\t\tmsg.Questions = []dnsmessage.Question{qA}\n\t\tif reqOpts != nil {\n\t\t\tmsg.Additionals = append(msg.Additionals, *reqOpts)\n\t\t}\n\t\treqs = append(reqs, &dnsRequest{\n\t\t\treqType: dnsmessage.TypeA,\n\t\t\tdomain:  domain,\n\t\t\tstart:   now,\n\t\t\tmsg:     msg,\n\t\t})\n\t}\n\n\tif option.IPv6Enable {\n\t\tmsg := new(dnsmessage.Message)\n\t\tmsg.Header.ID = reqIDGen()\n\t\tmsg.Header.RecursionDesired = true\n\t\tmsg.Questions = []dnsmessage.Question{qAAAA}\n\t\tif reqOpts != nil {\n\t\t\tmsg.Additionals = append(msg.Additionals, *reqOpts)\n\t\t}\n\t\treqs = append(reqs, &dnsRequest{\n\t\t\treqType: dnsmessage.TypeAAAA,\n\t\t\tdomain:  domain,\n\t\t\tstart:   now,\n\t\t\tmsg:     msg,\n\t\t})\n\t}\n\n\treturn reqs\n}\n\n// parseResponse parse DNS answers from the returned payload\nfunc parseResponse(payload []byte) (*IPRecord, error) {\n\tvar parser dnsmessage.Parser\n\th, err := parser.Start(payload)\n\tif err != nil {\n\t\treturn nil, newError(\"failed to parse DNS response\").Base(err).AtWarning()\n\t}\n\tif err := parser.SkipAllQuestions(); err != nil {\n\t\treturn nil, newError(\"failed to skip questions in DNS response\").Base(err).AtWarning()\n\t}\n\n\tnow := time.Now()\n\tipRecord := &IPRecord{\n\t\tReqID:  h.ID,\n\t\tRCode:  h.RCode,\n\t\tExpire: now.Add(time.Second * 600),\n\t}\n\nL:\n\tfor {\n\t\tah, err := parser.AnswerHeader()\n\t\tif err != nil {\n\t\t\tif err != dnsmessage.ErrSectionDone {\n\t\t\t\tnewError(\"failed to parse answer section for domain: \", ah.Name.String()).Base(err).WriteToLog()\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\n\t\tttl := ah.TTL\n\t\tif ttl == 0 {\n\t\t\tttl = 600\n\t\t}\n\t\texpire := now.Add(time.Duration(ttl) * time.Second)\n\t\tif ipRecord.Expire.After(expire) {\n\t\t\tipRecord.Expire = expire\n\t\t}\n\n\t\tswitch ah.Type {\n\t\tcase dnsmessage.TypeA:\n\t\t\tans, err := parser.AResource()\n\t\t\tif err != nil {\n\t\t\t\tnewError(\"failed to parse A record for domain: \", ah.Name).Base(err).WriteToLog()\n\t\t\t\tbreak L\n\t\t\t}\n\t\t\tipRecord.IP = append(ipRecord.IP, net.IPAddress(ans.A[:]))\n\t\tcase dnsmessage.TypeAAAA:\n\t\t\tans, err := parser.AAAAResource()\n\t\t\tif err != nil {\n\t\t\t\tnewError(\"failed to parse A record for domain: \", ah.Name).Base(err).WriteToLog()\n\t\t\t\tbreak L\n\t\t\t}\n\t\t\tipRecord.IP = append(ipRecord.IP, net.IPAddress(ans.AAAA[:]))\n\t\tdefault:\n\t\t\tif err := parser.SkipAnswer(); err != nil {\n\t\t\t\tnewError(\"failed to skip answer\").Base(err).WriteToLog()\n\t\t\t\tbreak L\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t}\n\n\treturn ipRecord, nil\n}\n"
  },
  {
    "path": "app/dns/dnscommon_test.go",
    "content": "// +build !confonly\n\npackage dns\n\nimport (\n\t\"math/rand\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/miekg/dns\"\n\t\"golang.org/x/net/dns/dnsmessage\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/net\"\n)\n\nfunc Test_parseResponse(t *testing.T) {\n\tvar p [][]byte\n\n\tans := new(dns.Msg)\n\tans.Id = 0\n\tp = append(p, common.Must2(ans.Pack()).([]byte))\n\n\tp = append(p, []byte{})\n\n\tans = new(dns.Msg)\n\tans.Id = 1\n\tans.Answer = append(ans.Answer,\n\t\tcommon.Must2(dns.NewRR(\"google.com. IN CNAME m.test.google.com\")).(dns.RR),\n\t\tcommon.Must2(dns.NewRR(\"google.com. IN CNAME fake.google.com\")).(dns.RR),\n\t\tcommon.Must2(dns.NewRR(\"google.com. IN A 8.8.8.8\")).(dns.RR),\n\t\tcommon.Must2(dns.NewRR(\"google.com. IN A 8.8.4.4\")).(dns.RR),\n\t)\n\tp = append(p, common.Must2(ans.Pack()).([]byte))\n\n\tans = new(dns.Msg)\n\tans.Id = 2\n\tans.Answer = append(ans.Answer,\n\t\tcommon.Must2(dns.NewRR(\"google.com. IN CNAME m.test.google.com\")).(dns.RR),\n\t\tcommon.Must2(dns.NewRR(\"google.com. IN CNAME fake.google.com\")).(dns.RR),\n\t\tcommon.Must2(dns.NewRR(\"google.com. IN CNAME m.test.google.com\")).(dns.RR),\n\t\tcommon.Must2(dns.NewRR(\"google.com. IN CNAME test.google.com\")).(dns.RR),\n\t\tcommon.Must2(dns.NewRR(\"google.com. IN AAAA 2001::123:8888\")).(dns.RR),\n\t\tcommon.Must2(dns.NewRR(\"google.com. IN AAAA 2001::123:8844\")).(dns.RR),\n\t)\n\tp = append(p, common.Must2(ans.Pack()).([]byte))\n\n\ttests := []struct {\n\t\tname    string\n\t\twant    *IPRecord\n\t\twantErr bool\n\t}{\n\t\t{\"empty\",\n\t\t\t&IPRecord{0, []net.Address(nil), time.Time{}, dnsmessage.RCodeSuccess},\n\t\t\tfalse,\n\t\t},\n\t\t{\"error\",\n\t\t\tnil,\n\t\t\ttrue,\n\t\t},\n\t\t{\"a record\",\n\t\t\t&IPRecord{1, []net.Address{net.ParseAddress(\"8.8.8.8\"), net.ParseAddress(\"8.8.4.4\")},\n\t\t\t\ttime.Time{}, dnsmessage.RCodeSuccess},\n\t\t\tfalse,\n\t\t},\n\t\t{\"aaaa record\",\n\t\t\t&IPRecord{2, []net.Address{net.ParseAddress(\"2001::123:8888\"), net.ParseAddress(\"2001::123:8844\")}, time.Time{}, dnsmessage.RCodeSuccess},\n\t\t\tfalse,\n\t\t},\n\t}\n\tfor i, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tgot, err := parseResponse(p[i])\n\t\t\tif (err != nil) != tt.wantErr {\n\t\t\t\tt.Errorf(\"handleResponse() error = %v, wantErr %v\", err, tt.wantErr)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif got != nil {\n\t\t\t\t// reset the time\n\t\t\t\tgot.Expire = time.Time{}\n\t\t\t}\n\t\t\tif cmp.Diff(got, tt.want) != \"\" {\n\t\t\t\tt.Errorf(cmp.Diff(got, tt.want))\n\t\t\t\t// t.Errorf(\"handleResponse() = %#v, want %#v\", got, tt.want)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc Test_buildReqMsgs(t *testing.T) {\n\n\tstubID := func() uint16 {\n\t\treturn uint16(rand.Uint32())\n\t}\n\ttype args struct {\n\t\tdomain  string\n\t\toption  IPOption\n\t\treqOpts *dnsmessage.Resource\n\t}\n\ttests := []struct {\n\t\tname string\n\t\targs args\n\t\twant int\n\t}{\n\t\t{\"dual stack\", args{\"test.com\", IPOption{true, true}, nil}, 2},\n\t\t{\"ipv4 only\", args{\"test.com\", IPOption{true, false}, nil}, 1},\n\t\t{\"ipv6 only\", args{\"test.com\", IPOption{false, true}, nil}, 1},\n\t\t{\"none/error\", args{\"test.com\", IPOption{false, false}, nil}, 0},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tif got := buildReqMsgs(tt.args.domain, tt.args.option, stubID, tt.args.reqOpts); !(len(got) == tt.want) {\n\t\t\t\tt.Errorf(\"buildReqMsgs() = %v, want %v\", got, tt.want)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc Test_genEDNS0Options(t *testing.T) {\n\ttype args struct {\n\t\tclientIP net.IP\n\t}\n\ttests := []struct {\n\t\tname string\n\t\targs args\n\t\twant *dnsmessage.Resource\n\t}{\n\t\t// TODO: Add test cases.\n\t\t{\"ipv4\", args{net.ParseIP(\"4.3.2.1\")}, nil},\n\t\t{\"ipv6\", args{net.ParseIP(\"2001::4321\")}, nil},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tif got := genEDNS0Options(tt.args.clientIP); got == nil {\n\t\t\t\tt.Errorf(\"genEDNS0Options() = %v, want %v\", got, tt.want)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestFqdn(t *testing.T) {\n\ttype args struct {\n\t\tdomain string\n\t}\n\ttests := []struct {\n\t\tname string\n\t\targs args\n\t\twant string\n\t}{\n\t\t{\"with fqdn\", args{\"www.v2ray.com.\"}, \"www.v2ray.com.\"},\n\t\t{\"without fqdn\", args{\"www.v2ray.com\"}, \"www.v2ray.com.\"},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tif got := Fqdn(tt.args.domain); got != tt.want {\n\t\t\t\tt.Errorf(\"Fqdn() = %v, want %v\", got, tt.want)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "app/dns/dohdns.go",
    "content": "// +build !confonly\n\npackage dns\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"golang.org/x/net/dns/dnsmessage\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol/dns\"\n\t\"v2ray.com/core/common/session\"\n\t\"v2ray.com/core/common/signal/pubsub\"\n\t\"v2ray.com/core/common/task\"\n\tdns_feature \"v2ray.com/core/features/dns\"\n\t\"v2ray.com/core/features/routing\"\n\t\"v2ray.com/core/transport/internet\"\n)\n\n// DoHNameServer implemented DNS over HTTPS (RFC8484) Wire Format,\n// which is compatible with traditional dns over udp(RFC1035),\n// thus most of the DOH implementation is copied from udpns.go\ntype DoHNameServer struct {\n\tsync.RWMutex\n\tips        map[string]record\n\tpub        *pubsub.Service\n\tcleanup    *task.Periodic\n\treqID      uint32\n\tclientIP   net.IP\n\thttpClient *http.Client\n\tdohURL     string\n\tname       string\n}\n\n// NewDoHNameServer creates DOH client object for remote resolving\nfunc NewDoHNameServer(url *url.URL, dispatcher routing.Dispatcher, clientIP net.IP) (*DoHNameServer, error) {\n\n\tnewError(\"DNS: created Remote DOH client for \", url.String()).AtInfo().WriteToLog()\n\ts := baseDOHNameServer(url, \"DOH\", clientIP)\n\n\t// Dispatched connection will be closed (interrupted) after each request\n\t// This makes DOH inefficient without a keep-alived connection\n\t// See: core/app/proxyman/outbound/handler.go:113\n\t// Using mux (https request wrapped in a stream layer) improves the situation.\n\t// Recommend to use NewDoHLocalNameServer (DOHL:) if v2ray instance is running on\n\t//  a normal network eg. the server side of v2ray\n\ttr := &http.Transport{\n\t\tMaxIdleConns:        30,\n\t\tIdleConnTimeout:     90 * time.Second,\n\t\tTLSHandshakeTimeout: 30 * time.Second,\n\t\tForceAttemptHTTP2:   true,\n\t\tDialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {\n\t\t\tdest, err := net.ParseDestination(network + \":\" + addr)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tlink, err := dispatcher.Dispatch(ctx, dest)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn net.NewConnection(\n\t\t\t\tnet.ConnectionInputMulti(link.Writer),\n\t\t\t\tnet.ConnectionOutputMulti(link.Reader),\n\t\t\t), nil\n\t\t},\n\t}\n\n\tdispatchedClient := &http.Client{\n\t\tTransport: tr,\n\t\tTimeout:   60 * time.Second,\n\t}\n\n\ts.httpClient = dispatchedClient\n\treturn s, nil\n}\n\n// NewDoHLocalNameServer creates DOH client object for local resolving\nfunc NewDoHLocalNameServer(url *url.URL, clientIP net.IP) *DoHNameServer {\n\turl.Scheme = \"https\"\n\ts := baseDOHNameServer(url, \"DOHL\", clientIP)\n\ttr := &http.Transport{\n\t\tIdleConnTimeout:   90 * time.Second,\n\t\tForceAttemptHTTP2: true,\n\t\tDialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {\n\t\t\tdest, err := net.ParseDestination(network + \":\" + addr)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tconn, err := internet.DialSystem(ctx, dest, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn conn, nil\n\t\t},\n\t}\n\ts.httpClient = &http.Client{\n\t\tTimeout:   time.Second * 180,\n\t\tTransport: tr,\n\t}\n\tnewError(\"DNS: created Local DOH client for \", url.String()).AtInfo().WriteToLog()\n\treturn s\n}\n\nfunc baseDOHNameServer(url *url.URL, prefix string, clientIP net.IP) *DoHNameServer {\n\n\ts := &DoHNameServer{\n\t\tips:      make(map[string]record),\n\t\tclientIP: clientIP,\n\t\tpub:      pubsub.NewService(),\n\t\tname:     prefix + \"//\" + url.Host,\n\t\tdohURL:   url.String(),\n\t}\n\ts.cleanup = &task.Periodic{\n\t\tInterval: time.Minute,\n\t\tExecute:  s.Cleanup,\n\t}\n\n\treturn s\n}\n\n// Name returns client name\nfunc (s *DoHNameServer) Name() string {\n\treturn s.name\n}\n\n// Cleanup clears expired items from cache\nfunc (s *DoHNameServer) Cleanup() error {\n\tnow := time.Now()\n\ts.Lock()\n\tdefer s.Unlock()\n\n\tif len(s.ips) == 0 {\n\t\treturn newError(\"nothing to do. stopping...\")\n\t}\n\n\tfor domain, record := range s.ips {\n\t\tif record.A != nil && record.A.Expire.Before(now) {\n\t\t\trecord.A = nil\n\t\t}\n\t\tif record.AAAA != nil && record.AAAA.Expire.Before(now) {\n\t\t\trecord.AAAA = nil\n\t\t}\n\n\t\tif record.A == nil && record.AAAA == nil {\n\t\t\tnewError(s.name, \" cleanup \", domain).AtDebug().WriteToLog()\n\t\t\tdelete(s.ips, domain)\n\t\t} else {\n\t\t\ts.ips[domain] = record\n\t\t}\n\t}\n\n\tif len(s.ips) == 0 {\n\t\ts.ips = make(map[string]record)\n\t}\n\n\treturn nil\n}\n\nfunc (s *DoHNameServer) updateIP(req *dnsRequest, ipRec *IPRecord) {\n\telapsed := time.Since(req.start)\n\n\ts.Lock()\n\trec := s.ips[req.domain]\n\tupdated := false\n\n\tswitch req.reqType {\n\tcase dnsmessage.TypeA:\n\t\tif isNewer(rec.A, ipRec) {\n\t\t\trec.A = ipRec\n\t\t\tupdated = true\n\t\t}\n\tcase dnsmessage.TypeAAAA:\n\t\taddr := make([]net.Address, 0)\n\t\tfor _, ip := range ipRec.IP {\n\t\t\tif len(ip.IP()) == net.IPv6len {\n\t\t\t\taddr = append(addr, ip)\n\t\t\t}\n\t\t}\n\t\tipRec.IP = addr\n\t\tif isNewer(rec.AAAA, ipRec) {\n\t\t\trec.AAAA = ipRec\n\t\t\tupdated = true\n\t\t}\n\t}\n\tnewError(s.name, \" got answer: \", req.domain, \" \", req.reqType, \" -> \", ipRec.IP, \" \", elapsed).AtInfo().WriteToLog()\n\n\tif updated {\n\t\ts.ips[req.domain] = rec\n\t}\n\tswitch req.reqType {\n\tcase dnsmessage.TypeA:\n\t\ts.pub.Publish(req.domain+\"4\", nil)\n\tcase dnsmessage.TypeAAAA:\n\t\ts.pub.Publish(req.domain+\"6\", nil)\n\t}\n\ts.Unlock()\n\tcommon.Must(s.cleanup.Start())\n}\n\nfunc (s *DoHNameServer) newReqID() uint16 {\n\treturn uint16(atomic.AddUint32(&s.reqID, 1))\n}\n\nfunc (s *DoHNameServer) sendQuery(ctx context.Context, domain string, option IPOption) {\n\tnewError(s.name, \" querying: \", domain).AtInfo().WriteToLog(session.ExportIDToError(ctx))\n\n\treqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(s.clientIP))\n\n\tvar deadline time.Time\n\tif d, ok := ctx.Deadline(); ok {\n\t\tdeadline = d\n\t} else {\n\t\tdeadline = time.Now().Add(time.Second * 5)\n\t}\n\n\tfor _, req := range reqs {\n\t\tgo func(r *dnsRequest) {\n\t\t\t// generate new context for each req, using same context\n\t\t\t// may cause reqs all aborted if any one encounter an error\n\t\t\tdnsCtx := context.Background()\n\n\t\t\t// reserve internal dns server requested Inbound\n\t\t\tif inbound := session.InboundFromContext(ctx); inbound != nil {\n\t\t\t\tdnsCtx = session.ContextWithInbound(dnsCtx, inbound)\n\t\t\t}\n\n\t\t\tdnsCtx = session.ContextWithContent(dnsCtx, &session.Content{\n\t\t\t\tProtocol:      \"https\",\n\t\t\t\tSkipRoutePick: true,\n\t\t\t})\n\n\t\t\t// forced to use mux for DOH\n\t\t\tdnsCtx = session.ContextWithMuxPrefered(dnsCtx, true)\n\n\t\t\tvar cancel context.CancelFunc\n\t\t\tdnsCtx, cancel = context.WithDeadline(dnsCtx, deadline)\n\t\t\tdefer cancel()\n\n\t\t\tb, err := dns.PackMessage(r.msg)\n\t\t\tif err != nil {\n\t\t\t\tnewError(\"failed to pack dns query\").Base(err).AtError().WriteToLog()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tresp, err := s.dohHTTPSContext(dnsCtx, b.Bytes())\n\t\t\tif err != nil {\n\t\t\t\tnewError(\"failed to retrieve response\").Base(err).AtError().WriteToLog()\n\t\t\t\treturn\n\t\t\t}\n\t\t\trec, err := parseResponse(resp)\n\t\t\tif err != nil {\n\t\t\t\tnewError(\"failed to handle DOH response\").Base(err).AtError().WriteToLog()\n\t\t\t\treturn\n\t\t\t}\n\t\t\ts.updateIP(r, rec)\n\t\t}(req)\n\t}\n}\n\nfunc (s *DoHNameServer) dohHTTPSContext(ctx context.Context, b []byte) ([]byte, error) {\n\tbody := bytes.NewBuffer(b)\n\treq, err := http.NewRequest(\"POST\", s.dohURL, body)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treq.Header.Add(\"Accept\", \"application/dns-message\")\n\treq.Header.Add(\"Content-Type\", \"application/dns-message\")\n\n\tresp, err := s.httpClient.Do(req.WithContext(ctx))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdefer resp.Body.Close()\n\tif resp.StatusCode != http.StatusOK {\n\t\tio.Copy(ioutil.Discard, resp.Body) // flush resp.Body so that the conn is reusable\n\t\treturn nil, fmt.Errorf(\"DOH server returned code %d\", resp.StatusCode)\n\t}\n\n\treturn ioutil.ReadAll(resp.Body)\n}\n\nfunc (s *DoHNameServer) findIPsForDomain(domain string, option IPOption) ([]net.IP, error) {\n\ts.RLock()\n\trecord, found := s.ips[domain]\n\ts.RUnlock()\n\n\tif !found {\n\t\treturn nil, errRecordNotFound\n\t}\n\n\tvar ips []net.Address\n\tvar lastErr error\n\tif option.IPv6Enable && record.AAAA != nil && record.AAAA.RCode == dnsmessage.RCodeSuccess {\n\t\taaaa, err := record.AAAA.getIPs()\n\t\tif err != nil {\n\t\t\tlastErr = err\n\t\t}\n\t\tips = append(ips, aaaa...)\n\t}\n\n\tif option.IPv4Enable && record.A != nil && record.A.RCode == dnsmessage.RCodeSuccess {\n\t\ta, err := record.A.getIPs()\n\t\tif err != nil {\n\t\t\tlastErr = err\n\t\t}\n\t\tips = append(ips, a...)\n\t}\n\n\tif len(ips) > 0 {\n\t\treturn toNetIP(ips), nil\n\t}\n\n\tif lastErr != nil {\n\t\treturn nil, lastErr\n\t}\n\n\tif (option.IPv4Enable && record.A != nil) || (option.IPv6Enable && record.AAAA != nil) {\n\t\treturn nil, dns_feature.ErrEmptyResponse\n\t}\n\n\treturn nil, errRecordNotFound\n}\n\n// QueryIP is called from dns.Server->queryIPTimeout\nfunc (s *DoHNameServer) QueryIP(ctx context.Context, domain string, option IPOption) ([]net.IP, error) {\n\tfqdn := Fqdn(domain)\n\n\tips, err := s.findIPsForDomain(fqdn, option)\n\tif err != errRecordNotFound {\n\t\tnewError(s.name, \" cache HIT \", domain, \" -> \", ips).Base(err).AtDebug().WriteToLog()\n\t\treturn ips, err\n\t}\n\n\t// ipv4 and ipv6 belong to different subscription groups\n\tvar sub4, sub6 *pubsub.Subscriber\n\tif option.IPv4Enable {\n\t\tsub4 = s.pub.Subscribe(fqdn + \"4\")\n\t\tdefer sub4.Close()\n\t}\n\tif option.IPv6Enable {\n\t\tsub6 = s.pub.Subscribe(fqdn + \"6\")\n\t\tdefer sub6.Close()\n\t}\n\tdone := make(chan interface{})\n\tgo func() {\n\t\tif sub4 != nil {\n\t\t\tselect {\n\t\t\tcase <-sub4.Wait():\n\t\t\tcase <-ctx.Done():\n\t\t\t}\n\t\t}\n\t\tif sub6 != nil {\n\t\t\tselect {\n\t\t\tcase <-sub6.Wait():\n\t\t\tcase <-ctx.Done():\n\t\t\t}\n\t\t}\n\t\tclose(done)\n\t}()\n\ts.sendQuery(ctx, fqdn, option)\n\n\tfor {\n\t\tips, err := s.findIPsForDomain(fqdn, option)\n\t\tif err != errRecordNotFound {\n\t\t\treturn ips, err\n\t\t}\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil, ctx.Err()\n\t\tcase <-done:\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "app/dns/errors.generated.go",
    "content": "package dns\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "app/dns/hosts.go",
    "content": "// +build !confonly\n\npackage dns\n\nimport (\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/strmatcher\"\n\t\"v2ray.com/core/features\"\n)\n\n// StaticHosts represents static domain-ip mapping in DNS server.\ntype StaticHosts struct {\n\tips      [][]net.Address\n\tmatchers *strmatcher.MatcherGroup\n}\n\nvar typeMap = map[DomainMatchingType]strmatcher.Type{\n\tDomainMatchingType_Full:      strmatcher.Full,\n\tDomainMatchingType_Subdomain: strmatcher.Domain,\n\tDomainMatchingType_Keyword:   strmatcher.Substr,\n\tDomainMatchingType_Regex:     strmatcher.Regex,\n}\n\nfunc toStrMatcher(t DomainMatchingType, domain string) (strmatcher.Matcher, error) {\n\tstrMType, f := typeMap[t]\n\tif !f {\n\t\treturn nil, newError(\"unknown mapping type\", t).AtWarning()\n\t}\n\tmatcher, err := strMType.New(domain)\n\tif err != nil {\n\t\treturn nil, newError(\"failed to create str matcher\").Base(err)\n\t}\n\treturn matcher, nil\n}\n\n// NewStaticHosts creates a new StaticHosts instance.\nfunc NewStaticHosts(hosts []*Config_HostMapping, legacy map[string]*net.IPOrDomain) (*StaticHosts, error) {\n\tg := new(strmatcher.MatcherGroup)\n\tsh := &StaticHosts{\n\t\tips:      make([][]net.Address, len(hosts)+len(legacy)+16),\n\t\tmatchers: g,\n\t}\n\n\tif legacy != nil {\n\t\tfeatures.PrintDeprecatedFeatureWarning(\"simple host mapping\")\n\n\t\tfor domain, ip := range legacy {\n\t\t\tmatcher, err := strmatcher.Full.New(domain)\n\t\t\tcommon.Must(err)\n\t\t\tid := g.Add(matcher)\n\n\t\t\taddress := ip.AsAddress()\n\t\t\tif address.Family().IsDomain() {\n\t\t\t\treturn nil, newError(\"invalid domain address in static hosts: \", address.Domain()).AtWarning()\n\t\t\t}\n\n\t\t\tsh.ips[id] = []net.Address{address}\n\t\t}\n\t}\n\n\tfor _, mapping := range hosts {\n\t\tmatcher, err := toStrMatcher(mapping.Type, mapping.Domain)\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"failed to create domain matcher\").Base(err)\n\t\t}\n\t\tid := g.Add(matcher)\n\t\tips := make([]net.Address, 0, len(mapping.Ip)+1)\n\t\tif len(mapping.Ip) > 0 {\n\t\t\tfor _, ip := range mapping.Ip {\n\t\t\t\taddr := net.IPAddress(ip)\n\t\t\t\tif addr == nil {\n\t\t\t\t\treturn nil, newError(\"invalid IP address in static hosts: \", ip).AtWarning()\n\t\t\t\t}\n\t\t\t\tips = append(ips, addr)\n\t\t\t}\n\t\t} else if len(mapping.ProxiedDomain) > 0 {\n\t\t\tips = append(ips, net.DomainAddress(mapping.ProxiedDomain))\n\t\t} else {\n\t\t\treturn nil, newError(\"neither IP address nor proxied domain specified for domain: \", mapping.Domain).AtWarning()\n\t\t}\n\n\t\t// Special handling for localhost IPv6. This is a dirty workaround as JSON config supports only single IP mapping.\n\t\tif len(ips) == 1 && ips[0] == net.LocalHostIP {\n\t\t\tips = append(ips, net.LocalHostIPv6)\n\t\t}\n\n\t\tsh.ips[id] = ips\n\t}\n\n\treturn sh, nil\n}\n\nfunc filterIP(ips []net.Address, option IPOption) []net.Address {\n\tfiltered := make([]net.Address, 0, len(ips))\n\tfor _, ip := range ips {\n\t\tif (ip.Family().IsIPv4() && option.IPv4Enable) || (ip.Family().IsIPv6() && option.IPv6Enable) {\n\t\t\tfiltered = append(filtered, ip)\n\t\t}\n\t}\n\tif len(filtered) == 0 {\n\t\treturn nil\n\t}\n\treturn filtered\n}\n\n// LookupIP returns IP address for the given domain, if exists in this StaticHosts.\nfunc (h *StaticHosts) LookupIP(domain string, option IPOption) []net.Address {\n\tindices := h.matchers.Match(domain)\n\tif len(indices) == 0 {\n\t\treturn nil\n\t}\n\tips := []net.Address{}\n\tfor _, id := range indices {\n\t\tips = append(ips, h.ips[id]...)\n\t}\n\tif len(ips) == 1 && ips[0].Family().IsDomain() {\n\t\treturn ips\n\t}\n\treturn filterIP(ips, option)\n}\n"
  },
  {
    "path": "app/dns/hosts_test.go",
    "content": "package dns_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\n\t. \"v2ray.com/core/app/dns\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/net\"\n)\n\nfunc TestStaticHosts(t *testing.T) {\n\tpb := []*Config_HostMapping{\n\t\t{\n\t\t\tType:   DomainMatchingType_Full,\n\t\t\tDomain: \"v2ray.com\",\n\t\t\tIp: [][]byte{\n\t\t\t\t{1, 1, 1, 1},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tType:   DomainMatchingType_Subdomain,\n\t\t\tDomain: \"v2ray.cn\",\n\t\t\tIp: [][]byte{\n\t\t\t\t{2, 2, 2, 2},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tType:   DomainMatchingType_Subdomain,\n\t\t\tDomain: \"baidu.com\",\n\t\t\tIp: [][]byte{\n\t\t\t\t{127, 0, 0, 1},\n\t\t\t},\n\t\t},\n\t}\n\n\thosts, err := NewStaticHosts(pb, nil)\n\tcommon.Must(err)\n\n\t{\n\t\tips := hosts.LookupIP(\"v2ray.com\", IPOption{\n\t\t\tIPv4Enable: true,\n\t\t\tIPv6Enable: true,\n\t\t})\n\t\tif len(ips) != 1 {\n\t\t\tt.Error(\"expect 1 IP, but got \", len(ips))\n\t\t}\n\t\tif diff := cmp.Diff([]byte(ips[0].IP()), []byte{1, 1, 1, 1}); diff != \"\" {\n\t\t\tt.Error(diff)\n\t\t}\n\t}\n\n\t{\n\t\tips := hosts.LookupIP(\"www.v2ray.cn\", IPOption{\n\t\t\tIPv4Enable: true,\n\t\t\tIPv6Enable: true,\n\t\t})\n\t\tif len(ips) != 1 {\n\t\t\tt.Error(\"expect 1 IP, but got \", len(ips))\n\t\t}\n\t\tif diff := cmp.Diff([]byte(ips[0].IP()), []byte{2, 2, 2, 2}); diff != \"\" {\n\t\t\tt.Error(diff)\n\t\t}\n\t}\n\n\t{\n\t\tips := hosts.LookupIP(\"baidu.com\", IPOption{\n\t\t\tIPv4Enable: false,\n\t\t\tIPv6Enable: true,\n\t\t})\n\t\tif len(ips) != 1 {\n\t\t\tt.Error(\"expect 1 IP, but got \", len(ips))\n\t\t}\n\t\tif diff := cmp.Diff([]byte(ips[0].IP()), []byte(net.LocalHostIPv6.IP())); diff != \"\" {\n\t\t\tt.Error(diff)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "app/dns/nameserver.go",
    "content": "// +build !confonly\n\npackage dns\n\nimport (\n\t\"context\"\n\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/features/dns/localdns\"\n)\n\n// IPOption is an object for IP query options.\ntype IPOption struct {\n\tIPv4Enable bool\n\tIPv6Enable bool\n}\n\n// Client is the interface for DNS client.\ntype Client interface {\n\t// Name of the Client.\n\tName() string\n\n\t// QueryIP sends IP queries to its configured server.\n\tQueryIP(ctx context.Context, domain string, option IPOption) ([]net.IP, error)\n}\n\ntype localNameServer struct {\n\tclient *localdns.Client\n}\n\nfunc (s *localNameServer) QueryIP(ctx context.Context, domain string, option IPOption) ([]net.IP, error) {\n\tif option.IPv4Enable && option.IPv6Enable {\n\t\treturn s.client.LookupIP(domain)\n\t}\n\n\tif option.IPv4Enable {\n\t\treturn s.client.LookupIPv4(domain)\n\t}\n\n\tif option.IPv6Enable {\n\t\treturn s.client.LookupIPv6(domain)\n\t}\n\n\treturn nil, newError(\"neither IPv4 nor IPv6 is enabled\")\n}\n\nfunc (s *localNameServer) Name() string {\n\treturn \"localhost\"\n}\n\nfunc NewLocalNameServer() *localNameServer {\n\tnewError(\"DNS: created localhost client\").AtInfo().WriteToLog()\n\treturn &localNameServer{\n\t\tclient: localdns.New(),\n\t}\n}\n"
  },
  {
    "path": "app/dns/nameserver_test.go",
    "content": "package dns_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t. \"v2ray.com/core/app/dns\"\n\t\"v2ray.com/core/common\"\n)\n\nfunc TestLocalNameServer(t *testing.T) {\n\ts := NewLocalNameServer()\n\tctx, cancel := context.WithTimeout(context.Background(), time.Second*2)\n\tips, err := s.QueryIP(ctx, \"google.com\", IPOption{\n\t\tIPv4Enable: true,\n\t\tIPv6Enable: true,\n\t})\n\tcancel()\n\tcommon.Must(err)\n\tif len(ips) == 0 {\n\t\tt.Error(\"expect some ips, but got 0\")\n\t}\n}\n"
  },
  {
    "path": "app/dns/server.go",
    "content": "// +build !confonly\n\npackage dns\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"net/url\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/app/router\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/errors\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/session\"\n\t\"v2ray.com/core/common/strmatcher\"\n\t\"v2ray.com/core/common/uuid\"\n\t\"v2ray.com/core/features\"\n\t\"v2ray.com/core/features/dns\"\n\t\"v2ray.com/core/features/routing\"\n)\n\n// Server is a DNS rely server.\ntype Server struct {\n\tsync.Mutex\n\thosts         *StaticHosts\n\tclientIP      net.IP\n\tclients       []Client             // clientIdx -> Client\n\tipIndexMap    []*MultiGeoIPMatcher // clientIdx -> *MultiGeoIPMatcher\n\tdomainRules   [][]string           // clientIdx -> domainRuleIdx -> DomainRule\n\tdomainMatcher strmatcher.IndexMatcher\n\tmatcherInfos  []DomainMatcherInfo // matcherIdx -> DomainMatcherInfo\n\ttag           string\n}\n\n// DomainMatcherInfo contains information attached to index returned by Server.domainMatcher\ntype DomainMatcherInfo struct {\n\tclientIdx     uint16\n\tdomainRuleIdx uint16\n}\n\n// MultiGeoIPMatcher for match\ntype MultiGeoIPMatcher struct {\n\tmatchers []*router.GeoIPMatcher\n}\n\nvar errExpectedIPNonMatch = errors.New(\"expectIPs not match\")\n\n// Match check ip match\nfunc (c *MultiGeoIPMatcher) Match(ip net.IP) bool {\n\tfor _, matcher := range c.matchers {\n\t\tif matcher.Match(ip) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// HasMatcher check has matcher\nfunc (c *MultiGeoIPMatcher) HasMatcher() bool {\n\treturn len(c.matchers) > 0\n}\n\nfunc generateRandomTag() string {\n\tid := uuid.New()\n\treturn \"v2ray.system.\" + id.String()\n}\n\n// New creates a new DNS server with given configuration.\nfunc New(ctx context.Context, config *Config) (*Server, error) {\n\tserver := &Server{\n\t\tclients: make([]Client, 0, len(config.NameServers)+len(config.NameServer)),\n\t\ttag:     config.Tag,\n\t}\n\tif server.tag == \"\" {\n\t\tserver.tag = generateRandomTag()\n\t}\n\tif len(config.ClientIp) > 0 {\n\t\tif len(config.ClientIp) != net.IPv4len && len(config.ClientIp) != net.IPv6len {\n\t\t\treturn nil, newError(\"unexpected IP length\", len(config.ClientIp))\n\t\t}\n\t\tserver.clientIP = net.IP(config.ClientIp)\n\t}\n\n\thosts, err := NewStaticHosts(config.StaticHosts, config.Hosts)\n\tif err != nil {\n\t\treturn nil, newError(\"failed to create hosts\").Base(err)\n\t}\n\tserver.hosts = hosts\n\n\taddNameServer := func(ns *NameServer) int {\n\t\tendpoint := ns.Address\n\t\taddress := endpoint.Address.AsAddress()\n\t\tif address.Family().IsDomain() && address.Domain() == \"localhost\" {\n\t\t\tserver.clients = append(server.clients, NewLocalNameServer())\n\t\t\t// Priotize local domains with specific TLDs or without any dot to local DNS\n\t\t\t// References:\n\t\t\t// https://www.iana.org/assignments/special-use-domain-names/special-use-domain-names.xhtml\n\t\t\t// https://unix.stackexchange.com/questions/92441/whats-the-difference-between-local-home-and-lan\n\t\t\tlocalTLDsAndDotlessDomains := []*NameServer_PriorityDomain{\n\t\t\t\t{Type: DomainMatchingType_Regex, Domain: \"^[^.]+$\"}, // This will only match domains without any dot\n\t\t\t\t{Type: DomainMatchingType_Subdomain, Domain: \"local\"},\n\t\t\t\t{Type: DomainMatchingType_Subdomain, Domain: \"localdomain\"},\n\t\t\t\t{Type: DomainMatchingType_Subdomain, Domain: \"localhost\"},\n\t\t\t\t{Type: DomainMatchingType_Subdomain, Domain: \"lan\"},\n\t\t\t\t{Type: DomainMatchingType_Subdomain, Domain: \"home.arpa\"},\n\t\t\t\t{Type: DomainMatchingType_Subdomain, Domain: \"example\"},\n\t\t\t\t{Type: DomainMatchingType_Subdomain, Domain: \"invalid\"},\n\t\t\t\t{Type: DomainMatchingType_Subdomain, Domain: \"test\"},\n\t\t\t}\n\t\t\tns.PrioritizedDomain = append(ns.PrioritizedDomain, localTLDsAndDotlessDomains...)\n\t\t} else if address.Family().IsDomain() && strings.HasPrefix(address.Domain(), \"https+local://\") {\n\t\t\t// URI schemed string treated as domain\n\t\t\t// DOH Local mode\n\t\t\tu, err := url.Parse(address.Domain())\n\t\t\tif err != nil {\n\t\t\t\tlog.Fatalln(newError(\"DNS config error\").Base(err))\n\t\t\t}\n\t\t\tserver.clients = append(server.clients, NewDoHLocalNameServer(u, server.clientIP))\n\t\t} else if address.Family().IsDomain() && strings.HasPrefix(address.Domain(), \"https://\") {\n\t\t\t// DOH Remote mode\n\t\t\tu, err := url.Parse(address.Domain())\n\t\t\tif err != nil {\n\t\t\t\tlog.Fatalln(newError(\"DNS config error\").Base(err))\n\t\t\t}\n\t\t\tidx := len(server.clients)\n\t\t\tserver.clients = append(server.clients, nil)\n\n\t\t\t// need the core dispatcher, register DOHClient at callback\n\t\t\tcommon.Must(core.RequireFeatures(ctx, func(d routing.Dispatcher) {\n\t\t\t\tc, err := NewDoHNameServer(u, d, server.clientIP)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlog.Fatalln(newError(\"DNS config error\").Base(err))\n\t\t\t\t}\n\t\t\t\tserver.clients[idx] = c\n\t\t\t}))\n\t\t} else {\n\t\t\t// UDP classic DNS mode\n\t\t\tdest := endpoint.AsDestination()\n\t\t\tif dest.Network == net.Network_Unknown {\n\t\t\t\tdest.Network = net.Network_UDP\n\t\t\t}\n\t\t\tif dest.Network == net.Network_UDP {\n\t\t\t\tidx := len(server.clients)\n\t\t\t\tserver.clients = append(server.clients, nil)\n\n\t\t\t\tcommon.Must(core.RequireFeatures(ctx, func(d routing.Dispatcher) {\n\t\t\t\t\tserver.clients[idx] = NewClassicNameServer(dest, d, server.clientIP)\n\t\t\t\t}))\n\t\t\t}\n\t\t}\n\t\tserver.ipIndexMap = append(server.ipIndexMap, nil)\n\t\treturn len(server.clients) - 1\n\t}\n\n\tif len(config.NameServers) > 0 {\n\t\tfeatures.PrintDeprecatedFeatureWarning(\"simple DNS server\")\n\t\tfor _, destPB := range config.NameServers {\n\t\t\taddNameServer(&NameServer{Address: destPB})\n\t\t}\n\t}\n\n\tif len(config.NameServer) > 0 {\n\t\tclientIndices := []int{}\n\t\tdomainRuleCount := 0\n\t\tfor _, ns := range config.NameServer {\n\t\t\tidx := addNameServer(ns)\n\t\t\tclientIndices = append(clientIndices, idx)\n\t\t\tdomainRuleCount += len(ns.PrioritizedDomain)\n\t\t}\n\n\t\tdomainRules := make([][]string, len(server.clients))\n\t\tdomainMatcher := &strmatcher.MatcherGroup{}\n\t\tmatcherInfos := make([]DomainMatcherInfo, domainRuleCount+1) // matcher index starts from 1\n\t\tvar geoIPMatcherContainer router.GeoIPMatcherContainer\n\t\tfor nidx, ns := range config.NameServer {\n\t\t\tidx := clientIndices[nidx]\n\n\t\t\t// Establish domain rule matcher\n\t\t\trules := []string{}\n\t\t\truleCurr := 0\n\t\t\truleIter := 0\n\t\t\tfor _, domain := range ns.PrioritizedDomain {\n\t\t\t\tmatcher, err := toStrMatcher(domain.Type, domain.Domain)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, newError(\"failed to create prioritized domain\").Base(err).AtWarning()\n\t\t\t\t}\n\t\t\t\tmidx := domainMatcher.Add(matcher)\n\t\t\t\tif midx >= uint32(len(matcherInfos)) { // This rarely happens according to current matcher's implementation\n\t\t\t\t\tnewError(\"expanding domain matcher info array to size \", midx, \" when adding \", matcher).AtDebug().WriteToLog()\n\t\t\t\t\tmatcherInfos = append(matcherInfos, make([]DomainMatcherInfo, midx-uint32(len(matcherInfos))+1)...)\n\t\t\t\t}\n\t\t\t\tinfo := &matcherInfos[midx]\n\t\t\t\tinfo.clientIdx = uint16(idx)\n\t\t\t\tif ruleCurr < len(ns.OriginalRules) {\n\t\t\t\t\tinfo.domainRuleIdx = uint16(ruleCurr)\n\t\t\t\t\trule := ns.OriginalRules[ruleCurr]\n\t\t\t\t\tif ruleCurr >= len(rules) {\n\t\t\t\t\t\trules = append(rules, rule.Rule)\n\t\t\t\t\t}\n\t\t\t\t\truleIter++\n\t\t\t\t\tif ruleIter >= int(rule.Size) {\n\t\t\t\t\t\truleIter = 0\n\t\t\t\t\t\truleCurr++\n\t\t\t\t\t}\n\t\t\t\t} else { // No original rule, generate one according to current domain matcher (majorly for compatibility with tests)\n\t\t\t\t\tinfo.domainRuleIdx = uint16(len(rules))\n\t\t\t\t\trules = append(rules, matcher.String())\n\t\t\t\t}\n\t\t\t}\n\t\t\tdomainRules[idx] = rules\n\n\t\t\t// only add to ipIndexMap if GeoIP is configured\n\t\t\tif len(ns.Geoip) > 0 {\n\t\t\t\tvar matchers []*router.GeoIPMatcher\n\t\t\t\tfor _, geoip := range ns.Geoip {\n\t\t\t\t\tmatcher, err := geoIPMatcherContainer.Add(geoip)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn nil, newError(\"failed to create ip matcher\").Base(err).AtWarning()\n\t\t\t\t\t}\n\t\t\t\t\tmatchers = append(matchers, matcher)\n\t\t\t\t}\n\t\t\t\tmatcher := &MultiGeoIPMatcher{matchers: matchers}\n\t\t\t\tserver.ipIndexMap[idx] = matcher\n\t\t\t}\n\t\t}\n\t\tserver.domainRules = domainRules\n\t\tserver.domainMatcher = domainMatcher\n\t\tserver.matcherInfos = matcherInfos\n\t}\n\n\tif len(server.clients) == 0 {\n\t\tserver.clients = append(server.clients, NewLocalNameServer())\n\t\tserver.ipIndexMap = append(server.ipIndexMap, nil)\n\t}\n\n\treturn server, nil\n}\n\n// Type implements common.HasType.\nfunc (*Server) Type() interface{} {\n\treturn dns.ClientType()\n}\n\n// Start implements common.Runnable.\nfunc (s *Server) Start() error {\n\treturn nil\n}\n\n// Close implements common.Closable.\nfunc (s *Server) Close() error {\n\treturn nil\n}\n\nfunc (s *Server) IsOwnLink(ctx context.Context) bool {\n\tinbound := session.InboundFromContext(ctx)\n\treturn inbound != nil && inbound.Tag == s.tag\n}\n\n// Match check dns ip match geoip\nfunc (s *Server) Match(idx int, client Client, domain string, ips []net.IP) ([]net.IP, error) {\n\tvar matcher *MultiGeoIPMatcher\n\tif idx < len(s.ipIndexMap) {\n\t\tmatcher = s.ipIndexMap[idx]\n\t}\n\tif matcher == nil {\n\t\treturn ips, nil\n\t}\n\n\tif !matcher.HasMatcher() {\n\t\tnewError(\"domain \", domain, \" server has no valid matcher: \", client.Name(), \" idx:\", idx).AtDebug().WriteToLog()\n\t\treturn ips, nil\n\t}\n\n\tnewIps := []net.IP{}\n\tfor _, ip := range ips {\n\t\tif matcher.Match(ip) {\n\t\t\tnewIps = append(newIps, ip)\n\t\t}\n\t}\n\tif len(newIps) == 0 {\n\t\treturn nil, errExpectedIPNonMatch\n\t}\n\tnewError(\"domain \", domain, \" expectIPs \", newIps, \" matched at server \", client.Name(), \" idx:\", idx).AtDebug().WriteToLog()\n\treturn newIps, nil\n}\n\nfunc (s *Server) queryIPTimeout(idx int, client Client, domain string, option IPOption) ([]net.IP, error) {\n\tctx, cancel := context.WithTimeout(context.Background(), time.Second*4)\n\tif len(s.tag) > 0 {\n\t\tctx = session.ContextWithInbound(ctx, &session.Inbound{\n\t\t\tTag: s.tag,\n\t\t})\n\t}\n\tips, err := client.QueryIP(ctx, domain, option)\n\tcancel()\n\n\tif err != nil {\n\t\treturn ips, err\n\t}\n\n\tips, err = s.Match(idx, client, domain, ips)\n\treturn ips, err\n}\n\n// LookupIP implements dns.Client.\nfunc (s *Server) LookupIP(domain string) ([]net.IP, error) {\n\treturn s.lookupIPInternal(domain, IPOption{\n\t\tIPv4Enable: true,\n\t\tIPv6Enable: true,\n\t})\n}\n\n// LookupIPv4 implements dns.IPv4Lookup.\nfunc (s *Server) LookupIPv4(domain string) ([]net.IP, error) {\n\treturn s.lookupIPInternal(domain, IPOption{\n\t\tIPv4Enable: true,\n\t\tIPv6Enable: false,\n\t})\n}\n\n// LookupIPv6 implements dns.IPv6Lookup.\nfunc (s *Server) LookupIPv6(domain string) ([]net.IP, error) {\n\treturn s.lookupIPInternal(domain, IPOption{\n\t\tIPv4Enable: false,\n\t\tIPv6Enable: true,\n\t})\n}\n\nfunc (s *Server) lookupStatic(domain string, option IPOption, depth int32) []net.Address {\n\tips := s.hosts.LookupIP(domain, option)\n\tif ips == nil {\n\t\treturn nil\n\t}\n\tif ips[0].Family().IsDomain() && depth < 5 {\n\t\tif newIPs := s.lookupStatic(ips[0].Domain(), option, depth+1); newIPs != nil {\n\t\t\treturn newIPs\n\t\t}\n\t}\n\treturn ips\n}\n\nfunc toNetIP(ips []net.Address) []net.IP {\n\tif len(ips) == 0 {\n\t\treturn nil\n\t}\n\tnetips := make([]net.IP, 0, len(ips))\n\tfor _, ip := range ips {\n\t\tnetips = append(netips, ip.IP())\n\t}\n\treturn netips\n}\n\nfunc (s *Server) lookupIPInternal(domain string, option IPOption) ([]net.IP, error) {\n\tif domain == \"\" {\n\t\treturn nil, newError(\"empty domain name\")\n\t}\n\n\t// normalize the FQDN form query\n\tif domain[len(domain)-1] == '.' {\n\t\tdomain = domain[:len(domain)-1]\n\t}\n\n\tips := s.lookupStatic(domain, option, 0)\n\tif ips != nil && ips[0].Family().IsIP() {\n\t\tnewError(\"returning \", len(ips), \" IPs for domain \", domain).WriteToLog()\n\t\treturn toNetIP(ips), nil\n\t}\n\n\tif ips != nil && ips[0].Family().IsDomain() {\n\t\tnewdomain := ips[0].Domain()\n\t\tnewError(\"domain replaced: \", domain, \" -> \", newdomain).WriteToLog()\n\t\tdomain = newdomain\n\t}\n\n\tvar lastErr error\n\tvar matchedClient Client\n\tif s.domainMatcher != nil {\n\t\tindices := s.domainMatcher.Match(domain)\n\t\tdomainRules := []string{}\n\t\tmatchingDNS := []string{}\n\t\tfor _, idx := range indices {\n\t\t\tinfo := s.matcherInfos[idx]\n\t\t\trule := s.domainRules[info.clientIdx][info.domainRuleIdx]\n\t\t\tdomainRules = append(domainRules, fmt.Sprintf(\"%s(DNS idx:%d)\", rule, info.clientIdx))\n\t\t\tmatchingDNS = append(matchingDNS, s.clients[info.clientIdx].Name())\n\t\t}\n\t\tif len(domainRules) > 0 {\n\t\t\tnewError(\"domain \", domain, \" matches following rules: \", domainRules).AtDebug().WriteToLog()\n\t\t}\n\t\tif len(matchingDNS) > 0 {\n\t\t\tnewError(\"domain \", domain, \" uses following DNS first: \", matchingDNS).AtDebug().WriteToLog()\n\t\t}\n\t\tfor _, idx := range indices {\n\t\t\tclientIdx := int(s.matcherInfos[idx].clientIdx)\n\t\t\tmatchedClient = s.clients[clientIdx]\n\t\t\tips, err := s.queryIPTimeout(clientIdx, matchedClient, domain, option)\n\t\t\tif len(ips) > 0 {\n\t\t\t\treturn ips, nil\n\t\t\t}\n\t\t\tif err == dns.ErrEmptyResponse {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tif err != nil {\n\t\t\t\tnewError(\"failed to lookup ip for domain \", domain, \" at server \", matchedClient.Name()).Base(err).WriteToLog()\n\t\t\t\tlastErr = err\n\t\t\t}\n\t\t}\n\t}\n\n\tfor idx, client := range s.clients {\n\t\tif client == matchedClient {\n\t\t\tnewError(\"domain \", domain, \" at server \", client.Name(), \" idx:\", idx, \" already lookup failed, just ignore\").AtDebug().WriteToLog()\n\t\t\tcontinue\n\t\t}\n\n\t\tips, err := s.queryIPTimeout(idx, client, domain, option)\n\t\tif len(ips) > 0 {\n\t\t\treturn ips, nil\n\t\t}\n\n\t\tif err != nil {\n\t\t\tnewError(\"failed to lookup ip for domain \", domain, \" at server \", client.Name()).Base(err).WriteToLog()\n\t\t\tlastErr = err\n\t\t}\n\t\tif err != context.Canceled && err != context.DeadlineExceeded && err != errExpectedIPNonMatch {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn nil, newError(\"returning nil for domain \", domain).Base(lastErr)\n}\n\nfunc init() {\n\tcommon.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {\n\t\treturn New(ctx, config.(*Config))\n\t}))\n}\n"
  },
  {
    "path": "app/dns/server_test.go",
    "content": "package dns_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/miekg/dns\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/app/dispatcher\"\n\t. \"v2ray.com/core/app/dns\"\n\t\"v2ray.com/core/app/policy\"\n\t\"v2ray.com/core/app/proxyman\"\n\t_ \"v2ray.com/core/app/proxyman/outbound\"\n\t\"v2ray.com/core/app/router\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/serial\"\n\tfeature_dns \"v2ray.com/core/features/dns\"\n\t\"v2ray.com/core/proxy/freedom\"\n\t\"v2ray.com/core/testing/servers/udp\"\n)\n\ntype staticHandler struct {\n}\n\nfunc (*staticHandler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {\n\tans := new(dns.Msg)\n\tans.Id = r.Id\n\n\tvar clientIP net.IP\n\n\topt := r.IsEdns0()\n\tif opt != nil {\n\t\tfor _, o := range opt.Option {\n\t\t\tif o.Option() == dns.EDNS0SUBNET {\n\t\t\t\tsubnet := o.(*dns.EDNS0_SUBNET)\n\t\t\t\tclientIP = subnet.Address\n\t\t\t}\n\t\t}\n\t}\n\n\tfor _, q := range r.Question {\n\t\tif q.Name == \"google.com.\" && q.Qtype == dns.TypeA {\n\t\t\tif clientIP == nil {\n\t\t\t\trr, _ := dns.NewRR(\"google.com. IN A 8.8.8.8\")\n\t\t\t\tans.Answer = append(ans.Answer, rr)\n\t\t\t} else {\n\t\t\t\trr, _ := dns.NewRR(\"google.com. IN A 8.8.4.4\")\n\t\t\t\tans.Answer = append(ans.Answer, rr)\n\t\t\t}\n\t\t} else if q.Name == \"api.google.com.\" && q.Qtype == dns.TypeA {\n\t\t\trr, _ := dns.NewRR(\"api.google.com. IN A 8.8.7.7\")\n\t\t\tans.Answer = append(ans.Answer, rr)\n\t\t} else if q.Name == \"v2.api.google.com.\" && q.Qtype == dns.TypeA {\n\t\t\trr, _ := dns.NewRR(\"v2.api.google.com. IN A 8.8.7.8\")\n\t\t\tans.Answer = append(ans.Answer, rr)\n\t\t} else if q.Name == \"facebook.com.\" && q.Qtype == dns.TypeA {\n\t\t\trr, _ := dns.NewRR(\"facebook.com. IN A 9.9.9.9\")\n\t\t\tans.Answer = append(ans.Answer, rr)\n\t\t} else if q.Name == \"ipv6.google.com.\" && q.Qtype == dns.TypeA {\n\t\t\trr, err := dns.NewRR(\"ipv6.google.com. IN A 8.8.8.7\")\n\t\t\tcommon.Must(err)\n\t\t\tans.Answer = append(ans.Answer, rr)\n\t\t} else if q.Name == \"ipv6.google.com.\" && q.Qtype == dns.TypeAAAA {\n\t\t\trr, err := dns.NewRR(\"ipv6.google.com. IN AAAA 2001:4860:4860::8888\")\n\t\t\tcommon.Must(err)\n\t\t\tans.Answer = append(ans.Answer, rr)\n\t\t} else if q.Name == \"notexist.google.com.\" && q.Qtype == dns.TypeAAAA {\n\t\t\tans.MsgHdr.Rcode = dns.RcodeNameError\n\t\t} else if q.Name == \"hostname.\" && q.Qtype == dns.TypeA {\n\t\t\trr, _ := dns.NewRR(\"hostname. IN A 127.0.0.1\")\n\t\t\tans.Answer = append(ans.Answer, rr)\n\t\t} else if q.Name == \"hostname.local.\" && q.Qtype == dns.TypeA {\n\t\t\trr, _ := dns.NewRR(\"hostname.local. IN A 127.0.0.1\")\n\t\t\tans.Answer = append(ans.Answer, rr)\n\t\t} else if q.Name == \"hostname.localdomain.\" && q.Qtype == dns.TypeA {\n\t\t\trr, _ := dns.NewRR(\"hostname.localdomain. IN A 127.0.0.1\")\n\t\t\tans.Answer = append(ans.Answer, rr)\n\t\t} else if q.Name == \"localhost.\" && q.Qtype == dns.TypeA {\n\t\t\trr, _ := dns.NewRR(\"localhost. IN A 127.0.0.2\")\n\t\t\tans.Answer = append(ans.Answer, rr)\n\t\t} else if q.Name == \"localhost-a.\" && q.Qtype == dns.TypeA {\n\t\t\trr, _ := dns.NewRR(\"localhost-a. IN A 127.0.0.3\")\n\t\t\tans.Answer = append(ans.Answer, rr)\n\t\t} else if q.Name == \"localhost-b.\" && q.Qtype == dns.TypeA {\n\t\t\trr, _ := dns.NewRR(\"localhost-b. IN A 127.0.0.4\")\n\t\t\tans.Answer = append(ans.Answer, rr)\n\t\t} else if q.Name == \"Mijia\\\\ Cloud.\" && q.Qtype == dns.TypeA {\n\t\t\trr, _ := dns.NewRR(\"Mijia\\\\ Cloud. IN A 127.0.0.1\")\n\t\t\tans.Answer = append(ans.Answer, rr)\n\t\t}\n\t}\n\tw.WriteMsg(ans)\n}\n\nfunc TestUDPServerSubnet(t *testing.T) {\n\tport := udp.PickPort()\n\n\tdnsServer := dns.Server{\n\t\tAddr:    \"127.0.0.1:\" + port.String(),\n\t\tNet:     \"udp\",\n\t\tHandler: &staticHandler{},\n\t\tUDPSize: 1200,\n\t}\n\n\tgo dnsServer.ListenAndServe()\n\ttime.Sleep(time.Second)\n\n\tconfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&Config{\n\t\t\t\tNameServers: []*net.Endpoint{\n\t\t\t\t\t{\n\t\t\t\t\t\tNetwork: net.Network_UDP,\n\t\t\t\t\t\tAddress: &net.IPOrDomain{\n\t\t\t\t\t\t\tAddress: &net.IPOrDomain_Ip{\n\t\t\t\t\t\t\t\tIp: []byte{127, 0, 0, 1},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tPort: uint32(port),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClientIp: []byte{7, 8, 9, 10},\n\t\t\t}),\n\t\t\tserial.ToTypedMessage(&dispatcher.Config{}),\n\t\t\tserial.ToTypedMessage(&proxyman.OutboundConfig{}),\n\t\t\tserial.ToTypedMessage(&policy.Config{}),\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tv, err := core.New(config)\n\tcommon.Must(err)\n\n\tclient := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)\n\n\tips, err := client.LookupIP(\"google.com\")\n\tif err != nil {\n\t\tt.Fatal(\"unexpected error: \", err)\n\t}\n\n\tif r := cmp.Diff(ips, []net.IP{{8, 8, 4, 4}}); r != \"\" {\n\t\tt.Fatal(r)\n\t}\n}\n\nfunc TestUDPServer(t *testing.T) {\n\tport := udp.PickPort()\n\n\tdnsServer := dns.Server{\n\t\tAddr:    \"127.0.0.1:\" + port.String(),\n\t\tNet:     \"udp\",\n\t\tHandler: &staticHandler{},\n\t\tUDPSize: 1200,\n\t}\n\n\tgo dnsServer.ListenAndServe()\n\ttime.Sleep(time.Second)\n\n\tconfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&Config{\n\t\t\t\tNameServers: []*net.Endpoint{\n\t\t\t\t\t{\n\t\t\t\t\t\tNetwork: net.Network_UDP,\n\t\t\t\t\t\tAddress: &net.IPOrDomain{\n\t\t\t\t\t\t\tAddress: &net.IPOrDomain_Ip{\n\t\t\t\t\t\t\t\tIp: []byte{127, 0, 0, 1},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tPort: uint32(port),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}),\n\t\t\tserial.ToTypedMessage(&dispatcher.Config{}),\n\t\t\tserial.ToTypedMessage(&proxyman.OutboundConfig{}),\n\t\t\tserial.ToTypedMessage(&policy.Config{}),\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tv, err := core.New(config)\n\tcommon.Must(err)\n\n\tclient := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)\n\n\t{\n\t\tips, err := client.LookupIP(\"google.com\")\n\t\tif err != nil {\n\t\t\tt.Fatal(\"unexpected error: \", err)\n\t\t}\n\n\t\tif r := cmp.Diff(ips, []net.IP{{8, 8, 8, 8}}); r != \"\" {\n\t\t\tt.Fatal(r)\n\t\t}\n\t}\n\n\t{\n\t\tips, err := client.LookupIP(\"facebook.com\")\n\t\tif err != nil {\n\t\t\tt.Fatal(\"unexpected error: \", err)\n\t\t}\n\n\t\tif r := cmp.Diff(ips, []net.IP{{9, 9, 9, 9}}); r != \"\" {\n\t\t\tt.Fatal(r)\n\t\t}\n\t}\n\n\t{\n\t\t_, err := client.LookupIP(\"notexist.google.com\")\n\t\tif err == nil {\n\t\t\tt.Fatal(\"nil error\")\n\t\t}\n\t\tif r := feature_dns.RCodeFromError(err); r != uint16(dns.RcodeNameError) {\n\t\t\tt.Fatal(\"expected NameError, but got \", r)\n\t\t}\n\t}\n\n\t{\n\t\tclientv6 := client.(feature_dns.IPv6Lookup)\n\t\tips, err := clientv6.LookupIPv6(\"ipv4only.google.com\")\n\t\tif err != feature_dns.ErrEmptyResponse {\n\t\t\tt.Fatal(\"error: \", err)\n\t\t}\n\t\tif len(ips) != 0 {\n\t\t\tt.Fatal(\"ips: \", ips)\n\t\t}\n\t}\n\n\tdnsServer.Shutdown()\n\n\t{\n\t\tips, err := client.LookupIP(\"google.com\")\n\t\tif err != nil {\n\t\t\tt.Fatal(\"unexpected error: \", err)\n\t\t}\n\n\t\tif r := cmp.Diff(ips, []net.IP{{8, 8, 8, 8}}); r != \"\" {\n\t\t\tt.Fatal(r)\n\t\t}\n\t}\n}\n\nfunc TestPrioritizedDomain(t *testing.T) {\n\tport := udp.PickPort()\n\n\tdnsServer := dns.Server{\n\t\tAddr:    \"127.0.0.1:\" + port.String(),\n\t\tNet:     \"udp\",\n\t\tHandler: &staticHandler{},\n\t\tUDPSize: 1200,\n\t}\n\n\tgo dnsServer.ListenAndServe()\n\ttime.Sleep(time.Second)\n\n\tconfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&Config{\n\t\t\t\tNameServers: []*net.Endpoint{\n\t\t\t\t\t{\n\t\t\t\t\t\tNetwork: net.Network_UDP,\n\t\t\t\t\t\tAddress: &net.IPOrDomain{\n\t\t\t\t\t\t\tAddress: &net.IPOrDomain_Ip{\n\t\t\t\t\t\t\t\tIp: []byte{127, 0, 0, 1},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tPort: 9999, /* unreachable */\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tNameServer: []*NameServer{\n\t\t\t\t\t{\n\t\t\t\t\t\tAddress: &net.Endpoint{\n\t\t\t\t\t\t\tNetwork: net.Network_UDP,\n\t\t\t\t\t\t\tAddress: &net.IPOrDomain{\n\t\t\t\t\t\t\t\tAddress: &net.IPOrDomain_Ip{\n\t\t\t\t\t\t\t\t\tIp: []byte{127, 0, 0, 1},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tPort: uint32(port),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tPrioritizedDomain: []*NameServer_PriorityDomain{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tType:   DomainMatchingType_Full,\n\t\t\t\t\t\t\t\tDomain: \"google.com\",\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\tserial.ToTypedMessage(&dispatcher.Config{}),\n\t\t\tserial.ToTypedMessage(&proxyman.OutboundConfig{}),\n\t\t\tserial.ToTypedMessage(&policy.Config{}),\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tv, err := core.New(config)\n\tcommon.Must(err)\n\n\tclient := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)\n\n\tstartTime := time.Now()\n\n\t{\n\t\tips, err := client.LookupIP(\"google.com\")\n\t\tif err != nil {\n\t\t\tt.Fatal(\"unexpected error: \", err)\n\t\t}\n\n\t\tif r := cmp.Diff(ips, []net.IP{{8, 8, 8, 8}}); r != \"\" {\n\t\t\tt.Fatal(r)\n\t\t}\n\t}\n\n\tendTime := time.Now()\n\tif startTime.After(endTime.Add(time.Second * 2)) {\n\t\tt.Error(\"DNS query doesn't finish in 2 seconds.\")\n\t}\n}\n\nfunc TestUDPServerIPv6(t *testing.T) {\n\tport := udp.PickPort()\n\n\tdnsServer := dns.Server{\n\t\tAddr:    \"127.0.0.1:\" + port.String(),\n\t\tNet:     \"udp\",\n\t\tHandler: &staticHandler{},\n\t\tUDPSize: 1200,\n\t}\n\n\tgo dnsServer.ListenAndServe()\n\ttime.Sleep(time.Second)\n\n\tconfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&Config{\n\t\t\t\tNameServers: []*net.Endpoint{\n\t\t\t\t\t{\n\t\t\t\t\t\tNetwork: net.Network_UDP,\n\t\t\t\t\t\tAddress: &net.IPOrDomain{\n\t\t\t\t\t\t\tAddress: &net.IPOrDomain_Ip{\n\t\t\t\t\t\t\t\tIp: []byte{127, 0, 0, 1},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tPort: uint32(port),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}),\n\t\t\tserial.ToTypedMessage(&dispatcher.Config{}),\n\t\t\tserial.ToTypedMessage(&proxyman.OutboundConfig{}),\n\t\t\tserial.ToTypedMessage(&policy.Config{}),\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tv, err := core.New(config)\n\tcommon.Must(err)\n\n\tclient := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)\n\tclient6 := client.(feature_dns.IPv6Lookup)\n\n\t{\n\t\tips, err := client6.LookupIPv6(\"ipv6.google.com\")\n\t\tif err != nil {\n\t\t\tt.Fatal(\"unexpected error: \", err)\n\t\t}\n\n\t\tif r := cmp.Diff(ips, []net.IP{{32, 1, 72, 96, 72, 96, 0, 0, 0, 0, 0, 0, 0, 0, 136, 136}}); r != \"\" {\n\t\t\tt.Fatal(r)\n\t\t}\n\t}\n}\n\nfunc TestStaticHostDomain(t *testing.T) {\n\tport := udp.PickPort()\n\n\tdnsServer := dns.Server{\n\t\tAddr:    \"127.0.0.1:\" + port.String(),\n\t\tNet:     \"udp\",\n\t\tHandler: &staticHandler{},\n\t\tUDPSize: 1200,\n\t}\n\n\tgo dnsServer.ListenAndServe()\n\ttime.Sleep(time.Second)\n\n\tconfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&Config{\n\t\t\t\tNameServers: []*net.Endpoint{\n\t\t\t\t\t{\n\t\t\t\t\t\tNetwork: net.Network_UDP,\n\t\t\t\t\t\tAddress: &net.IPOrDomain{\n\t\t\t\t\t\t\tAddress: &net.IPOrDomain_Ip{\n\t\t\t\t\t\t\t\tIp: []byte{127, 0, 0, 1},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tPort: uint32(port),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tStaticHosts: []*Config_HostMapping{\n\t\t\t\t\t{\n\t\t\t\t\t\tType:          DomainMatchingType_Full,\n\t\t\t\t\t\tDomain:        \"example.com\",\n\t\t\t\t\t\tProxiedDomain: \"google.com\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}),\n\t\t\tserial.ToTypedMessage(&dispatcher.Config{}),\n\t\t\tserial.ToTypedMessage(&proxyman.OutboundConfig{}),\n\t\t\tserial.ToTypedMessage(&policy.Config{}),\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tv, err := core.New(config)\n\tcommon.Must(err)\n\n\tclient := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)\n\n\t{\n\t\tips, err := client.LookupIP(\"example.com\")\n\t\tif err != nil {\n\t\t\tt.Fatal(\"unexpected error: \", err)\n\t\t}\n\n\t\tif r := cmp.Diff(ips, []net.IP{{8, 8, 8, 8}}); r != \"\" {\n\t\t\tt.Fatal(r)\n\t\t}\n\t}\n\n\tdnsServer.Shutdown()\n}\n\nfunc TestIPMatch(t *testing.T) {\n\tport := udp.PickPort()\n\n\tdnsServer := dns.Server{\n\t\tAddr:    \"127.0.0.1:\" + port.String(),\n\t\tNet:     \"udp\",\n\t\tHandler: &staticHandler{},\n\t\tUDPSize: 1200,\n\t}\n\n\tgo dnsServer.ListenAndServe()\n\ttime.Sleep(time.Second)\n\n\tconfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&Config{\n\t\t\t\tNameServer: []*NameServer{\n\t\t\t\t\t// private dns, not match\n\t\t\t\t\t{\n\t\t\t\t\t\tAddress: &net.Endpoint{\n\t\t\t\t\t\t\tNetwork: net.Network_UDP,\n\t\t\t\t\t\t\tAddress: &net.IPOrDomain{\n\t\t\t\t\t\t\t\tAddress: &net.IPOrDomain_Ip{\n\t\t\t\t\t\t\t\t\tIp: []byte{127, 0, 0, 1},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tPort: uint32(port),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tGeoip: []*router.GeoIP{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tCountryCode: \"local\",\n\t\t\t\t\t\t\t\tCidr: []*router.CIDR{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t// inner ip, will not match\n\t\t\t\t\t\t\t\t\t\tIp:     []byte{192, 168, 11, 1},\n\t\t\t\t\t\t\t\t\t\tPrefix: 32,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\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\t// second dns, match ip\n\t\t\t\t\t{\n\t\t\t\t\t\tAddress: &net.Endpoint{\n\t\t\t\t\t\t\tNetwork: net.Network_UDP,\n\t\t\t\t\t\t\tAddress: &net.IPOrDomain{\n\t\t\t\t\t\t\t\tAddress: &net.IPOrDomain_Ip{\n\t\t\t\t\t\t\t\t\tIp: []byte{127, 0, 0, 1},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tPort: uint32(port),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tGeoip: []*router.GeoIP{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tCountryCode: \"test\",\n\t\t\t\t\t\t\t\tCidr: []*router.CIDR{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tIp:     []byte{8, 8, 8, 8},\n\t\t\t\t\t\t\t\t\t\tPrefix: 32,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tCountryCode: \"test\",\n\t\t\t\t\t\t\t\tCidr: []*router.CIDR{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tIp:     []byte{8, 8, 8, 4},\n\t\t\t\t\t\t\t\t\t\tPrefix: 32,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\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\tserial.ToTypedMessage(&dispatcher.Config{}),\n\t\t\tserial.ToTypedMessage(&proxyman.OutboundConfig{}),\n\t\t\tserial.ToTypedMessage(&policy.Config{}),\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tv, err := core.New(config)\n\tcommon.Must(err)\n\n\tclient := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)\n\n\tstartTime := time.Now()\n\n\t{\n\t\tips, err := client.LookupIP(\"google.com\")\n\t\tif err != nil {\n\t\t\tt.Fatal(\"unexpected error: \", err)\n\t\t}\n\n\t\tif r := cmp.Diff(ips, []net.IP{{8, 8, 8, 8}}); r != \"\" {\n\t\t\tt.Fatal(r)\n\t\t}\n\t}\n\n\tendTime := time.Now()\n\tif startTime.After(endTime.Add(time.Second * 2)) {\n\t\tt.Error(\"DNS query doesn't finish in 2 seconds.\")\n\t}\n}\n\nfunc TestLocalDomain(t *testing.T) {\n\tport := udp.PickPort()\n\n\tdnsServer := dns.Server{\n\t\tAddr:    \"127.0.0.1:\" + port.String(),\n\t\tNet:     \"udp\",\n\t\tHandler: &staticHandler{},\n\t\tUDPSize: 1200,\n\t}\n\n\tgo dnsServer.ListenAndServe()\n\ttime.Sleep(time.Second)\n\n\tconfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&Config{\n\t\t\t\tNameServers: []*net.Endpoint{\n\t\t\t\t\t{\n\t\t\t\t\t\tNetwork: net.Network_UDP,\n\t\t\t\t\t\tAddress: &net.IPOrDomain{\n\t\t\t\t\t\t\tAddress: &net.IPOrDomain_Ip{\n\t\t\t\t\t\t\t\tIp: []byte{127, 0, 0, 1},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tPort: 9999, /* unreachable */\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tNameServer: []*NameServer{\n\t\t\t\t\t{\n\t\t\t\t\t\tAddress: &net.Endpoint{\n\t\t\t\t\t\t\tNetwork: net.Network_UDP,\n\t\t\t\t\t\t\tAddress: &net.IPOrDomain{\n\t\t\t\t\t\t\t\tAddress: &net.IPOrDomain_Ip{\n\t\t\t\t\t\t\t\t\tIp: []byte{127, 0, 0, 1},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tPort: uint32(port),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tPrioritizedDomain: []*NameServer_PriorityDomain{\n\t\t\t\t\t\t\t// Equivalent of dotless:localhost\n\t\t\t\t\t\t\t{Type: DomainMatchingType_Regex, Domain: \"^[^.]*localhost[^.]*$\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tGeoip: []*router.GeoIP{\n\t\t\t\t\t\t\t{ // Will match localhost, localhost-a and localhost-b,\n\t\t\t\t\t\t\t\tCountryCode: \"local\",\n\t\t\t\t\t\t\t\tCidr: []*router.CIDR{\n\t\t\t\t\t\t\t\t\t{Ip: []byte{127, 0, 0, 2}, Prefix: 32},\n\t\t\t\t\t\t\t\t\t{Ip: []byte{127, 0, 0, 3}, Prefix: 32},\n\t\t\t\t\t\t\t\t\t{Ip: []byte{127, 0, 0, 4}, Prefix: 32},\n\t\t\t\t\t\t\t\t},\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\t{\n\t\t\t\t\t\tAddress: &net.Endpoint{\n\t\t\t\t\t\t\tNetwork: net.Network_UDP,\n\t\t\t\t\t\t\tAddress: &net.IPOrDomain{\n\t\t\t\t\t\t\t\tAddress: &net.IPOrDomain_Ip{\n\t\t\t\t\t\t\t\t\tIp: []byte{127, 0, 0, 1},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tPort: uint32(port),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tPrioritizedDomain: []*NameServer_PriorityDomain{\n\t\t\t\t\t\t\t// Equivalent of dotless: and domain:local\n\t\t\t\t\t\t\t{Type: DomainMatchingType_Regex, Domain: \"^[^.]*$\"},\n\t\t\t\t\t\t\t{Type: DomainMatchingType_Subdomain, Domain: \"local\"},\n\t\t\t\t\t\t\t{Type: DomainMatchingType_Subdomain, Domain: \"localdomain\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tStaticHosts: []*Config_HostMapping{\n\t\t\t\t\t{\n\t\t\t\t\t\tType:   DomainMatchingType_Full,\n\t\t\t\t\t\tDomain: \"hostnamestatic\",\n\t\t\t\t\t\tIp:     [][]byte{{127, 0, 0, 53}},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tType:          DomainMatchingType_Full,\n\t\t\t\t\t\tDomain:        \"hostnamealias\",\n\t\t\t\t\t\tProxiedDomain: \"hostname.localdomain\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}),\n\t\t\tserial.ToTypedMessage(&dispatcher.Config{}),\n\t\t\tserial.ToTypedMessage(&proxyman.OutboundConfig{}),\n\t\t\tserial.ToTypedMessage(&policy.Config{}),\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tv, err := core.New(config)\n\tcommon.Must(err)\n\n\tclient := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)\n\n\tstartTime := time.Now()\n\n\t{ // Will match dotless:\n\t\tips, err := client.LookupIP(\"hostname\")\n\t\tif err != nil {\n\t\t\tt.Fatal(\"unexpected error: \", err)\n\t\t}\n\n\t\tif r := cmp.Diff(ips, []net.IP{{127, 0, 0, 1}}); r != \"\" {\n\t\t\tt.Fatal(r)\n\t\t}\n\t}\n\n\t{ // Will match domain:local\n\t\tips, err := client.LookupIP(\"hostname.local\")\n\t\tif err != nil {\n\t\t\tt.Fatal(\"unexpected error: \", err)\n\t\t}\n\n\t\tif r := cmp.Diff(ips, []net.IP{{127, 0, 0, 1}}); r != \"\" {\n\t\t\tt.Fatal(r)\n\t\t}\n\t}\n\n\t{ // Will match static ip\n\t\tips, err := client.LookupIP(\"hostnamestatic\")\n\t\tif err != nil {\n\t\t\tt.Fatal(\"unexpected error: \", err)\n\t\t}\n\n\t\tif r := cmp.Diff(ips, []net.IP{{127, 0, 0, 53}}); r != \"\" {\n\t\t\tt.Fatal(r)\n\t\t}\n\t}\n\n\t{ // Will match domain replacing\n\t\tips, err := client.LookupIP(\"hostnamealias\")\n\t\tif err != nil {\n\t\t\tt.Fatal(\"unexpected error: \", err)\n\t\t}\n\n\t\tif r := cmp.Diff(ips, []net.IP{{127, 0, 0, 1}}); r != \"\" {\n\t\t\tt.Fatal(r)\n\t\t}\n\t}\n\n\t{ // Will match dotless:localhost, but not expectIPs: 127.0.0.2, 127.0.0.3, then matches at dotless:\n\t\tips, err := client.LookupIP(\"localhost\")\n\t\tif err != nil {\n\t\t\tt.Fatal(\"unexpected error: \", err)\n\t\t}\n\n\t\tif r := cmp.Diff(ips, []net.IP{{127, 0, 0, 2}}); r != \"\" {\n\t\t\tt.Fatal(r)\n\t\t}\n\t}\n\n\t{ // Will match dotless:localhost, and expectIPs: 127.0.0.2, 127.0.0.3\n\t\tips, err := client.LookupIP(\"localhost-a\")\n\t\tif err != nil {\n\t\t\tt.Fatal(\"unexpected error: \", err)\n\t\t}\n\n\t\tif r := cmp.Diff(ips, []net.IP{{127, 0, 0, 3}}); r != \"\" {\n\t\t\tt.Fatal(r)\n\t\t}\n\t}\n\n\t{ // Will match dotless:localhost, and expectIPs: 127.0.0.2, 127.0.0.3\n\t\tips, err := client.LookupIP(\"localhost-b\")\n\t\tif err != nil {\n\t\t\tt.Fatal(\"unexpected error: \", err)\n\t\t}\n\n\t\tif r := cmp.Diff(ips, []net.IP{{127, 0, 0, 4}}); r != \"\" {\n\t\t\tt.Fatal(r)\n\t\t}\n\t}\n\n\t{ // Will match dotless:\n\t\tips, err := client.LookupIP(\"Mijia Cloud\")\n\t\tif err != nil {\n\t\t\tt.Fatal(\"unexpected error: \", err)\n\t\t}\n\n\t\tif r := cmp.Diff(ips, []net.IP{{127, 0, 0, 1}}); r != \"\" {\n\t\t\tt.Fatal(r)\n\t\t}\n\t}\n\n\tendTime := time.Now()\n\tif startTime.After(endTime.Add(time.Second * 2)) {\n\t\tt.Error(\"DNS query doesn't finish in 2 seconds.\")\n\t}\n}\n\nfunc TestMultiMatchPrioritizedDomain(t *testing.T) {\n\tport := udp.PickPort()\n\n\tdnsServer := dns.Server{\n\t\tAddr:    \"127.0.0.1:\" + port.String(),\n\t\tNet:     \"udp\",\n\t\tHandler: &staticHandler{},\n\t\tUDPSize: 1200,\n\t}\n\n\tgo dnsServer.ListenAndServe()\n\ttime.Sleep(time.Second)\n\n\tconfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&Config{\n\t\t\t\tNameServers: []*net.Endpoint{\n\t\t\t\t\t{\n\t\t\t\t\t\tNetwork: net.Network_UDP,\n\t\t\t\t\t\tAddress: &net.IPOrDomain{\n\t\t\t\t\t\t\tAddress: &net.IPOrDomain_Ip{\n\t\t\t\t\t\t\t\tIp: []byte{127, 0, 0, 1},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tPort: 9999, /* unreachable */\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tNameServer: []*NameServer{\n\t\t\t\t\t{\n\t\t\t\t\t\tAddress: &net.Endpoint{\n\t\t\t\t\t\t\tNetwork: net.Network_UDP,\n\t\t\t\t\t\t\tAddress: &net.IPOrDomain{\n\t\t\t\t\t\t\t\tAddress: &net.IPOrDomain_Ip{\n\t\t\t\t\t\t\t\t\tIp: []byte{127, 0, 0, 1},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tPort: uint32(port),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tPrioritizedDomain: []*NameServer_PriorityDomain{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tType:   DomainMatchingType_Subdomain,\n\t\t\t\t\t\t\t\tDomain: \"google.com\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tGeoip: []*router.GeoIP{\n\t\t\t\t\t\t\t{ // Will only match 8.8.8.8 and 8.8.4.4\n\t\t\t\t\t\t\t\tCidr: []*router.CIDR{\n\t\t\t\t\t\t\t\t\t{Ip: []byte{8, 8, 8, 8}, Prefix: 32},\n\t\t\t\t\t\t\t\t\t{Ip: []byte{8, 8, 4, 4}, Prefix: 32},\n\t\t\t\t\t\t\t\t},\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\t{\n\t\t\t\t\t\tAddress: &net.Endpoint{\n\t\t\t\t\t\t\tNetwork: net.Network_UDP,\n\t\t\t\t\t\t\tAddress: &net.IPOrDomain{\n\t\t\t\t\t\t\t\tAddress: &net.IPOrDomain_Ip{\n\t\t\t\t\t\t\t\t\tIp: []byte{127, 0, 0, 1},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tPort: uint32(port),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tPrioritizedDomain: []*NameServer_PriorityDomain{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tType:   DomainMatchingType_Subdomain,\n\t\t\t\t\t\t\t\tDomain: \"google.com\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tGeoip: []*router.GeoIP{\n\t\t\t\t\t\t\t{ // Will match 8.8.8.8 and 8.8.8.7, etc\n\t\t\t\t\t\t\t\tCidr: []*router.CIDR{\n\t\t\t\t\t\t\t\t\t{Ip: []byte{8, 8, 8, 7}, Prefix: 24},\n\t\t\t\t\t\t\t\t},\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\t{\n\t\t\t\t\t\tAddress: &net.Endpoint{\n\t\t\t\t\t\t\tNetwork: net.Network_UDP,\n\t\t\t\t\t\t\tAddress: &net.IPOrDomain{\n\t\t\t\t\t\t\t\tAddress: &net.IPOrDomain_Ip{\n\t\t\t\t\t\t\t\t\tIp: []byte{127, 0, 0, 1},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tPort: uint32(port),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tPrioritizedDomain: []*NameServer_PriorityDomain{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tType:   DomainMatchingType_Subdomain,\n\t\t\t\t\t\t\t\tDomain: \"api.google.com\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tGeoip: []*router.GeoIP{\n\t\t\t\t\t\t\t{ // Will only match 8.8.7.7 (api.google.com)\n\t\t\t\t\t\t\t\tCidr: []*router.CIDR{\n\t\t\t\t\t\t\t\t\t{Ip: []byte{8, 8, 7, 7}, Prefix: 32},\n\t\t\t\t\t\t\t\t},\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\t{\n\t\t\t\t\t\tAddress: &net.Endpoint{\n\t\t\t\t\t\t\tNetwork: net.Network_UDP,\n\t\t\t\t\t\t\tAddress: &net.IPOrDomain{\n\t\t\t\t\t\t\t\tAddress: &net.IPOrDomain_Ip{\n\t\t\t\t\t\t\t\t\tIp: []byte{127, 0, 0, 1},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tPort: uint32(port),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tPrioritizedDomain: []*NameServer_PriorityDomain{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tType:   DomainMatchingType_Full,\n\t\t\t\t\t\t\t\tDomain: \"v2.api.google.com\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tGeoip: []*router.GeoIP{\n\t\t\t\t\t\t\t{ // Will only match 8.8.7.8 (v2.api.google.com)\n\t\t\t\t\t\t\t\tCidr: []*router.CIDR{\n\t\t\t\t\t\t\t\t\t{Ip: []byte{8, 8, 7, 8}, Prefix: 32},\n\t\t\t\t\t\t\t\t},\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\tserial.ToTypedMessage(&dispatcher.Config{}),\n\t\t\tserial.ToTypedMessage(&proxyman.OutboundConfig{}),\n\t\t\tserial.ToTypedMessage(&policy.Config{}),\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tv, err := core.New(config)\n\tcommon.Must(err)\n\n\tclient := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)\n\n\tstartTime := time.Now()\n\n\t{ // Will match server 1,2 and server 1 returns expected ip\n\t\tips, err := client.LookupIP(\"google.com\")\n\t\tif err != nil {\n\t\t\tt.Fatal(\"unexpected error: \", err)\n\t\t}\n\n\t\tif r := cmp.Diff(ips, []net.IP{{8, 8, 8, 8}}); r != \"\" {\n\t\t\tt.Fatal(r)\n\t\t}\n\t}\n\n\t{ // Will match server 1,2 and server 1 returns unexpected ip, then server 2 returns expected one\n\t\tclientv4 := client.(feature_dns.IPv4Lookup)\n\t\tips, err := clientv4.LookupIPv4(\"ipv6.google.com\")\n\t\tif err != nil {\n\t\t\tt.Fatal(\"unexpected error: \", err)\n\t\t}\n\n\t\tif r := cmp.Diff(ips, []net.IP{{8, 8, 8, 7}}); r != \"\" {\n\t\t\tt.Fatal(r)\n\t\t}\n\t}\n\n\t{ // Will match server 3,1,2 and server 3 returns expected one\n\t\tips, err := client.LookupIP(\"api.google.com\")\n\t\tif err != nil {\n\t\t\tt.Fatal(\"unexpected error: \", err)\n\t\t}\n\n\t\tif r := cmp.Diff(ips, []net.IP{{8, 8, 7, 7}}); r != \"\" {\n\t\t\tt.Fatal(r)\n\t\t}\n\t}\n\n\t{ // Will match server 4,3,1,2 and server 4 returns expected one\n\t\tips, err := client.LookupIP(\"v2.api.google.com\")\n\t\tif err != nil {\n\t\t\tt.Fatal(\"unexpected error: \", err)\n\t\t}\n\n\t\tif r := cmp.Diff(ips, []net.IP{{8, 8, 7, 8}}); r != \"\" {\n\t\t\tt.Fatal(r)\n\t\t}\n\t}\n\n\tendTime := time.Now()\n\tif startTime.After(endTime.Add(time.Second * 2)) {\n\t\tt.Error(\"DNS query doesn't finish in 2 seconds.\")\n\t}\n}\n"
  },
  {
    "path": "app/dns/udpns.go",
    "content": "// +build !confonly\n\npackage dns\n\nimport (\n\t\"context\"\n\t\"strings\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"golang.org/x/net/dns/dnsmessage\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol/dns\"\n\tudp_proto \"v2ray.com/core/common/protocol/udp\"\n\t\"v2ray.com/core/common/session\"\n\t\"v2ray.com/core/common/signal/pubsub\"\n\t\"v2ray.com/core/common/task\"\n\tdns_feature \"v2ray.com/core/features/dns\"\n\t\"v2ray.com/core/features/routing\"\n\t\"v2ray.com/core/transport/internet/udp\"\n)\n\ntype ClassicNameServer struct {\n\tsync.RWMutex\n\tname      string\n\taddress   net.Destination\n\tips       map[string]record\n\trequests  map[uint16]dnsRequest\n\tpub       *pubsub.Service\n\tudpServer *udp.Dispatcher\n\tcleanup   *task.Periodic\n\treqID     uint32\n\tclientIP  net.IP\n}\n\nfunc NewClassicNameServer(address net.Destination, dispatcher routing.Dispatcher, clientIP net.IP) *ClassicNameServer {\n\n\t// default to 53 if unspecific\n\tif address.Port == 0 {\n\t\taddress.Port = net.Port(53)\n\t}\n\n\ts := &ClassicNameServer{\n\t\taddress:  address,\n\t\tips:      make(map[string]record),\n\t\trequests: make(map[uint16]dnsRequest),\n\t\tclientIP: clientIP,\n\t\tpub:      pubsub.NewService(),\n\t\tname:     strings.ToUpper(address.String()),\n\t}\n\ts.cleanup = &task.Periodic{\n\t\tInterval: time.Minute,\n\t\tExecute:  s.Cleanup,\n\t}\n\ts.udpServer = udp.NewDispatcher(dispatcher, s.HandleResponse)\n\tnewError(\"DNS: created udp client inited for \", address.NetAddr()).AtInfo().WriteToLog()\n\treturn s\n}\n\nfunc (s *ClassicNameServer) Name() string {\n\treturn s.name\n}\n\nfunc (s *ClassicNameServer) Cleanup() error {\n\tnow := time.Now()\n\ts.Lock()\n\tdefer s.Unlock()\n\n\tif len(s.ips) == 0 && len(s.requests) == 0 {\n\t\treturn newError(s.name, \" nothing to do. stopping...\")\n\t}\n\n\tfor domain, record := range s.ips {\n\t\tif record.A != nil && record.A.Expire.Before(now) {\n\t\t\trecord.A = nil\n\t\t}\n\t\tif record.AAAA != nil && record.AAAA.Expire.Before(now) {\n\t\t\trecord.AAAA = nil\n\t\t}\n\n\t\tif record.A == nil && record.AAAA == nil {\n\t\t\tdelete(s.ips, domain)\n\t\t} else {\n\t\t\ts.ips[domain] = record\n\t\t}\n\t}\n\n\tif len(s.ips) == 0 {\n\t\ts.ips = make(map[string]record)\n\t}\n\n\tfor id, req := range s.requests {\n\t\tif req.expire.Before(now) {\n\t\t\tdelete(s.requests, id)\n\t\t}\n\t}\n\n\tif len(s.requests) == 0 {\n\t\ts.requests = make(map[uint16]dnsRequest)\n\t}\n\n\treturn nil\n}\n\nfunc (s *ClassicNameServer) HandleResponse(ctx context.Context, packet *udp_proto.Packet) {\n\n\tipRec, err := parseResponse(packet.Payload.Bytes())\n\tif err != nil {\n\t\tnewError(s.name, \" fail to parse responded DNS udp\").AtError().WriteToLog()\n\t\treturn\n\t}\n\n\ts.Lock()\n\tid := ipRec.ReqID\n\treq, ok := s.requests[id]\n\tif ok {\n\t\t// remove the pending request\n\t\tdelete(s.requests, id)\n\t}\n\ts.Unlock()\n\tif !ok {\n\t\tnewError(s.name, \" cannot find the pending request\").AtError().WriteToLog()\n\t\treturn\n\t}\n\n\tvar rec record\n\tswitch req.reqType {\n\tcase dnsmessage.TypeA:\n\t\trec.A = ipRec\n\tcase dnsmessage.TypeAAAA:\n\t\trec.AAAA = ipRec\n\t}\n\n\telapsed := time.Since(req.start)\n\tnewError(s.name, \" got answer: \", req.domain, \" \", req.reqType, \" -> \", ipRec.IP, \" \", elapsed).AtInfo().WriteToLog()\n\tif len(req.domain) > 0 && (rec.A != nil || rec.AAAA != nil) {\n\t\ts.updateIP(req.domain, rec)\n\t}\n}\n\nfunc (s *ClassicNameServer) updateIP(domain string, newRec record) {\n\ts.Lock()\n\n\tnewError(s.name, \" updating IP records for domain:\", domain).AtDebug().WriteToLog()\n\trec := s.ips[domain]\n\n\tupdated := false\n\tif isNewer(rec.A, newRec.A) {\n\t\trec.A = newRec.A\n\t\tupdated = true\n\t}\n\tif isNewer(rec.AAAA, newRec.AAAA) {\n\t\trec.AAAA = newRec.AAAA\n\t\tupdated = true\n\t}\n\n\tif updated {\n\t\ts.ips[domain] = rec\n\t}\n\tif newRec.A != nil {\n\t\ts.pub.Publish(domain+\"4\", nil)\n\t}\n\tif newRec.AAAA != nil {\n\t\ts.pub.Publish(domain+\"6\", nil)\n\t}\n\ts.Unlock()\n\tcommon.Must(s.cleanup.Start())\n}\n\nfunc (s *ClassicNameServer) newReqID() uint16 {\n\treturn uint16(atomic.AddUint32(&s.reqID, 1))\n}\n\nfunc (s *ClassicNameServer) addPendingRequest(req *dnsRequest) {\n\ts.Lock()\n\tdefer s.Unlock()\n\n\tid := req.msg.ID\n\treq.expire = time.Now().Add(time.Second * 8)\n\ts.requests[id] = *req\n}\n\nfunc (s *ClassicNameServer) sendQuery(ctx context.Context, domain string, option IPOption) {\n\tnewError(s.name, \" querying DNS for: \", domain).AtDebug().WriteToLog(session.ExportIDToError(ctx))\n\n\treqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(s.clientIP))\n\n\tfor _, req := range reqs {\n\t\ts.addPendingRequest(req)\n\t\tb, _ := dns.PackMessage(req.msg)\n\t\tudpCtx := context.Background()\n\t\tif inbound := session.InboundFromContext(ctx); inbound != nil {\n\t\t\tudpCtx = session.ContextWithInbound(udpCtx, inbound)\n\t\t}\n\t\tudpCtx = session.ContextWithContent(udpCtx, &session.Content{\n\t\t\tProtocol: \"dns\",\n\t\t})\n\t\ts.udpServer.Dispatch(udpCtx, s.address, b)\n\t}\n}\n\nfunc (s *ClassicNameServer) findIPsForDomain(domain string, option IPOption) ([]net.IP, error) {\n\ts.RLock()\n\trecord, found := s.ips[domain]\n\ts.RUnlock()\n\n\tif !found {\n\t\treturn nil, errRecordNotFound\n\t}\n\n\tvar ips []net.Address\n\tvar lastErr error\n\tif option.IPv4Enable {\n\t\ta, err := record.A.getIPs()\n\t\tif err != nil {\n\t\t\tlastErr = err\n\t\t}\n\t\tips = append(ips, a...)\n\t}\n\n\tif option.IPv6Enable {\n\t\taaaa, err := record.AAAA.getIPs()\n\t\tif err != nil {\n\t\t\tlastErr = err\n\t\t}\n\t\tips = append(ips, aaaa...)\n\t}\n\n\tif len(ips) > 0 {\n\t\treturn toNetIP(ips), nil\n\t}\n\n\tif lastErr != nil {\n\t\treturn nil, lastErr\n\t}\n\n\treturn nil, dns_feature.ErrEmptyResponse\n}\n\nfunc (s *ClassicNameServer) QueryIP(ctx context.Context, domain string, option IPOption) ([]net.IP, error) {\n\n\tfqdn := Fqdn(domain)\n\n\tips, err := s.findIPsForDomain(fqdn, option)\n\tif err != errRecordNotFound {\n\t\tnewError(s.name, \" cache HIT \", domain, \" -> \", ips).Base(err).AtDebug().WriteToLog()\n\t\treturn ips, err\n\t}\n\n\t// ipv4 and ipv6 belong to different subscription groups\n\tvar sub4, sub6 *pubsub.Subscriber\n\tif option.IPv4Enable {\n\t\tsub4 = s.pub.Subscribe(fqdn + \"4\")\n\t\tdefer sub4.Close()\n\t}\n\tif option.IPv6Enable {\n\t\tsub6 = s.pub.Subscribe(fqdn + \"6\")\n\t\tdefer sub6.Close()\n\t}\n\tdone := make(chan interface{})\n\tgo func() {\n\t\tif sub4 != nil {\n\t\t\tselect {\n\t\t\tcase <-sub4.Wait():\n\t\t\tcase <-ctx.Done():\n\t\t\t}\n\t\t}\n\t\tif sub6 != nil {\n\t\t\tselect {\n\t\t\tcase <-sub6.Wait():\n\t\t\tcase <-ctx.Done():\n\t\t\t}\n\t\t}\n\t\tclose(done)\n\t}()\n\ts.sendQuery(ctx, fqdn, option)\n\n\tfor {\n\t\tips, err := s.findIPsForDomain(fqdn, option)\n\t\tif err != errRecordNotFound {\n\t\t\treturn ips, err\n\t\t}\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil, ctx.Err()\n\t\tcase <-done:\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "app/log/command/command.go",
    "content": "// +build !confonly\n\npackage command\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n\nimport (\n\t\"context\"\n\n\tgrpc \"google.golang.org/grpc\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/app/log\"\n\t\"v2ray.com/core/common\"\n)\n\ntype LoggerServer struct {\n\tV *core.Instance\n}\n\n// RestartLogger implements LoggerService.\nfunc (s *LoggerServer) RestartLogger(ctx context.Context, request *RestartLoggerRequest) (*RestartLoggerResponse, error) {\n\tlogger := s.V.GetFeature((*log.Instance)(nil))\n\tif logger == nil {\n\t\treturn nil, newError(\"unable to get logger instance\")\n\t}\n\tif err := logger.Close(); err != nil {\n\t\treturn nil, newError(\"failed to close logger\").Base(err)\n\t}\n\tif err := logger.Start(); err != nil {\n\t\treturn nil, newError(\"failed to start logger\").Base(err)\n\t}\n\treturn &RestartLoggerResponse{}, nil\n}\n\nfunc (s *LoggerServer) mustEmbedUnimplementedLoggerServiceServer() {}\n\ntype service struct {\n\tv *core.Instance\n}\n\nfunc (s *service) Register(server *grpc.Server) {\n\tRegisterLoggerServiceServer(server, &LoggerServer{\n\t\tV: s.v,\n\t})\n}\n\nfunc init() {\n\tcommon.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, cfg interface{}) (interface{}, error) {\n\t\ts := core.MustFromContext(ctx)\n\t\treturn &service{v: s}, nil\n\t}))\n}\n"
  },
  {
    "path": "app/log/command/command_test.go",
    "content": "package command_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/app/dispatcher\"\n\t\"v2ray.com/core/app/log\"\n\t. \"v2ray.com/core/app/log/command\"\n\t\"v2ray.com/core/app/proxyman\"\n\t_ \"v2ray.com/core/app/proxyman/inbound\"\n\t_ \"v2ray.com/core/app/proxyman/outbound\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/serial\"\n)\n\nfunc TestLoggerRestart(t *testing.T) {\n\tv, err := core.New(&core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&log.Config{}),\n\t\t\tserial.ToTypedMessage(&dispatcher.Config{}),\n\t\t\tserial.ToTypedMessage(&proxyman.InboundConfig{}),\n\t\t\tserial.ToTypedMessage(&proxyman.OutboundConfig{}),\n\t\t},\n\t})\n\tcommon.Must(err)\n\tcommon.Must(v.Start())\n\n\tserver := &LoggerServer{\n\t\tV: v,\n\t}\n\tcommon.Must2(server.RestartLogger(context.Background(), &RestartLoggerRequest{}))\n}\n"
  },
  {
    "path": "app/log/command/config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: app/log/command/config.proto\n\npackage command\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype Config struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *Config) Reset() {\n\t*x = Config{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_log_command_config_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Config) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Config) ProtoMessage() {}\n\nfunc (x *Config) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_log_command_config_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Config.ProtoReflect.Descriptor instead.\nfunc (*Config) Descriptor() ([]byte, []int) {\n\treturn file_app_log_command_config_proto_rawDescGZIP(), []int{0}\n}\n\ntype RestartLoggerRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *RestartLoggerRequest) Reset() {\n\t*x = RestartLoggerRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_log_command_config_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *RestartLoggerRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RestartLoggerRequest) ProtoMessage() {}\n\nfunc (x *RestartLoggerRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_log_command_config_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RestartLoggerRequest.ProtoReflect.Descriptor instead.\nfunc (*RestartLoggerRequest) Descriptor() ([]byte, []int) {\n\treturn file_app_log_command_config_proto_rawDescGZIP(), []int{1}\n}\n\ntype RestartLoggerResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *RestartLoggerResponse) Reset() {\n\t*x = RestartLoggerResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_log_command_config_proto_msgTypes[2]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *RestartLoggerResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RestartLoggerResponse) ProtoMessage() {}\n\nfunc (x *RestartLoggerResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_log_command_config_proto_msgTypes[2]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RestartLoggerResponse.ProtoReflect.Descriptor instead.\nfunc (*RestartLoggerResponse) Descriptor() ([]byte, []int) {\n\treturn file_app_log_command_config_proto_rawDescGZIP(), []int{2}\n}\n\nvar File_app_log_command_config_proto protoreflect.FileDescriptor\n\nvar file_app_log_command_config_proto_rawDesc = []byte{\n\t0x0a, 0x1c, 0x61, 0x70, 0x70, 0x2f, 0x6c, 0x6f, 0x67, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e,\n\t0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1a,\n\t0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6c,\n\t0x6f, 0x67, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x22, 0x08, 0x0a, 0x06, 0x43, 0x6f,\n\t0x6e, 0x66, 0x69, 0x67, 0x22, 0x16, 0x0a, 0x14, 0x52, 0x65, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4c,\n\t0x6f, 0x67, 0x67, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x17, 0x0a, 0x15,\n\t0x52, 0x65, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4c, 0x6f, 0x67, 0x67, 0x65, 0x72, 0x52, 0x65, 0x73,\n\t0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x87, 0x01, 0x0a, 0x0d, 0x4c, 0x6f, 0x67, 0x67, 0x65, 0x72,\n\t0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x76, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x74, 0x61,\n\t0x72, 0x74, 0x4c, 0x6f, 0x67, 0x67, 0x65, 0x72, 0x12, 0x30, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,\n\t0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6c, 0x6f, 0x67, 0x2e, 0x63, 0x6f,\n\t0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4c, 0x6f, 0x67,\n\t0x67, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x76, 0x32, 0x72,\n\t0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6c, 0x6f, 0x67, 0x2e,\n\t0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4c,\n\t0x6f, 0x67, 0x67, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42,\n\t0x5f, 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72,\n\t0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6c, 0x6f, 0x67, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e,\n\t0x64, 0x50, 0x01, 0x5a, 0x1e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63,\n\t0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x6c, 0x6f, 0x67, 0x2f, 0x63, 0x6f, 0x6d, 0x6d,\n\t0x61, 0x6e, 0x64, 0xaa, 0x02, 0x1a, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65,\n\t0x2e, 0x41, 0x70, 0x70, 0x2e, 0x4c, 0x6f, 0x67, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,\n\t0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_app_log_command_config_proto_rawDescOnce sync.Once\n\tfile_app_log_command_config_proto_rawDescData = file_app_log_command_config_proto_rawDesc\n)\n\nfunc file_app_log_command_config_proto_rawDescGZIP() []byte {\n\tfile_app_log_command_config_proto_rawDescOnce.Do(func() {\n\t\tfile_app_log_command_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_log_command_config_proto_rawDescData)\n\t})\n\treturn file_app_log_command_config_proto_rawDescData\n}\n\nvar file_app_log_command_config_proto_msgTypes = make([]protoimpl.MessageInfo, 3)\nvar file_app_log_command_config_proto_goTypes = []interface{}{\n\t(*Config)(nil),                // 0: v2ray.core.app.log.command.Config\n\t(*RestartLoggerRequest)(nil),  // 1: v2ray.core.app.log.command.RestartLoggerRequest\n\t(*RestartLoggerResponse)(nil), // 2: v2ray.core.app.log.command.RestartLoggerResponse\n}\nvar file_app_log_command_config_proto_depIdxs = []int32{\n\t1, // 0: v2ray.core.app.log.command.LoggerService.RestartLogger:input_type -> v2ray.core.app.log.command.RestartLoggerRequest\n\t2, // 1: v2ray.core.app.log.command.LoggerService.RestartLogger:output_type -> v2ray.core.app.log.command.RestartLoggerResponse\n\t1, // [1:2] is the sub-list for method output_type\n\t0, // [0:1] is the sub-list for method input_type\n\t0, // [0:0] is the sub-list for extension type_name\n\t0, // [0:0] is the sub-list for extension extendee\n\t0, // [0:0] is the sub-list for field type_name\n}\n\nfunc init() { file_app_log_command_config_proto_init() }\nfunc file_app_log_command_config_proto_init() {\n\tif File_app_log_command_config_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_app_log_command_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Config); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_log_command_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*RestartLoggerRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_log_command_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*RestartLoggerResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_app_log_command_config_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   3,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   1,\n\t\t},\n\t\tGoTypes:           file_app_log_command_config_proto_goTypes,\n\t\tDependencyIndexes: file_app_log_command_config_proto_depIdxs,\n\t\tMessageInfos:      file_app_log_command_config_proto_msgTypes,\n\t}.Build()\n\tFile_app_log_command_config_proto = out.File\n\tfile_app_log_command_config_proto_rawDesc = nil\n\tfile_app_log_command_config_proto_goTypes = nil\n\tfile_app_log_command_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "app/log/command/config.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.app.log.command;\noption csharp_namespace = \"V2Ray.Core.App.Log.Command\";\noption go_package = \"v2ray.com/core/app/log/command\";\noption java_package = \"com.v2ray.core.app.log.command\";\noption java_multiple_files = true;\n\nmessage Config {}\n\nmessage RestartLoggerRequest {}\n\nmessage RestartLoggerResponse {}\n\nservice LoggerService {\n  rpc RestartLogger(RestartLoggerRequest) returns (RestartLoggerResponse) {}\n}\n"
  },
  {
    "path": "app/log/command/config_grpc.pb.go",
    "content": "// Code generated by protoc-gen-go-grpc. DO NOT EDIT.\n\npackage command\n\nimport (\n\tcontext \"context\"\n\tgrpc \"google.golang.org/grpc\"\n\tcodes \"google.golang.org/grpc/codes\"\n\tstatus \"google.golang.org/grpc/status\"\n)\n\n// This is a compile-time assertion to ensure that this generated file\n// is compatible with the grpc package it is being compiled against.\nconst _ = grpc.SupportPackageIsVersion7\n\n// LoggerServiceClient is the client API for LoggerService service.\n//\n// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.\ntype LoggerServiceClient interface {\n\tRestartLogger(ctx context.Context, in *RestartLoggerRequest, opts ...grpc.CallOption) (*RestartLoggerResponse, error)\n}\n\ntype loggerServiceClient struct {\n\tcc grpc.ClientConnInterface\n}\n\nfunc NewLoggerServiceClient(cc grpc.ClientConnInterface) LoggerServiceClient {\n\treturn &loggerServiceClient{cc}\n}\n\nfunc (c *loggerServiceClient) RestartLogger(ctx context.Context, in *RestartLoggerRequest, opts ...grpc.CallOption) (*RestartLoggerResponse, error) {\n\tout := new(RestartLoggerResponse)\n\terr := c.cc.Invoke(ctx, \"/v2ray.core.app.log.command.LoggerService/RestartLogger\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\n// LoggerServiceServer is the server API for LoggerService service.\n// All implementations must embed UnimplementedLoggerServiceServer\n// for forward compatibility\ntype LoggerServiceServer interface {\n\tRestartLogger(context.Context, *RestartLoggerRequest) (*RestartLoggerResponse, error)\n\tmustEmbedUnimplementedLoggerServiceServer()\n}\n\n// UnimplementedLoggerServiceServer must be embedded to have forward compatible implementations.\ntype UnimplementedLoggerServiceServer struct {\n}\n\nfunc (UnimplementedLoggerServiceServer) RestartLogger(context.Context, *RestartLoggerRequest) (*RestartLoggerResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method RestartLogger not implemented\")\n}\nfunc (UnimplementedLoggerServiceServer) mustEmbedUnimplementedLoggerServiceServer() {}\n\n// UnsafeLoggerServiceServer may be embedded to opt out of forward compatibility for this service.\n// Use of this interface is not recommended, as added methods to LoggerServiceServer will\n// result in compilation errors.\ntype UnsafeLoggerServiceServer interface {\n\tmustEmbedUnimplementedLoggerServiceServer()\n}\n\nfunc RegisterLoggerServiceServer(s *grpc.Server, srv LoggerServiceServer) {\n\ts.RegisterService(&_LoggerService_serviceDesc, srv)\n}\n\nfunc _LoggerService_RestartLogger_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(RestartLoggerRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(LoggerServiceServer).RestartLogger(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/v2ray.core.app.log.command.LoggerService/RestartLogger\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(LoggerServiceServer).RestartLogger(ctx, req.(*RestartLoggerRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nvar _LoggerService_serviceDesc = grpc.ServiceDesc{\n\tServiceName: \"v2ray.core.app.log.command.LoggerService\",\n\tHandlerType: (*LoggerServiceServer)(nil),\n\tMethods: []grpc.MethodDesc{\n\t\t{\n\t\t\tMethodName: \"RestartLogger\",\n\t\t\tHandler:    _LoggerService_RestartLogger_Handler,\n\t\t},\n\t},\n\tStreams:  []grpc.StreamDesc{},\n\tMetadata: \"app/log/command/config.proto\",\n}\n"
  },
  {
    "path": "app/log/command/errors.generated.go",
    "content": "package command\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "app/log/config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: app/log/config.proto\n\npackage log\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n\tlog \"v2ray.com/core/common/log\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype LogType int32\n\nconst (\n\tLogType_None    LogType = 0\n\tLogType_Console LogType = 1\n\tLogType_File    LogType = 2\n\tLogType_Event   LogType = 3\n)\n\n// Enum value maps for LogType.\nvar (\n\tLogType_name = map[int32]string{\n\t\t0: \"None\",\n\t\t1: \"Console\",\n\t\t2: \"File\",\n\t\t3: \"Event\",\n\t}\n\tLogType_value = map[string]int32{\n\t\t\"None\":    0,\n\t\t\"Console\": 1,\n\t\t\"File\":    2,\n\t\t\"Event\":   3,\n\t}\n)\n\nfunc (x LogType) Enum() *LogType {\n\tp := new(LogType)\n\t*p = x\n\treturn p\n}\n\nfunc (x LogType) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (LogType) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_app_log_config_proto_enumTypes[0].Descriptor()\n}\n\nfunc (LogType) Type() protoreflect.EnumType {\n\treturn &file_app_log_config_proto_enumTypes[0]\n}\n\nfunc (x LogType) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use LogType.Descriptor instead.\nfunc (LogType) EnumDescriptor() ([]byte, []int) {\n\treturn file_app_log_config_proto_rawDescGZIP(), []int{0}\n}\n\ntype Config struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tErrorLogType  LogType      `protobuf:\"varint,1,opt,name=error_log_type,json=errorLogType,proto3,enum=v2ray.core.app.log.LogType\" json:\"error_log_type,omitempty\"`\n\tErrorLogLevel log.Severity `protobuf:\"varint,2,opt,name=error_log_level,json=errorLogLevel,proto3,enum=v2ray.core.common.log.Severity\" json:\"error_log_level,omitempty\"`\n\tErrorLogPath  string       `protobuf:\"bytes,3,opt,name=error_log_path,json=errorLogPath,proto3\" json:\"error_log_path,omitempty\"`\n\tAccessLogType LogType      `protobuf:\"varint,4,opt,name=access_log_type,json=accessLogType,proto3,enum=v2ray.core.app.log.LogType\" json:\"access_log_type,omitempty\"`\n\tAccessLogPath string       `protobuf:\"bytes,5,opt,name=access_log_path,json=accessLogPath,proto3\" json:\"access_log_path,omitempty\"`\n}\n\nfunc (x *Config) Reset() {\n\t*x = Config{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_log_config_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Config) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Config) ProtoMessage() {}\n\nfunc (x *Config) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_log_config_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Config.ProtoReflect.Descriptor instead.\nfunc (*Config) Descriptor() ([]byte, []int) {\n\treturn file_app_log_config_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *Config) GetErrorLogType() LogType {\n\tif x != nil {\n\t\treturn x.ErrorLogType\n\t}\n\treturn LogType_None\n}\n\nfunc (x *Config) GetErrorLogLevel() log.Severity {\n\tif x != nil {\n\t\treturn x.ErrorLogLevel\n\t}\n\treturn log.Severity_Unknown\n}\n\nfunc (x *Config) GetErrorLogPath() string {\n\tif x != nil {\n\t\treturn x.ErrorLogPath\n\t}\n\treturn \"\"\n}\n\nfunc (x *Config) GetAccessLogType() LogType {\n\tif x != nil {\n\t\treturn x.AccessLogType\n\t}\n\treturn LogType_None\n}\n\nfunc (x *Config) GetAccessLogPath() string {\n\tif x != nil {\n\t\treturn x.AccessLogPath\n\t}\n\treturn \"\"\n}\n\nvar File_app_log_config_proto protoreflect.FileDescriptor\n\nvar file_app_log_config_proto_rawDesc = []byte{\n\t0x0a, 0x14, 0x61, 0x70, 0x70, 0x2f, 0x6c, 0x6f, 0x67, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,\n\t0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x12, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,\n\t0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6c, 0x6f, 0x67, 0x1a, 0x14, 0x63, 0x6f, 0x6d, 0x6d,\n\t0x6f, 0x6e, 0x2f, 0x6c, 0x6f, 0x67, 0x2f, 0x6c, 0x6f, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,\n\t0x22, 0xa7, 0x02, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x41, 0x0a, 0x0e, 0x65,\n\t0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20,\n\t0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,\n\t0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6c, 0x6f, 0x67, 0x2e, 0x4c, 0x6f, 0x67, 0x54, 0x79, 0x70, 0x65,\n\t0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4c, 0x6f, 0x67, 0x54, 0x79, 0x70, 0x65, 0x12, 0x47,\n\t0x0a, 0x0f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x6c, 0x65, 0x76, 0x65,\n\t0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,\n\t0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6c, 0x6f, 0x67, 0x2e,\n\t0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x52, 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4c,\n\t0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x24, 0x0a, 0x0e, 0x65, 0x72, 0x72, 0x6f, 0x72,\n\t0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,\n\t0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4c, 0x6f, 0x67, 0x50, 0x61, 0x74, 0x68, 0x12, 0x43, 0x0a,\n\t0x0f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x74, 0x79, 0x70, 0x65,\n\t0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,\n\t0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6c, 0x6f, 0x67, 0x2e, 0x4c, 0x6f, 0x67, 0x54,\n\t0x79, 0x70, 0x65, 0x52, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x6f, 0x67, 0x54, 0x79,\n\t0x70, 0x65, 0x12, 0x26, 0x0a, 0x0f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6c, 0x6f, 0x67,\n\t0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x61, 0x63, 0x63,\n\t0x65, 0x73, 0x73, 0x4c, 0x6f, 0x67, 0x50, 0x61, 0x74, 0x68, 0x2a, 0x35, 0x0a, 0x07, 0x4c, 0x6f,\n\t0x67, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x6f, 0x6e, 0x65, 0x10, 0x00, 0x12,\n\t0x0b, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04,\n\t0x46, 0x69, 0x6c, 0x65, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x10,\n\t0x03, 0x42, 0x47, 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,\n\t0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6c, 0x6f, 0x67, 0x50, 0x01, 0x5a, 0x16, 0x76,\n\t0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70,\n\t0x70, 0x2f, 0x6c, 0x6f, 0x67, 0xaa, 0x02, 0x12, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f,\n\t0x72, 0x65, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x4c, 0x6f, 0x67, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,\n\t0x6f, 0x33,\n}\n\nvar (\n\tfile_app_log_config_proto_rawDescOnce sync.Once\n\tfile_app_log_config_proto_rawDescData = file_app_log_config_proto_rawDesc\n)\n\nfunc file_app_log_config_proto_rawDescGZIP() []byte {\n\tfile_app_log_config_proto_rawDescOnce.Do(func() {\n\t\tfile_app_log_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_log_config_proto_rawDescData)\n\t})\n\treturn file_app_log_config_proto_rawDescData\n}\n\nvar file_app_log_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1)\nvar file_app_log_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)\nvar file_app_log_config_proto_goTypes = []interface{}{\n\t(LogType)(0),      // 0: v2ray.core.app.log.LogType\n\t(*Config)(nil),    // 1: v2ray.core.app.log.Config\n\t(log.Severity)(0), // 2: v2ray.core.common.log.Severity\n}\nvar file_app_log_config_proto_depIdxs = []int32{\n\t0, // 0: v2ray.core.app.log.Config.error_log_type:type_name -> v2ray.core.app.log.LogType\n\t2, // 1: v2ray.core.app.log.Config.error_log_level:type_name -> v2ray.core.common.log.Severity\n\t0, // 2: v2ray.core.app.log.Config.access_log_type:type_name -> v2ray.core.app.log.LogType\n\t3, // [3:3] is the sub-list for method output_type\n\t3, // [3:3] is the sub-list for method input_type\n\t3, // [3:3] is the sub-list for extension type_name\n\t3, // [3:3] is the sub-list for extension extendee\n\t0, // [0:3] is the sub-list for field type_name\n}\n\nfunc init() { file_app_log_config_proto_init() }\nfunc file_app_log_config_proto_init() {\n\tif File_app_log_config_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_app_log_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Config); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_app_log_config_proto_rawDesc,\n\t\t\tNumEnums:      1,\n\t\t\tNumMessages:   1,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_app_log_config_proto_goTypes,\n\t\tDependencyIndexes: file_app_log_config_proto_depIdxs,\n\t\tEnumInfos:         file_app_log_config_proto_enumTypes,\n\t\tMessageInfos:      file_app_log_config_proto_msgTypes,\n\t}.Build()\n\tFile_app_log_config_proto = out.File\n\tfile_app_log_config_proto_rawDesc = nil\n\tfile_app_log_config_proto_goTypes = nil\n\tfile_app_log_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "app/log/config.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.app.log;\noption csharp_namespace = \"V2Ray.Core.App.Log\";\noption go_package = \"v2ray.com/core/app/log\";\noption java_package = \"com.v2ray.core.app.log\";\noption java_multiple_files = true;\n\nimport \"common/log/log.proto\";\n\nenum LogType {\n  None = 0;\n  Console = 1;\n  File = 2;\n  Event = 3;\n}\n\nmessage Config {\n  LogType error_log_type = 1;\n  v2ray.core.common.log.Severity error_log_level = 2;\n  string error_log_path = 3;\n\n  LogType access_log_type = 4;\n  string access_log_path = 5;\n}\n"
  },
  {
    "path": "app/log/errors.generated.go",
    "content": "package log\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "app/log/log.go",
    "content": "// +build !confonly\n\npackage log\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n\nimport (\n\t\"context\"\n\t\"sync\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/log\"\n)\n\n// Instance is a log.Handler that handles logs.\ntype Instance struct {\n\tsync.RWMutex\n\tconfig       *Config\n\taccessLogger log.Handler\n\terrorLogger  log.Handler\n\tactive       bool\n}\n\n// New creates a new log.Instance based on the given config.\nfunc New(ctx context.Context, config *Config) (*Instance, error) {\n\tg := &Instance{\n\t\tconfig: config,\n\t\tactive: false,\n\t}\n\tlog.RegisterHandler(g)\n\n\t// start logger instantly on inited\n\t// other modules would log during init\n\tif err := g.startInternal(); err != nil {\n\t\treturn nil, err\n\t}\n\n\tnewError(\"Logger started\").AtDebug().WriteToLog()\n\treturn g, nil\n}\n\nfunc (g *Instance) initAccessLogger() error {\n\thandler, err := createHandler(g.config.AccessLogType, HandlerCreatorOptions{\n\t\tPath: g.config.AccessLogPath,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tg.accessLogger = handler\n\treturn nil\n}\n\nfunc (g *Instance) initErrorLogger() error {\n\thandler, err := createHandler(g.config.ErrorLogType, HandlerCreatorOptions{\n\t\tPath: g.config.ErrorLogPath,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tg.errorLogger = handler\n\treturn nil\n}\n\n// Type implements common.HasType.\nfunc (*Instance) Type() interface{} {\n\treturn (*Instance)(nil)\n}\n\nfunc (g *Instance) startInternal() error {\n\tg.Lock()\n\tdefer g.Unlock()\n\n\tif g.active {\n\t\treturn nil\n\t}\n\n\tg.active = true\n\n\tif err := g.initAccessLogger(); err != nil {\n\t\treturn newError(\"failed to initialize access logger\").Base(err).AtWarning()\n\t}\n\tif err := g.initErrorLogger(); err != nil {\n\t\treturn newError(\"failed to initialize error logger\").Base(err).AtWarning()\n\t}\n\n\treturn nil\n}\n\n// Start implements common.Runnable.Start().\nfunc (g *Instance) Start() error {\n\treturn g.startInternal()\n}\n\n// Handle implements log.Handler.\nfunc (g *Instance) Handle(msg log.Message) {\n\tg.RLock()\n\tdefer g.RUnlock()\n\n\tif !g.active {\n\t\treturn\n\t}\n\n\tswitch msg := msg.(type) {\n\tcase *log.AccessMessage:\n\t\tif g.accessLogger != nil {\n\t\t\tg.accessLogger.Handle(msg)\n\t\t}\n\tcase *log.GeneralMessage:\n\t\tif g.errorLogger != nil && msg.Severity <= g.config.ErrorLogLevel {\n\t\t\tg.errorLogger.Handle(msg)\n\t\t}\n\tdefault:\n\t\t// Swallow\n\t}\n}\n\n// Close implements common.Closable.Close().\nfunc (g *Instance) Close() error {\n\tnewError(\"Logger closing\").AtDebug().WriteToLog()\n\n\tg.Lock()\n\tdefer g.Unlock()\n\n\tif !g.active {\n\t\treturn nil\n\t}\n\n\tg.active = false\n\n\tcommon.Close(g.accessLogger) // nolint: errcheck\n\tg.accessLogger = nil\n\n\tcommon.Close(g.errorLogger) // nolint: errcheck\n\tg.errorLogger = nil\n\n\treturn nil\n}\n\nfunc init() {\n\tcommon.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {\n\t\treturn New(ctx, config.(*Config))\n\t}))\n}\n"
  },
  {
    "path": "app/log/log_creator.go",
    "content": "// +build !confonly\n\npackage log\n\nimport (\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/log\"\n)\n\ntype HandlerCreatorOptions struct {\n\tPath string\n}\n\ntype HandlerCreator func(LogType, HandlerCreatorOptions) (log.Handler, error)\n\nvar (\n\thandlerCreatorMap = make(map[LogType]HandlerCreator)\n)\n\nfunc RegisterHandlerCreator(logType LogType, f HandlerCreator) error {\n\tif f == nil {\n\t\treturn newError(\"nil HandlerCreator\")\n\t}\n\n\thandlerCreatorMap[logType] = f\n\treturn nil\n}\n\nfunc createHandler(logType LogType, options HandlerCreatorOptions) (log.Handler, error) {\n\tcreator, found := handlerCreatorMap[logType]\n\tif !found {\n\t\treturn nil, newError(\"unable to create log handler for \", logType)\n\t}\n\treturn creator(logType, options)\n}\n\nfunc init() {\n\tcommon.Must(RegisterHandlerCreator(LogType_Console, func(lt LogType, options HandlerCreatorOptions) (log.Handler, error) {\n\t\treturn log.NewLogger(log.CreateStdoutLogWriter()), nil\n\t}))\n\n\tcommon.Must(RegisterHandlerCreator(LogType_File, func(lt LogType, options HandlerCreatorOptions) (log.Handler, error) {\n\t\tcreator, err := log.CreateFileLogWriter(options.Path)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn log.NewLogger(creator), nil\n\t}))\n\n\tcommon.Must(RegisterHandlerCreator(LogType_None, func(lt LogType, options HandlerCreatorOptions) (log.Handler, error) {\n\t\treturn nil, nil\n\t}))\n}\n"
  },
  {
    "path": "app/log/log_test.go",
    "content": "package log_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/golang/mock/gomock\"\n\t\"v2ray.com/core/app/log\"\n\t\"v2ray.com/core/common\"\n\tclog \"v2ray.com/core/common/log\"\n\t\"v2ray.com/core/testing/mocks\"\n)\n\nfunc TestCustomLogHandler(t *testing.T) {\n\tmockCtl := gomock.NewController(t)\n\tdefer mockCtl.Finish()\n\n\tvar loggedValue []string\n\n\tmockHandler := mocks.NewLogHandler(mockCtl)\n\tmockHandler.EXPECT().Handle(gomock.Any()).AnyTimes().DoAndReturn(func(msg clog.Message) {\n\t\tloggedValue = append(loggedValue, msg.String())\n\t})\n\n\tlog.RegisterHandlerCreator(log.LogType_Console, func(lt log.LogType, options log.HandlerCreatorOptions) (clog.Handler, error) {\n\t\treturn mockHandler, nil\n\t})\n\n\tlogger, err := log.New(context.Background(), &log.Config{\n\t\tErrorLogLevel: clog.Severity_Debug,\n\t\tErrorLogType:  log.LogType_Console,\n\t\tAccessLogType: log.LogType_None,\n\t})\n\tcommon.Must(err)\n\n\tcommon.Must(logger.Start())\n\n\tclog.Record(&clog.GeneralMessage{\n\t\tSeverity: clog.Severity_Debug,\n\t\tContent:  \"test\",\n\t})\n\n\tif len(loggedValue) < 2 {\n\t\tt.Fatal(\"expected 2 log messages, but actually \", loggedValue)\n\t}\n\n\tif loggedValue[1] != \"[Debug] test\" {\n\t\tt.Fatal(\"expected '[Debug] test', but actually \", loggedValue[1])\n\t}\n\n\tcommon.Must(logger.Close())\n}\n"
  },
  {
    "path": "app/policy/config.go",
    "content": "package policy\n\nimport (\n\t\"time\"\n\n\t\"v2ray.com/core/features/policy\"\n)\n\n// Duration converts Second to time.Duration.\nfunc (s *Second) Duration() time.Duration {\n\tif s == nil {\n\t\treturn 0\n\t}\n\treturn time.Second * time.Duration(s.Value)\n}\n\nfunc defaultPolicy() *Policy {\n\tp := policy.SessionDefault()\n\n\treturn &Policy{\n\t\tTimeout: &Policy_Timeout{\n\t\t\tHandshake:      &Second{Value: uint32(p.Timeouts.Handshake / time.Second)},\n\t\t\tConnectionIdle: &Second{Value: uint32(p.Timeouts.ConnectionIdle / time.Second)},\n\t\t\tUplinkOnly:     &Second{Value: uint32(p.Timeouts.UplinkOnly / time.Second)},\n\t\t\tDownlinkOnly:   &Second{Value: uint32(p.Timeouts.DownlinkOnly / time.Second)},\n\t\t},\n\t\tBuffer: &Policy_Buffer{\n\t\t\tConnection: p.Buffer.PerConnection,\n\t\t},\n\t}\n}\n\nfunc (p *Policy_Timeout) overrideWith(another *Policy_Timeout) {\n\tif another.Handshake != nil {\n\t\tp.Handshake = &Second{Value: another.Handshake.Value}\n\t}\n\tif another.ConnectionIdle != nil {\n\t\tp.ConnectionIdle = &Second{Value: another.ConnectionIdle.Value}\n\t}\n\tif another.UplinkOnly != nil {\n\t\tp.UplinkOnly = &Second{Value: another.UplinkOnly.Value}\n\t}\n\tif another.DownlinkOnly != nil {\n\t\tp.DownlinkOnly = &Second{Value: another.DownlinkOnly.Value}\n\t}\n}\n\nfunc (p *Policy) overrideWith(another *Policy) {\n\tif another.Timeout != nil {\n\t\tp.Timeout.overrideWith(another.Timeout)\n\t}\n\tif another.Stats != nil && p.Stats == nil {\n\t\tp.Stats = &Policy_Stats{}\n\t\tp.Stats = another.Stats\n\t}\n\tif another.Buffer != nil {\n\t\tp.Buffer = &Policy_Buffer{\n\t\t\tConnection: another.Buffer.Connection,\n\t\t}\n\t}\n}\n\n// ToCorePolicy converts this Policy to policy.Session.\nfunc (p *Policy) ToCorePolicy() policy.Session {\n\tcp := policy.SessionDefault()\n\n\tif p.Timeout != nil {\n\t\tcp.Timeouts.ConnectionIdle = p.Timeout.ConnectionIdle.Duration()\n\t\tcp.Timeouts.Handshake = p.Timeout.Handshake.Duration()\n\t\tcp.Timeouts.DownlinkOnly = p.Timeout.DownlinkOnly.Duration()\n\t\tcp.Timeouts.UplinkOnly = p.Timeout.UplinkOnly.Duration()\n\t}\n\tif p.Stats != nil {\n\t\tcp.Stats.UserUplink = p.Stats.UserUplink\n\t\tcp.Stats.UserDownlink = p.Stats.UserDownlink\n\t}\n\tif p.Buffer != nil {\n\t\tcp.Buffer.PerConnection = p.Buffer.Connection\n\t}\n\treturn cp\n}\n\n// ToCorePolicy converts this SystemPolicy to policy.System.\nfunc (p *SystemPolicy) ToCorePolicy() policy.System {\n\treturn policy.System{\n\t\tStats: policy.SystemStats{\n\t\t\tInboundUplink:    p.Stats.InboundUplink,\n\t\t\tInboundDownlink:  p.Stats.InboundDownlink,\n\t\t\tOutboundUplink:   p.Stats.OutboundUplink,\n\t\t\tOutboundDownlink: p.Stats.OutboundDownlink,\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "app/policy/config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: app/policy/config.proto\n\npackage policy\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype Second struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tValue uint32 `protobuf:\"varint,1,opt,name=value,proto3\" json:\"value,omitempty\"`\n}\n\nfunc (x *Second) Reset() {\n\t*x = Second{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_policy_config_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Second) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Second) ProtoMessage() {}\n\nfunc (x *Second) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_policy_config_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Second.ProtoReflect.Descriptor instead.\nfunc (*Second) Descriptor() ([]byte, []int) {\n\treturn file_app_policy_config_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *Second) GetValue() uint32 {\n\tif x != nil {\n\t\treturn x.Value\n\t}\n\treturn 0\n}\n\ntype Policy struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tTimeout *Policy_Timeout `protobuf:\"bytes,1,opt,name=timeout,proto3\" json:\"timeout,omitempty\"`\n\tStats   *Policy_Stats   `protobuf:\"bytes,2,opt,name=stats,proto3\" json:\"stats,omitempty\"`\n\tBuffer  *Policy_Buffer  `protobuf:\"bytes,3,opt,name=buffer,proto3\" json:\"buffer,omitempty\"`\n}\n\nfunc (x *Policy) Reset() {\n\t*x = Policy{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_policy_config_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Policy) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Policy) ProtoMessage() {}\n\nfunc (x *Policy) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_policy_config_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Policy.ProtoReflect.Descriptor instead.\nfunc (*Policy) Descriptor() ([]byte, []int) {\n\treturn file_app_policy_config_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *Policy) GetTimeout() *Policy_Timeout {\n\tif x != nil {\n\t\treturn x.Timeout\n\t}\n\treturn nil\n}\n\nfunc (x *Policy) GetStats() *Policy_Stats {\n\tif x != nil {\n\t\treturn x.Stats\n\t}\n\treturn nil\n}\n\nfunc (x *Policy) GetBuffer() *Policy_Buffer {\n\tif x != nil {\n\t\treturn x.Buffer\n\t}\n\treturn nil\n}\n\ntype SystemPolicy struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tStats *SystemPolicy_Stats `protobuf:\"bytes,1,opt,name=stats,proto3\" json:\"stats,omitempty\"`\n}\n\nfunc (x *SystemPolicy) Reset() {\n\t*x = SystemPolicy{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_policy_config_proto_msgTypes[2]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *SystemPolicy) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SystemPolicy) ProtoMessage() {}\n\nfunc (x *SystemPolicy) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_policy_config_proto_msgTypes[2]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SystemPolicy.ProtoReflect.Descriptor instead.\nfunc (*SystemPolicy) Descriptor() ([]byte, []int) {\n\treturn file_app_policy_config_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *SystemPolicy) GetStats() *SystemPolicy_Stats {\n\tif x != nil {\n\t\treturn x.Stats\n\t}\n\treturn nil\n}\n\ntype Config struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tLevel  map[uint32]*Policy `protobuf:\"bytes,1,rep,name=level,proto3\" json:\"level,omitempty\" protobuf_key:\"varint,1,opt,name=key,proto3\" protobuf_val:\"bytes,2,opt,name=value,proto3\"`\n\tSystem *SystemPolicy      `protobuf:\"bytes,2,opt,name=system,proto3\" json:\"system,omitempty\"`\n}\n\nfunc (x *Config) Reset() {\n\t*x = Config{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_policy_config_proto_msgTypes[3]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Config) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Config) ProtoMessage() {}\n\nfunc (x *Config) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_policy_config_proto_msgTypes[3]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Config.ProtoReflect.Descriptor instead.\nfunc (*Config) Descriptor() ([]byte, []int) {\n\treturn file_app_policy_config_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *Config) GetLevel() map[uint32]*Policy {\n\tif x != nil {\n\t\treturn x.Level\n\t}\n\treturn nil\n}\n\nfunc (x *Config) GetSystem() *SystemPolicy {\n\tif x != nil {\n\t\treturn x.System\n\t}\n\treturn nil\n}\n\n// Timeout is a message for timeout settings in various stages, in seconds.\ntype Policy_Timeout struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tHandshake      *Second `protobuf:\"bytes,1,opt,name=handshake,proto3\" json:\"handshake,omitempty\"`\n\tConnectionIdle *Second `protobuf:\"bytes,2,opt,name=connection_idle,json=connectionIdle,proto3\" json:\"connection_idle,omitempty\"`\n\tUplinkOnly     *Second `protobuf:\"bytes,3,opt,name=uplink_only,json=uplinkOnly,proto3\" json:\"uplink_only,omitempty\"`\n\tDownlinkOnly   *Second `protobuf:\"bytes,4,opt,name=downlink_only,json=downlinkOnly,proto3\" json:\"downlink_only,omitempty\"`\n}\n\nfunc (x *Policy_Timeout) Reset() {\n\t*x = Policy_Timeout{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_policy_config_proto_msgTypes[4]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Policy_Timeout) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Policy_Timeout) ProtoMessage() {}\n\nfunc (x *Policy_Timeout) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_policy_config_proto_msgTypes[4]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Policy_Timeout.ProtoReflect.Descriptor instead.\nfunc (*Policy_Timeout) Descriptor() ([]byte, []int) {\n\treturn file_app_policy_config_proto_rawDescGZIP(), []int{1, 0}\n}\n\nfunc (x *Policy_Timeout) GetHandshake() *Second {\n\tif x != nil {\n\t\treturn x.Handshake\n\t}\n\treturn nil\n}\n\nfunc (x *Policy_Timeout) GetConnectionIdle() *Second {\n\tif x != nil {\n\t\treturn x.ConnectionIdle\n\t}\n\treturn nil\n}\n\nfunc (x *Policy_Timeout) GetUplinkOnly() *Second {\n\tif x != nil {\n\t\treturn x.UplinkOnly\n\t}\n\treturn nil\n}\n\nfunc (x *Policy_Timeout) GetDownlinkOnly() *Second {\n\tif x != nil {\n\t\treturn x.DownlinkOnly\n\t}\n\treturn nil\n}\n\ntype Policy_Stats struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tUserUplink   bool `protobuf:\"varint,1,opt,name=user_uplink,json=userUplink,proto3\" json:\"user_uplink,omitempty\"`\n\tUserDownlink bool `protobuf:\"varint,2,opt,name=user_downlink,json=userDownlink,proto3\" json:\"user_downlink,omitempty\"`\n}\n\nfunc (x *Policy_Stats) Reset() {\n\t*x = Policy_Stats{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_policy_config_proto_msgTypes[5]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Policy_Stats) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Policy_Stats) ProtoMessage() {}\n\nfunc (x *Policy_Stats) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_policy_config_proto_msgTypes[5]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Policy_Stats.ProtoReflect.Descriptor instead.\nfunc (*Policy_Stats) Descriptor() ([]byte, []int) {\n\treturn file_app_policy_config_proto_rawDescGZIP(), []int{1, 1}\n}\n\nfunc (x *Policy_Stats) GetUserUplink() bool {\n\tif x != nil {\n\t\treturn x.UserUplink\n\t}\n\treturn false\n}\n\nfunc (x *Policy_Stats) GetUserDownlink() bool {\n\tif x != nil {\n\t\treturn x.UserDownlink\n\t}\n\treturn false\n}\n\ntype Policy_Buffer struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Buffer size per connection, in bytes. -1 for unlimited buffer.\n\tConnection int32 `protobuf:\"varint,1,opt,name=connection,proto3\" json:\"connection,omitempty\"`\n}\n\nfunc (x *Policy_Buffer) Reset() {\n\t*x = Policy_Buffer{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_policy_config_proto_msgTypes[6]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Policy_Buffer) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Policy_Buffer) ProtoMessage() {}\n\nfunc (x *Policy_Buffer) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_policy_config_proto_msgTypes[6]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Policy_Buffer.ProtoReflect.Descriptor instead.\nfunc (*Policy_Buffer) Descriptor() ([]byte, []int) {\n\treturn file_app_policy_config_proto_rawDescGZIP(), []int{1, 2}\n}\n\nfunc (x *Policy_Buffer) GetConnection() int32 {\n\tif x != nil {\n\t\treturn x.Connection\n\t}\n\treturn 0\n}\n\ntype SystemPolicy_Stats struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tInboundUplink    bool `protobuf:\"varint,1,opt,name=inbound_uplink,json=inboundUplink,proto3\" json:\"inbound_uplink,omitempty\"`\n\tInboundDownlink  bool `protobuf:\"varint,2,opt,name=inbound_downlink,json=inboundDownlink,proto3\" json:\"inbound_downlink,omitempty\"`\n\tOutboundUplink   bool `protobuf:\"varint,3,opt,name=outbound_uplink,json=outboundUplink,proto3\" json:\"outbound_uplink,omitempty\"`\n\tOutboundDownlink bool `protobuf:\"varint,4,opt,name=outbound_downlink,json=outboundDownlink,proto3\" json:\"outbound_downlink,omitempty\"`\n}\n\nfunc (x *SystemPolicy_Stats) Reset() {\n\t*x = SystemPolicy_Stats{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_policy_config_proto_msgTypes[7]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *SystemPolicy_Stats) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SystemPolicy_Stats) ProtoMessage() {}\n\nfunc (x *SystemPolicy_Stats) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_policy_config_proto_msgTypes[7]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SystemPolicy_Stats.ProtoReflect.Descriptor instead.\nfunc (*SystemPolicy_Stats) Descriptor() ([]byte, []int) {\n\treturn file_app_policy_config_proto_rawDescGZIP(), []int{2, 0}\n}\n\nfunc (x *SystemPolicy_Stats) GetInboundUplink() bool {\n\tif x != nil {\n\t\treturn x.InboundUplink\n\t}\n\treturn false\n}\n\nfunc (x *SystemPolicy_Stats) GetInboundDownlink() bool {\n\tif x != nil {\n\t\treturn x.InboundDownlink\n\t}\n\treturn false\n}\n\nfunc (x *SystemPolicy_Stats) GetOutboundUplink() bool {\n\tif x != nil {\n\t\treturn x.OutboundUplink\n\t}\n\treturn false\n}\n\nfunc (x *SystemPolicy_Stats) GetOutboundDownlink() bool {\n\tif x != nil {\n\t\treturn x.OutboundDownlink\n\t}\n\treturn false\n}\n\nvar File_app_policy_config_proto protoreflect.FileDescriptor\n\nvar file_app_policy_config_proto_rawDesc = []byte{\n\t0x0a, 0x17, 0x61, 0x70, 0x70, 0x2f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2f, 0x63, 0x6f, 0x6e,\n\t0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x15, 0x76, 0x32, 0x72, 0x61, 0x79,\n\t0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79,\n\t0x22, 0x1e, 0x0a, 0x06, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61,\n\t0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,\n\t0x22, 0xd0, 0x04, 0x0a, 0x06, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x3f, 0x0a, 0x07, 0x74,\n\t0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x76,\n\t0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x6f,\n\t0x6c, 0x69, 0x63, 0x79, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x54, 0x69, 0x6d, 0x65,\n\t0x6f, 0x75, 0x74, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x39, 0x0a, 0x05,\n\t0x73, 0x74, 0x61, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x76, 0x32,\n\t0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x6f, 0x6c,\n\t0x69, 0x63, 0x79, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x73,\n\t0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x73, 0x12, 0x3c, 0x0a, 0x06, 0x62, 0x75, 0x66, 0x66, 0x65,\n\t0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,\n\t0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e,\n\t0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x52, 0x06, 0x62,\n\t0x75, 0x66, 0x66, 0x65, 0x72, 0x1a, 0x92, 0x02, 0x0a, 0x07, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75,\n\t0x74, 0x12, 0x3b, 0x0a, 0x09, 0x68, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x18, 0x01,\n\t0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72,\n\t0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x53, 0x65, 0x63,\n\t0x6f, 0x6e, 0x64, 0x52, 0x09, 0x68, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x12, 0x46,\n\t0x0a, 0x0f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x6c,\n\t0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,\n\t0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e,\n\t0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x52, 0x0e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69,\n\t0x6f, 0x6e, 0x49, 0x64, 0x6c, 0x65, 0x12, 0x3e, 0x0a, 0x0b, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b,\n\t0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x76, 0x32,\n\t0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x6f, 0x6c,\n\t0x69, 0x63, 0x79, 0x2e, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x52, 0x0a, 0x75, 0x70, 0x6c, 0x69,\n\t0x6e, 0x6b, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x42, 0x0a, 0x0d, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69,\n\t0x6e, 0x6b, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e,\n\t0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70,\n\t0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x52, 0x0c, 0x64, 0x6f,\n\t0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x4f, 0x6e, 0x6c, 0x79, 0x1a, 0x4d, 0x0a, 0x05, 0x53, 0x74,\n\t0x61, 0x74, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x75, 0x70, 0x6c, 0x69,\n\t0x6e, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x55, 0x70,\n\t0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x23, 0x0a, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x64, 0x6f, 0x77,\n\t0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x75, 0x73, 0x65,\n\t0x72, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x1a, 0x28, 0x0a, 0x06, 0x42, 0x75, 0x66,\n\t0x66, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f,\n\t0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74,\n\t0x69, 0x6f, 0x6e, 0x22, 0x81, 0x02, 0x0a, 0x0c, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x50, 0x6f,\n\t0x6c, 0x69, 0x63, 0x79, 0x12, 0x3f, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x73, 0x18, 0x01, 0x20,\n\t0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,\n\t0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x53, 0x79, 0x73, 0x74,\n\t0x65, 0x6d, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x05,\n\t0x73, 0x74, 0x61, 0x74, 0x73, 0x1a, 0xaf, 0x01, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12,\n\t0x25, 0x0a, 0x0e, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x75, 0x70, 0x6c, 0x69, 0x6e,\n\t0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64,\n\t0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x29, 0x0a, 0x10, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e,\n\t0x64, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08,\n\t0x52, 0x0f, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e,\n\t0x6b, 0x12, 0x27, 0x0a, 0x0f, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x75, 0x70,\n\t0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x6f, 0x75, 0x74, 0x62,\n\t0x6f, 0x75, 0x6e, 0x64, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x2b, 0x0a, 0x11, 0x6f, 0x75,\n\t0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x18,\n\t0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x44,\n\t0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x22, 0xde, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66,\n\t0x69, 0x67, 0x12, 0x3e, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x03, 0x28,\n\t0x0b, 0x32, 0x28, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61,\n\t0x70, 0x70, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,\n\t0x2e, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x6c, 0x65, 0x76,\n\t0x65, 0x6c, 0x12, 0x3b, 0x0a, 0x06, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x18, 0x02, 0x20, 0x01,\n\t0x28, 0x0b, 0x32, 0x23, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,\n\t0x61, 0x70, 0x70, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x53, 0x79, 0x73, 0x74, 0x65,\n\t0x6d, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x06, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x1a,\n\t0x57, 0x0a, 0x0a, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a,\n\t0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12,\n\t0x33, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d,\n\t0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e,\n\t0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x05, 0x76,\n\t0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x50, 0x0a, 0x19, 0x63, 0x6f, 0x6d, 0x2e,\n\t0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70,\n\t0x6f, 0x6c, 0x69, 0x63, 0x79, 0x50, 0x01, 0x5a, 0x19, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,\n\t0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x70, 0x6f, 0x6c, 0x69,\n\t0x63, 0x79, 0xaa, 0x02, 0x15, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e,\n\t0x41, 0x70, 0x70, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,\n\t0x6f, 0x33,\n}\n\nvar (\n\tfile_app_policy_config_proto_rawDescOnce sync.Once\n\tfile_app_policy_config_proto_rawDescData = file_app_policy_config_proto_rawDesc\n)\n\nfunc file_app_policy_config_proto_rawDescGZIP() []byte {\n\tfile_app_policy_config_proto_rawDescOnce.Do(func() {\n\t\tfile_app_policy_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_policy_config_proto_rawDescData)\n\t})\n\treturn file_app_policy_config_proto_rawDescData\n}\n\nvar file_app_policy_config_proto_msgTypes = make([]protoimpl.MessageInfo, 9)\nvar file_app_policy_config_proto_goTypes = []interface{}{\n\t(*Second)(nil),             // 0: v2ray.core.app.policy.Second\n\t(*Policy)(nil),             // 1: v2ray.core.app.policy.Policy\n\t(*SystemPolicy)(nil),       // 2: v2ray.core.app.policy.SystemPolicy\n\t(*Config)(nil),             // 3: v2ray.core.app.policy.Config\n\t(*Policy_Timeout)(nil),     // 4: v2ray.core.app.policy.Policy.Timeout\n\t(*Policy_Stats)(nil),       // 5: v2ray.core.app.policy.Policy.Stats\n\t(*Policy_Buffer)(nil),      // 6: v2ray.core.app.policy.Policy.Buffer\n\t(*SystemPolicy_Stats)(nil), // 7: v2ray.core.app.policy.SystemPolicy.Stats\n\tnil,                        // 8: v2ray.core.app.policy.Config.LevelEntry\n}\nvar file_app_policy_config_proto_depIdxs = []int32{\n\t4,  // 0: v2ray.core.app.policy.Policy.timeout:type_name -> v2ray.core.app.policy.Policy.Timeout\n\t5,  // 1: v2ray.core.app.policy.Policy.stats:type_name -> v2ray.core.app.policy.Policy.Stats\n\t6,  // 2: v2ray.core.app.policy.Policy.buffer:type_name -> v2ray.core.app.policy.Policy.Buffer\n\t7,  // 3: v2ray.core.app.policy.SystemPolicy.stats:type_name -> v2ray.core.app.policy.SystemPolicy.Stats\n\t8,  // 4: v2ray.core.app.policy.Config.level:type_name -> v2ray.core.app.policy.Config.LevelEntry\n\t2,  // 5: v2ray.core.app.policy.Config.system:type_name -> v2ray.core.app.policy.SystemPolicy\n\t0,  // 6: v2ray.core.app.policy.Policy.Timeout.handshake:type_name -> v2ray.core.app.policy.Second\n\t0,  // 7: v2ray.core.app.policy.Policy.Timeout.connection_idle:type_name -> v2ray.core.app.policy.Second\n\t0,  // 8: v2ray.core.app.policy.Policy.Timeout.uplink_only:type_name -> v2ray.core.app.policy.Second\n\t0,  // 9: v2ray.core.app.policy.Policy.Timeout.downlink_only:type_name -> v2ray.core.app.policy.Second\n\t1,  // 10: v2ray.core.app.policy.Config.LevelEntry.value:type_name -> v2ray.core.app.policy.Policy\n\t11, // [11:11] is the sub-list for method output_type\n\t11, // [11:11] is the sub-list for method input_type\n\t11, // [11:11] is the sub-list for extension type_name\n\t11, // [11:11] is the sub-list for extension extendee\n\t0,  // [0:11] is the sub-list for field type_name\n}\n\nfunc init() { file_app_policy_config_proto_init() }\nfunc file_app_policy_config_proto_init() {\n\tif File_app_policy_config_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_app_policy_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Second); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_policy_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Policy); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_policy_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*SystemPolicy); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_policy_config_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Config); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_policy_config_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Policy_Timeout); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_policy_config_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Policy_Stats); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_policy_config_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Policy_Buffer); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_policy_config_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*SystemPolicy_Stats); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_app_policy_config_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   9,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_app_policy_config_proto_goTypes,\n\t\tDependencyIndexes: file_app_policy_config_proto_depIdxs,\n\t\tMessageInfos:      file_app_policy_config_proto_msgTypes,\n\t}.Build()\n\tFile_app_policy_config_proto = out.File\n\tfile_app_policy_config_proto_rawDesc = nil\n\tfile_app_policy_config_proto_goTypes = nil\n\tfile_app_policy_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "app/policy/config.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.app.policy;\noption csharp_namespace = \"V2Ray.Core.App.Policy\";\noption go_package = \"v2ray.com/core/app/policy\";\noption java_package = \"com.v2ray.core.app.policy\";\noption java_multiple_files = true;\n\nmessage Second {\n  uint32 value = 1;\n}\n\nmessage Policy {\n  // Timeout is a message for timeout settings in various stages, in seconds.\n  message Timeout {\n    Second handshake = 1;\n    Second connection_idle = 2;\n    Second uplink_only = 3;\n    Second downlink_only = 4;\n  }\n\n  message Stats {\n    bool user_uplink = 1;\n    bool user_downlink = 2;\n  }\n\n  message Buffer {\n    // Buffer size per connection, in bytes. -1 for unlimited buffer.\n    int32 connection = 1;\n  }\n\n  Timeout timeout = 1;\n  Stats stats = 2;\n  Buffer buffer = 3;\n}\n\nmessage SystemPolicy {\n  message Stats {\n    bool inbound_uplink = 1;\n    bool inbound_downlink = 2;\n    bool outbound_uplink = 3;\n    bool outbound_downlink = 4;\n  }\n\n  Stats stats = 1;\n}\n\nmessage Config {\n  map<uint32, Policy> level = 1;\n  SystemPolicy system = 2;\n}\n"
  },
  {
    "path": "app/policy/errors.generated.go",
    "content": "package policy\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "app/policy/manager.go",
    "content": "package policy\n\nimport (\n\t\"context\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/features/policy\"\n)\n\n// Instance is an instance of Policy manager.\ntype Instance struct {\n\tlevels map[uint32]*Policy\n\tsystem *SystemPolicy\n}\n\n// New creates new Policy manager instance.\nfunc New(ctx context.Context, config *Config) (*Instance, error) {\n\tm := &Instance{\n\t\tlevels: make(map[uint32]*Policy),\n\t\tsystem: config.System,\n\t}\n\tif len(config.Level) > 0 {\n\t\tfor lv, p := range config.Level {\n\t\t\tpp := defaultPolicy()\n\t\t\tpp.overrideWith(p)\n\t\t\tm.levels[lv] = pp\n\t\t}\n\t}\n\n\treturn m, nil\n}\n\n// Type implements common.HasType.\nfunc (*Instance) Type() interface{} {\n\treturn policy.ManagerType()\n}\n\n// ForLevel implements policy.Manager.\nfunc (m *Instance) ForLevel(level uint32) policy.Session {\n\tif p, ok := m.levels[level]; ok {\n\t\treturn p.ToCorePolicy()\n\t}\n\treturn policy.SessionDefault()\n}\n\n// ForSystem implements policy.Manager.\nfunc (m *Instance) ForSystem() policy.System {\n\tif m.system == nil {\n\t\treturn policy.System{}\n\t}\n\treturn m.system.ToCorePolicy()\n}\n\n// Start implements common.Runnable.Start().\nfunc (m *Instance) Start() error {\n\treturn nil\n}\n\n// Close implements common.Closable.Close().\nfunc (m *Instance) Close() error {\n\treturn nil\n}\n\nfunc init() {\n\tcommon.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {\n\t\treturn New(ctx, config.(*Config))\n\t}))\n}\n"
  },
  {
    "path": "app/policy/manager_test.go",
    "content": "package policy_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t. \"v2ray.com/core/app/policy\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/features/policy\"\n)\n\nfunc TestPolicy(t *testing.T) {\n\tmanager, err := New(context.Background(), &Config{\n\t\tLevel: map[uint32]*Policy{\n\t\t\t0: {\n\t\t\t\tTimeout: &Policy_Timeout{\n\t\t\t\t\tHandshake: &Second{\n\t\t\t\t\t\tValue: 2,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t})\n\tcommon.Must(err)\n\n\tpDefault := policy.SessionDefault()\n\n\t{\n\t\tp := manager.ForLevel(0)\n\t\tif p.Timeouts.Handshake != 2*time.Second {\n\t\t\tt.Error(\"expect 2 sec timeout, but got \", p.Timeouts.Handshake)\n\t\t}\n\t\tif p.Timeouts.ConnectionIdle != pDefault.Timeouts.ConnectionIdle {\n\t\t\tt.Error(\"expect \", pDefault.Timeouts.ConnectionIdle, \" sec timeout, but got \", p.Timeouts.ConnectionIdle)\n\t\t}\n\t}\n\n\t{\n\t\tp := manager.ForLevel(1)\n\t\tif p.Timeouts.Handshake != pDefault.Timeouts.Handshake {\n\t\t\tt.Error(\"expect \", pDefault.Timeouts.Handshake, \" sec timeout, but got \", p.Timeouts.Handshake)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "app/policy/policy.go",
    "content": "// Package policy is an implementation of policy.Manager feature.\npackage policy\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n"
  },
  {
    "path": "app/proxyman/command/command.go",
    "content": "// +build !confonly\n\npackage command\n\nimport (\n\t\"context\"\n\n\tgrpc \"google.golang.org/grpc\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/features/inbound\"\n\t\"v2ray.com/core/features/outbound\"\n\t\"v2ray.com/core/proxy\"\n)\n\n// InboundOperation is the interface for operations that applies to inbound handlers.\ntype InboundOperation interface {\n\t// ApplyInbound applies this operation to the given inbound handler.\n\tApplyInbound(context.Context, inbound.Handler) error\n}\n\n// OutboundOperation is the interface for operations that applies to outbound handlers.\ntype OutboundOperation interface {\n\t// ApplyOutbound applies this operation to the given outbound handler.\n\tApplyOutbound(context.Context, outbound.Handler) error\n}\n\nfunc getInbound(handler inbound.Handler) (proxy.Inbound, error) {\n\tgi, ok := handler.(proxy.GetInbound)\n\tif !ok {\n\t\treturn nil, newError(\"can't get inbound proxy from handler.\")\n\t}\n\treturn gi.GetInbound(), nil\n}\n\n// ApplyInbound implements InboundOperation.\nfunc (op *AddUserOperation) ApplyInbound(ctx context.Context, handler inbound.Handler) error {\n\tp, err := getInbound(handler)\n\tif err != nil {\n\t\treturn err\n\t}\n\tum, ok := p.(proxy.UserManager)\n\tif !ok {\n\t\treturn newError(\"proxy is not a UserManager\")\n\t}\n\tmUser, err := op.User.ToMemoryUser()\n\tif err != nil {\n\t\treturn newError(\"failed to parse user\").Base(err)\n\t}\n\treturn um.AddUser(ctx, mUser)\n}\n\n// ApplyInbound implements InboundOperation.\nfunc (op *RemoveUserOperation) ApplyInbound(ctx context.Context, handler inbound.Handler) error {\n\tp, err := getInbound(handler)\n\tif err != nil {\n\t\treturn err\n\t}\n\tum, ok := p.(proxy.UserManager)\n\tif !ok {\n\t\treturn newError(\"proxy is not a UserManager\")\n\t}\n\treturn um.RemoveUser(ctx, op.Email)\n}\n\ntype handlerServer struct {\n\ts   *core.Instance\n\tihm inbound.Manager\n\tohm outbound.Manager\n}\n\nfunc (s *handlerServer) AddInbound(ctx context.Context, request *AddInboundRequest) (*AddInboundResponse, error) {\n\tif err := core.AddInboundHandler(s.s, request.Inbound); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &AddInboundResponse{}, nil\n}\n\nfunc (s *handlerServer) RemoveInbound(ctx context.Context, request *RemoveInboundRequest) (*RemoveInboundResponse, error) {\n\treturn &RemoveInboundResponse{}, s.ihm.RemoveHandler(ctx, request.Tag)\n}\n\nfunc (s *handlerServer) AlterInbound(ctx context.Context, request *AlterInboundRequest) (*AlterInboundResponse, error) {\n\trawOperation, err := request.Operation.GetInstance()\n\tif err != nil {\n\t\treturn nil, newError(\"unknown operation\").Base(err)\n\t}\n\toperation, ok := rawOperation.(InboundOperation)\n\tif !ok {\n\t\treturn nil, newError(\"not an inbound operation\")\n\t}\n\n\thandler, err := s.ihm.GetHandler(ctx, request.Tag)\n\tif err != nil {\n\t\treturn nil, newError(\"failed to get handler: \", request.Tag).Base(err)\n\t}\n\n\treturn &AlterInboundResponse{}, operation.ApplyInbound(ctx, handler)\n}\n\nfunc (s *handlerServer) AddOutbound(ctx context.Context, request *AddOutboundRequest) (*AddOutboundResponse, error) {\n\tif err := core.AddOutboundHandler(s.s, request.Outbound); err != nil {\n\t\treturn nil, err\n\t}\n\treturn &AddOutboundResponse{}, nil\n}\n\nfunc (s *handlerServer) RemoveOutbound(ctx context.Context, request *RemoveOutboundRequest) (*RemoveOutboundResponse, error) {\n\treturn &RemoveOutboundResponse{}, s.ohm.RemoveHandler(ctx, request.Tag)\n}\n\nfunc (s *handlerServer) AlterOutbound(ctx context.Context, request *AlterOutboundRequest) (*AlterOutboundResponse, error) {\n\trawOperation, err := request.Operation.GetInstance()\n\tif err != nil {\n\t\treturn nil, newError(\"unknown operation\").Base(err)\n\t}\n\toperation, ok := rawOperation.(OutboundOperation)\n\tif !ok {\n\t\treturn nil, newError(\"not an outbound operation\")\n\t}\n\n\thandler := s.ohm.GetHandler(request.Tag)\n\treturn &AlterOutboundResponse{}, operation.ApplyOutbound(ctx, handler)\n}\n\nfunc (s *handlerServer) mustEmbedUnimplementedHandlerServiceServer() {}\n\ntype service struct {\n\tv *core.Instance\n}\n\nfunc (s *service) Register(server *grpc.Server) {\n\ths := &handlerServer{\n\t\ts: s.v,\n\t}\n\tcommon.Must(s.v.RequireFeatures(func(im inbound.Manager, om outbound.Manager) {\n\t\ths.ihm = im\n\t\ths.ohm = om\n\t}))\n\tRegisterHandlerServiceServer(server, hs)\n}\n\nfunc init() {\n\tcommon.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, cfg interface{}) (interface{}, error) {\n\t\ts := core.MustFromContext(ctx)\n\t\treturn &service{v: s}, nil\n\t}))\n}\n"
  },
  {
    "path": "app/proxyman/command/command.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: app/proxyman/command/command.proto\n\npackage command\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n\tcore \"v2ray.com/core\"\n\tprotocol \"v2ray.com/core/common/protocol\"\n\tserial \"v2ray.com/core/common/serial\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype AddUserOperation struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tUser *protocol.User `protobuf:\"bytes,1,opt,name=user,proto3\" json:\"user,omitempty\"`\n}\n\nfunc (x *AddUserOperation) Reset() {\n\t*x = AddUserOperation{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_proxyman_command_command_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *AddUserOperation) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AddUserOperation) ProtoMessage() {}\n\nfunc (x *AddUserOperation) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_proxyman_command_command_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AddUserOperation.ProtoReflect.Descriptor instead.\nfunc (*AddUserOperation) Descriptor() ([]byte, []int) {\n\treturn file_app_proxyman_command_command_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *AddUserOperation) GetUser() *protocol.User {\n\tif x != nil {\n\t\treturn x.User\n\t}\n\treturn nil\n}\n\ntype RemoveUserOperation struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tEmail string `protobuf:\"bytes,1,opt,name=email,proto3\" json:\"email,omitempty\"`\n}\n\nfunc (x *RemoveUserOperation) Reset() {\n\t*x = RemoveUserOperation{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_proxyman_command_command_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *RemoveUserOperation) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RemoveUserOperation) ProtoMessage() {}\n\nfunc (x *RemoveUserOperation) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_proxyman_command_command_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RemoveUserOperation.ProtoReflect.Descriptor instead.\nfunc (*RemoveUserOperation) Descriptor() ([]byte, []int) {\n\treturn file_app_proxyman_command_command_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *RemoveUserOperation) GetEmail() string {\n\tif x != nil {\n\t\treturn x.Email\n\t}\n\treturn \"\"\n}\n\ntype AddInboundRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tInbound *core.InboundHandlerConfig `protobuf:\"bytes,1,opt,name=inbound,proto3\" json:\"inbound,omitempty\"`\n}\n\nfunc (x *AddInboundRequest) Reset() {\n\t*x = AddInboundRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_proxyman_command_command_proto_msgTypes[2]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *AddInboundRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AddInboundRequest) ProtoMessage() {}\n\nfunc (x *AddInboundRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_proxyman_command_command_proto_msgTypes[2]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AddInboundRequest.ProtoReflect.Descriptor instead.\nfunc (*AddInboundRequest) Descriptor() ([]byte, []int) {\n\treturn file_app_proxyman_command_command_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *AddInboundRequest) GetInbound() *core.InboundHandlerConfig {\n\tif x != nil {\n\t\treturn x.Inbound\n\t}\n\treturn nil\n}\n\ntype AddInboundResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *AddInboundResponse) Reset() {\n\t*x = AddInboundResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_proxyman_command_command_proto_msgTypes[3]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *AddInboundResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AddInboundResponse) ProtoMessage() {}\n\nfunc (x *AddInboundResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_proxyman_command_command_proto_msgTypes[3]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AddInboundResponse.ProtoReflect.Descriptor instead.\nfunc (*AddInboundResponse) Descriptor() ([]byte, []int) {\n\treturn file_app_proxyman_command_command_proto_rawDescGZIP(), []int{3}\n}\n\ntype RemoveInboundRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tTag string `protobuf:\"bytes,1,opt,name=tag,proto3\" json:\"tag,omitempty\"`\n}\n\nfunc (x *RemoveInboundRequest) Reset() {\n\t*x = RemoveInboundRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_proxyman_command_command_proto_msgTypes[4]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *RemoveInboundRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RemoveInboundRequest) ProtoMessage() {}\n\nfunc (x *RemoveInboundRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_proxyman_command_command_proto_msgTypes[4]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RemoveInboundRequest.ProtoReflect.Descriptor instead.\nfunc (*RemoveInboundRequest) Descriptor() ([]byte, []int) {\n\treturn file_app_proxyman_command_command_proto_rawDescGZIP(), []int{4}\n}\n\nfunc (x *RemoveInboundRequest) GetTag() string {\n\tif x != nil {\n\t\treturn x.Tag\n\t}\n\treturn \"\"\n}\n\ntype RemoveInboundResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *RemoveInboundResponse) Reset() {\n\t*x = RemoveInboundResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_proxyman_command_command_proto_msgTypes[5]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *RemoveInboundResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RemoveInboundResponse) ProtoMessage() {}\n\nfunc (x *RemoveInboundResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_proxyman_command_command_proto_msgTypes[5]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RemoveInboundResponse.ProtoReflect.Descriptor instead.\nfunc (*RemoveInboundResponse) Descriptor() ([]byte, []int) {\n\treturn file_app_proxyman_command_command_proto_rawDescGZIP(), []int{5}\n}\n\ntype AlterInboundRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tTag       string               `protobuf:\"bytes,1,opt,name=tag,proto3\" json:\"tag,omitempty\"`\n\tOperation *serial.TypedMessage `protobuf:\"bytes,2,opt,name=operation,proto3\" json:\"operation,omitempty\"`\n}\n\nfunc (x *AlterInboundRequest) Reset() {\n\t*x = AlterInboundRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_proxyman_command_command_proto_msgTypes[6]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *AlterInboundRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AlterInboundRequest) ProtoMessage() {}\n\nfunc (x *AlterInboundRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_proxyman_command_command_proto_msgTypes[6]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AlterInboundRequest.ProtoReflect.Descriptor instead.\nfunc (*AlterInboundRequest) Descriptor() ([]byte, []int) {\n\treturn file_app_proxyman_command_command_proto_rawDescGZIP(), []int{6}\n}\n\nfunc (x *AlterInboundRequest) GetTag() string {\n\tif x != nil {\n\t\treturn x.Tag\n\t}\n\treturn \"\"\n}\n\nfunc (x *AlterInboundRequest) GetOperation() *serial.TypedMessage {\n\tif x != nil {\n\t\treturn x.Operation\n\t}\n\treturn nil\n}\n\ntype AlterInboundResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *AlterInboundResponse) Reset() {\n\t*x = AlterInboundResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_proxyman_command_command_proto_msgTypes[7]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *AlterInboundResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AlterInboundResponse) ProtoMessage() {}\n\nfunc (x *AlterInboundResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_proxyman_command_command_proto_msgTypes[7]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AlterInboundResponse.ProtoReflect.Descriptor instead.\nfunc (*AlterInboundResponse) Descriptor() ([]byte, []int) {\n\treturn file_app_proxyman_command_command_proto_rawDescGZIP(), []int{7}\n}\n\ntype AddOutboundRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tOutbound *core.OutboundHandlerConfig `protobuf:\"bytes,1,opt,name=outbound,proto3\" json:\"outbound,omitempty\"`\n}\n\nfunc (x *AddOutboundRequest) Reset() {\n\t*x = AddOutboundRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_proxyman_command_command_proto_msgTypes[8]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *AddOutboundRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AddOutboundRequest) ProtoMessage() {}\n\nfunc (x *AddOutboundRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_proxyman_command_command_proto_msgTypes[8]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AddOutboundRequest.ProtoReflect.Descriptor instead.\nfunc (*AddOutboundRequest) Descriptor() ([]byte, []int) {\n\treturn file_app_proxyman_command_command_proto_rawDescGZIP(), []int{8}\n}\n\nfunc (x *AddOutboundRequest) GetOutbound() *core.OutboundHandlerConfig {\n\tif x != nil {\n\t\treturn x.Outbound\n\t}\n\treturn nil\n}\n\ntype AddOutboundResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *AddOutboundResponse) Reset() {\n\t*x = AddOutboundResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_proxyman_command_command_proto_msgTypes[9]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *AddOutboundResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AddOutboundResponse) ProtoMessage() {}\n\nfunc (x *AddOutboundResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_proxyman_command_command_proto_msgTypes[9]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AddOutboundResponse.ProtoReflect.Descriptor instead.\nfunc (*AddOutboundResponse) Descriptor() ([]byte, []int) {\n\treturn file_app_proxyman_command_command_proto_rawDescGZIP(), []int{9}\n}\n\ntype RemoveOutboundRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tTag string `protobuf:\"bytes,1,opt,name=tag,proto3\" json:\"tag,omitempty\"`\n}\n\nfunc (x *RemoveOutboundRequest) Reset() {\n\t*x = RemoveOutboundRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_proxyman_command_command_proto_msgTypes[10]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *RemoveOutboundRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RemoveOutboundRequest) ProtoMessage() {}\n\nfunc (x *RemoveOutboundRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_proxyman_command_command_proto_msgTypes[10]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RemoveOutboundRequest.ProtoReflect.Descriptor instead.\nfunc (*RemoveOutboundRequest) Descriptor() ([]byte, []int) {\n\treturn file_app_proxyman_command_command_proto_rawDescGZIP(), []int{10}\n}\n\nfunc (x *RemoveOutboundRequest) GetTag() string {\n\tif x != nil {\n\t\treturn x.Tag\n\t}\n\treturn \"\"\n}\n\ntype RemoveOutboundResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *RemoveOutboundResponse) Reset() {\n\t*x = RemoveOutboundResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_proxyman_command_command_proto_msgTypes[11]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *RemoveOutboundResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RemoveOutboundResponse) ProtoMessage() {}\n\nfunc (x *RemoveOutboundResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_proxyman_command_command_proto_msgTypes[11]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RemoveOutboundResponse.ProtoReflect.Descriptor instead.\nfunc (*RemoveOutboundResponse) Descriptor() ([]byte, []int) {\n\treturn file_app_proxyman_command_command_proto_rawDescGZIP(), []int{11}\n}\n\ntype AlterOutboundRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tTag       string               `protobuf:\"bytes,1,opt,name=tag,proto3\" json:\"tag,omitempty\"`\n\tOperation *serial.TypedMessage `protobuf:\"bytes,2,opt,name=operation,proto3\" json:\"operation,omitempty\"`\n}\n\nfunc (x *AlterOutboundRequest) Reset() {\n\t*x = AlterOutboundRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_proxyman_command_command_proto_msgTypes[12]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *AlterOutboundRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AlterOutboundRequest) ProtoMessage() {}\n\nfunc (x *AlterOutboundRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_proxyman_command_command_proto_msgTypes[12]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AlterOutboundRequest.ProtoReflect.Descriptor instead.\nfunc (*AlterOutboundRequest) Descriptor() ([]byte, []int) {\n\treturn file_app_proxyman_command_command_proto_rawDescGZIP(), []int{12}\n}\n\nfunc (x *AlterOutboundRequest) GetTag() string {\n\tif x != nil {\n\t\treturn x.Tag\n\t}\n\treturn \"\"\n}\n\nfunc (x *AlterOutboundRequest) GetOperation() *serial.TypedMessage {\n\tif x != nil {\n\t\treturn x.Operation\n\t}\n\treturn nil\n}\n\ntype AlterOutboundResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *AlterOutboundResponse) Reset() {\n\t*x = AlterOutboundResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_proxyman_command_command_proto_msgTypes[13]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *AlterOutboundResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AlterOutboundResponse) ProtoMessage() {}\n\nfunc (x *AlterOutboundResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_proxyman_command_command_proto_msgTypes[13]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AlterOutboundResponse.ProtoReflect.Descriptor instead.\nfunc (*AlterOutboundResponse) Descriptor() ([]byte, []int) {\n\treturn file_app_proxyman_command_command_proto_rawDescGZIP(), []int{13}\n}\n\ntype Config struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *Config) Reset() {\n\t*x = Config{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_proxyman_command_command_proto_msgTypes[14]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Config) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Config) ProtoMessage() {}\n\nfunc (x *Config) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_proxyman_command_command_proto_msgTypes[14]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Config.ProtoReflect.Descriptor instead.\nfunc (*Config) Descriptor() ([]byte, []int) {\n\treturn file_app_proxyman_command_command_proto_rawDescGZIP(), []int{14}\n}\n\nvar File_app_proxyman_command_command_proto protoreflect.FileDescriptor\n\nvar file_app_proxyman_command_command_proto_rawDesc = []byte{\n\t0x0a, 0x22, 0x61, 0x70, 0x70, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2f, 0x63,\n\t0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x70,\n\t0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1f, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,\n\t0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f,\n\t0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x1a, 0x1a, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72,\n\t0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74,\n\t0x6f, 0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c,\n\t0x2f, 0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70,\n\t0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x0c, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f,\n\t0x74, 0x6f, 0x22, 0x48, 0x0a, 0x10, 0x41, 0x64, 0x64, 0x55, 0x73, 0x65, 0x72, 0x4f, 0x70, 0x65,\n\t0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x34, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01,\n\t0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72,\n\t0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,\n\t0x6c, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x22, 0x2b, 0x0a, 0x13,\n\t0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x55, 0x73, 0x65, 0x72, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74,\n\t0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20, 0x01,\n\t0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0x4f, 0x0a, 0x11, 0x41, 0x64, 0x64,\n\t0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3a,\n\t0x0a, 0x07, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,\n\t0x20, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x49, 0x6e, 0x62,\n\t0x6f, 0x75, 0x6e, 0x64, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69,\n\t0x67, 0x52, 0x07, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x22, 0x14, 0x0a, 0x12, 0x41, 0x64,\n\t0x64, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,\n\t0x22, 0x28, 0x0a, 0x14, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e,\n\t0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18,\n\t0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x22, 0x17, 0x0a, 0x15, 0x52, 0x65,\n\t0x6d, 0x6f, 0x76, 0x65, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f,\n\t0x6e, 0x73, 0x65, 0x22, 0x6d, 0x0a, 0x13, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x62, 0x6f,\n\t0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61,\n\t0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x44, 0x0a, 0x09,\n\t0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,\n\t0x26, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d,\n\t0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64,\n\t0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69,\n\t0x6f, 0x6e, 0x22, 0x16, 0x0a, 0x14, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x62, 0x6f, 0x75,\n\t0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x53, 0x0a, 0x12, 0x41, 0x64,\n\t0x64, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,\n\t0x12, 0x3d, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01,\n\t0x28, 0x0b, 0x32, 0x21, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,\n\t0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x43,\n\t0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x22,\n\t0x15, 0x0a, 0x13, 0x41, 0x64, 0x64, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65,\n\t0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x29, 0x0a, 0x15, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65,\n\t0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,\n\t0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61,\n\t0x67, 0x22, 0x18, 0x0a, 0x16, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4f, 0x75, 0x74, 0x62, 0x6f,\n\t0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x6e, 0x0a, 0x14, 0x41,\n\t0x6c, 0x74, 0x65, 0x72, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75,\n\t0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,\n\t0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x44, 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69,\n\t0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,\n\t0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72,\n\t0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,\n\t0x52, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x17, 0x0a, 0x15, 0x41,\n\t0x6c, 0x74, 0x65, 0x72, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70,\n\t0x6f, 0x6e, 0x73, 0x65, 0x22, 0x08, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x32, 0x90,\n\t0x06, 0x0a, 0x0e, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,\n\t0x65, 0x12, 0x77, 0x0a, 0x0a, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12,\n\t0x32, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70,\n\t0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e,\n\t0x64, 0x2e, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75,\n\t0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,\n\t0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f,\n\t0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64,\n\t0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x80, 0x01, 0x0a, 0x0d, 0x52,\n\t0x65, 0x6d, 0x6f, 0x76, 0x65, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x35, 0x2e, 0x76,\n\t0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72,\n\t0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52,\n\t0x65, 0x6d, 0x6f, 0x76, 0x65, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75,\n\t0x65, 0x73, 0x74, 0x1a, 0x36, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,\n\t0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f,\n\t0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x49, 0x6e, 0x62, 0x6f,\n\t0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x7d, 0x0a,\n\t0x0c, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x34, 0x2e,\n\t0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70,\n\t0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e,\n\t0x41, 0x6c, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75,\n\t0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,\n\t0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f,\n\t0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x62, 0x6f, 0x75,\n\t0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x7a, 0x0a, 0x0b,\n\t0x41, 0x64, 0x64, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x33, 0x2e, 0x76, 0x32,\n\t0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f,\n\t0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x41, 0x64,\n\t0x64, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,\n\t0x1a, 0x34, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70,\n\t0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61,\n\t0x6e, 0x64, 0x2e, 0x41, 0x64, 0x64, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65,\n\t0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x83, 0x01, 0x0a, 0x0e, 0x52, 0x65, 0x6d,\n\t0x6f, 0x76, 0x65, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x36, 0x2e, 0x76, 0x32,\n\t0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f,\n\t0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65,\n\t0x6d, 0x6f, 0x76, 0x65, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75,\n\t0x65, 0x73, 0x74, 0x1a, 0x37, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,\n\t0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f,\n\t0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4f, 0x75, 0x74, 0x62,\n\t0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x80,\n\t0x01, 0x0a, 0x0d, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64,\n\t0x12, 0x35, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70,\n\t0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61,\n\t0x6e, 0x64, 0x2e, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64,\n\t0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x36, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,\n\t0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61,\n\t0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x4f,\n\t0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,\n\t0x00, 0x42, 0x6e, 0x0a, 0x23, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,\n\t0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e,\n\t0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x50, 0x01, 0x5a, 0x23, 0x76, 0x32, 0x72, 0x61,\n\t0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x70,\n\t0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0xaa,\n\t0x02, 0x1f, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x41, 0x70, 0x70,\n\t0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e,\n\t0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_app_proxyman_command_command_proto_rawDescOnce sync.Once\n\tfile_app_proxyman_command_command_proto_rawDescData = file_app_proxyman_command_command_proto_rawDesc\n)\n\nfunc file_app_proxyman_command_command_proto_rawDescGZIP() []byte {\n\tfile_app_proxyman_command_command_proto_rawDescOnce.Do(func() {\n\t\tfile_app_proxyman_command_command_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_proxyman_command_command_proto_rawDescData)\n\t})\n\treturn file_app_proxyman_command_command_proto_rawDescData\n}\n\nvar file_app_proxyman_command_command_proto_msgTypes = make([]protoimpl.MessageInfo, 15)\nvar file_app_proxyman_command_command_proto_goTypes = []interface{}{\n\t(*AddUserOperation)(nil),           // 0: v2ray.core.app.proxyman.command.AddUserOperation\n\t(*RemoveUserOperation)(nil),        // 1: v2ray.core.app.proxyman.command.RemoveUserOperation\n\t(*AddInboundRequest)(nil),          // 2: v2ray.core.app.proxyman.command.AddInboundRequest\n\t(*AddInboundResponse)(nil),         // 3: v2ray.core.app.proxyman.command.AddInboundResponse\n\t(*RemoveInboundRequest)(nil),       // 4: v2ray.core.app.proxyman.command.RemoveInboundRequest\n\t(*RemoveInboundResponse)(nil),      // 5: v2ray.core.app.proxyman.command.RemoveInboundResponse\n\t(*AlterInboundRequest)(nil),        // 6: v2ray.core.app.proxyman.command.AlterInboundRequest\n\t(*AlterInboundResponse)(nil),       // 7: v2ray.core.app.proxyman.command.AlterInboundResponse\n\t(*AddOutboundRequest)(nil),         // 8: v2ray.core.app.proxyman.command.AddOutboundRequest\n\t(*AddOutboundResponse)(nil),        // 9: v2ray.core.app.proxyman.command.AddOutboundResponse\n\t(*RemoveOutboundRequest)(nil),      // 10: v2ray.core.app.proxyman.command.RemoveOutboundRequest\n\t(*RemoveOutboundResponse)(nil),     // 11: v2ray.core.app.proxyman.command.RemoveOutboundResponse\n\t(*AlterOutboundRequest)(nil),       // 12: v2ray.core.app.proxyman.command.AlterOutboundRequest\n\t(*AlterOutboundResponse)(nil),      // 13: v2ray.core.app.proxyman.command.AlterOutboundResponse\n\t(*Config)(nil),                     // 14: v2ray.core.app.proxyman.command.Config\n\t(*protocol.User)(nil),              // 15: v2ray.core.common.protocol.User\n\t(*core.InboundHandlerConfig)(nil),  // 16: v2ray.core.InboundHandlerConfig\n\t(*serial.TypedMessage)(nil),        // 17: v2ray.core.common.serial.TypedMessage\n\t(*core.OutboundHandlerConfig)(nil), // 18: v2ray.core.OutboundHandlerConfig\n}\nvar file_app_proxyman_command_command_proto_depIdxs = []int32{\n\t15, // 0: v2ray.core.app.proxyman.command.AddUserOperation.user:type_name -> v2ray.core.common.protocol.User\n\t16, // 1: v2ray.core.app.proxyman.command.AddInboundRequest.inbound:type_name -> v2ray.core.InboundHandlerConfig\n\t17, // 2: v2ray.core.app.proxyman.command.AlterInboundRequest.operation:type_name -> v2ray.core.common.serial.TypedMessage\n\t18, // 3: v2ray.core.app.proxyman.command.AddOutboundRequest.outbound:type_name -> v2ray.core.OutboundHandlerConfig\n\t17, // 4: v2ray.core.app.proxyman.command.AlterOutboundRequest.operation:type_name -> v2ray.core.common.serial.TypedMessage\n\t2,  // 5: v2ray.core.app.proxyman.command.HandlerService.AddInbound:input_type -> v2ray.core.app.proxyman.command.AddInboundRequest\n\t4,  // 6: v2ray.core.app.proxyman.command.HandlerService.RemoveInbound:input_type -> v2ray.core.app.proxyman.command.RemoveInboundRequest\n\t6,  // 7: v2ray.core.app.proxyman.command.HandlerService.AlterInbound:input_type -> v2ray.core.app.proxyman.command.AlterInboundRequest\n\t8,  // 8: v2ray.core.app.proxyman.command.HandlerService.AddOutbound:input_type -> v2ray.core.app.proxyman.command.AddOutboundRequest\n\t10, // 9: v2ray.core.app.proxyman.command.HandlerService.RemoveOutbound:input_type -> v2ray.core.app.proxyman.command.RemoveOutboundRequest\n\t12, // 10: v2ray.core.app.proxyman.command.HandlerService.AlterOutbound:input_type -> v2ray.core.app.proxyman.command.AlterOutboundRequest\n\t3,  // 11: v2ray.core.app.proxyman.command.HandlerService.AddInbound:output_type -> v2ray.core.app.proxyman.command.AddInboundResponse\n\t5,  // 12: v2ray.core.app.proxyman.command.HandlerService.RemoveInbound:output_type -> v2ray.core.app.proxyman.command.RemoveInboundResponse\n\t7,  // 13: v2ray.core.app.proxyman.command.HandlerService.AlterInbound:output_type -> v2ray.core.app.proxyman.command.AlterInboundResponse\n\t9,  // 14: v2ray.core.app.proxyman.command.HandlerService.AddOutbound:output_type -> v2ray.core.app.proxyman.command.AddOutboundResponse\n\t11, // 15: v2ray.core.app.proxyman.command.HandlerService.RemoveOutbound:output_type -> v2ray.core.app.proxyman.command.RemoveOutboundResponse\n\t13, // 16: v2ray.core.app.proxyman.command.HandlerService.AlterOutbound:output_type -> v2ray.core.app.proxyman.command.AlterOutboundResponse\n\t11, // [11:17] is the sub-list for method output_type\n\t5,  // [5:11] is the sub-list for method input_type\n\t5,  // [5:5] is the sub-list for extension type_name\n\t5,  // [5:5] is the sub-list for extension extendee\n\t0,  // [0:5] is the sub-list for field type_name\n}\n\nfunc init() { file_app_proxyman_command_command_proto_init() }\nfunc file_app_proxyman_command_command_proto_init() {\n\tif File_app_proxyman_command_command_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_app_proxyman_command_command_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*AddUserOperation); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_proxyman_command_command_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*RemoveUserOperation); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_proxyman_command_command_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*AddInboundRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_proxyman_command_command_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*AddInboundResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_proxyman_command_command_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*RemoveInboundRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_proxyman_command_command_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*RemoveInboundResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_proxyman_command_command_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*AlterInboundRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_proxyman_command_command_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*AlterInboundResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_proxyman_command_command_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*AddOutboundRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_proxyman_command_command_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*AddOutboundResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_proxyman_command_command_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*RemoveOutboundRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_proxyman_command_command_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*RemoveOutboundResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_proxyman_command_command_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*AlterOutboundRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_proxyman_command_command_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*AlterOutboundResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_proxyman_command_command_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Config); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_app_proxyman_command_command_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   15,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   1,\n\t\t},\n\t\tGoTypes:           file_app_proxyman_command_command_proto_goTypes,\n\t\tDependencyIndexes: file_app_proxyman_command_command_proto_depIdxs,\n\t\tMessageInfos:      file_app_proxyman_command_command_proto_msgTypes,\n\t}.Build()\n\tFile_app_proxyman_command_command_proto = out.File\n\tfile_app_proxyman_command_command_proto_rawDesc = nil\n\tfile_app_proxyman_command_command_proto_goTypes = nil\n\tfile_app_proxyman_command_command_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "app/proxyman/command/command.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.app.proxyman.command;\noption csharp_namespace = \"V2Ray.Core.App.Proxyman.Command\";\noption go_package = \"v2ray.com/core/app/proxyman/command\";\noption java_package = \"com.v2ray.core.app.proxyman.command\";\noption java_multiple_files = true;\n\nimport \"common/protocol/user.proto\";\nimport \"common/serial/typed_message.proto\";\nimport \"config.proto\";\n\nmessage AddUserOperation {\n  v2ray.core.common.protocol.User user = 1;\n}\n\nmessage RemoveUserOperation {\n  string email = 1;\n}\n\nmessage AddInboundRequest {\n  core.InboundHandlerConfig inbound = 1;\n}\n\nmessage AddInboundResponse {}\n\nmessage RemoveInboundRequest {\n  string tag = 1;\n}\n\nmessage RemoveInboundResponse {}\n\nmessage AlterInboundRequest {\n  string tag = 1;\n  v2ray.core.common.serial.TypedMessage operation = 2;\n}\n\nmessage AlterInboundResponse {}\n\nmessage AddOutboundRequest {\n  core.OutboundHandlerConfig outbound = 1;\n}\n\nmessage AddOutboundResponse {}\n\nmessage RemoveOutboundRequest {\n  string tag = 1;\n}\n\nmessage RemoveOutboundResponse {}\n\nmessage AlterOutboundRequest {\n  string tag = 1;\n  v2ray.core.common.serial.TypedMessage operation = 2;\n}\n\nmessage AlterOutboundResponse {}\n\nservice HandlerService {\n  rpc AddInbound(AddInboundRequest) returns (AddInboundResponse) {}\n\n  rpc RemoveInbound(RemoveInboundRequest) returns (RemoveInboundResponse) {}\n\n  rpc AlterInbound(AlterInboundRequest) returns (AlterInboundResponse) {}\n\n  rpc AddOutbound(AddOutboundRequest) returns (AddOutboundResponse) {}\n\n  rpc RemoveOutbound(RemoveOutboundRequest) returns (RemoveOutboundResponse) {}\n\n  rpc AlterOutbound(AlterOutboundRequest) returns (AlterOutboundResponse) {}\n}\n\nmessage Config {}\n"
  },
  {
    "path": "app/proxyman/command/command_grpc.pb.go",
    "content": "// Code generated by protoc-gen-go-grpc. DO NOT EDIT.\n\npackage command\n\nimport (\n\tcontext \"context\"\n\tgrpc \"google.golang.org/grpc\"\n\tcodes \"google.golang.org/grpc/codes\"\n\tstatus \"google.golang.org/grpc/status\"\n)\n\n// This is a compile-time assertion to ensure that this generated file\n// is compatible with the grpc package it is being compiled against.\nconst _ = grpc.SupportPackageIsVersion7\n\n// HandlerServiceClient is the client API for HandlerService service.\n//\n// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.\ntype HandlerServiceClient interface {\n\tAddInbound(ctx context.Context, in *AddInboundRequest, opts ...grpc.CallOption) (*AddInboundResponse, error)\n\tRemoveInbound(ctx context.Context, in *RemoveInboundRequest, opts ...grpc.CallOption) (*RemoveInboundResponse, error)\n\tAlterInbound(ctx context.Context, in *AlterInboundRequest, opts ...grpc.CallOption) (*AlterInboundResponse, error)\n\tAddOutbound(ctx context.Context, in *AddOutboundRequest, opts ...grpc.CallOption) (*AddOutboundResponse, error)\n\tRemoveOutbound(ctx context.Context, in *RemoveOutboundRequest, opts ...grpc.CallOption) (*RemoveOutboundResponse, error)\n\tAlterOutbound(ctx context.Context, in *AlterOutboundRequest, opts ...grpc.CallOption) (*AlterOutboundResponse, error)\n}\n\ntype handlerServiceClient struct {\n\tcc grpc.ClientConnInterface\n}\n\nfunc NewHandlerServiceClient(cc grpc.ClientConnInterface) HandlerServiceClient {\n\treturn &handlerServiceClient{cc}\n}\n\nfunc (c *handlerServiceClient) AddInbound(ctx context.Context, in *AddInboundRequest, opts ...grpc.CallOption) (*AddInboundResponse, error) {\n\tout := new(AddInboundResponse)\n\terr := c.cc.Invoke(ctx, \"/v2ray.core.app.proxyman.command.HandlerService/AddInbound\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *handlerServiceClient) RemoveInbound(ctx context.Context, in *RemoveInboundRequest, opts ...grpc.CallOption) (*RemoveInboundResponse, error) {\n\tout := new(RemoveInboundResponse)\n\terr := c.cc.Invoke(ctx, \"/v2ray.core.app.proxyman.command.HandlerService/RemoveInbound\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *handlerServiceClient) AlterInbound(ctx context.Context, in *AlterInboundRequest, opts ...grpc.CallOption) (*AlterInboundResponse, error) {\n\tout := new(AlterInboundResponse)\n\terr := c.cc.Invoke(ctx, \"/v2ray.core.app.proxyman.command.HandlerService/AlterInbound\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *handlerServiceClient) AddOutbound(ctx context.Context, in *AddOutboundRequest, opts ...grpc.CallOption) (*AddOutboundResponse, error) {\n\tout := new(AddOutboundResponse)\n\terr := c.cc.Invoke(ctx, \"/v2ray.core.app.proxyman.command.HandlerService/AddOutbound\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *handlerServiceClient) RemoveOutbound(ctx context.Context, in *RemoveOutboundRequest, opts ...grpc.CallOption) (*RemoveOutboundResponse, error) {\n\tout := new(RemoveOutboundResponse)\n\terr := c.cc.Invoke(ctx, \"/v2ray.core.app.proxyman.command.HandlerService/RemoveOutbound\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *handlerServiceClient) AlterOutbound(ctx context.Context, in *AlterOutboundRequest, opts ...grpc.CallOption) (*AlterOutboundResponse, error) {\n\tout := new(AlterOutboundResponse)\n\terr := c.cc.Invoke(ctx, \"/v2ray.core.app.proxyman.command.HandlerService/AlterOutbound\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\n// HandlerServiceServer is the server API for HandlerService service.\n// All implementations must embed UnimplementedHandlerServiceServer\n// for forward compatibility\ntype HandlerServiceServer interface {\n\tAddInbound(context.Context, *AddInboundRequest) (*AddInboundResponse, error)\n\tRemoveInbound(context.Context, *RemoveInboundRequest) (*RemoveInboundResponse, error)\n\tAlterInbound(context.Context, *AlterInboundRequest) (*AlterInboundResponse, error)\n\tAddOutbound(context.Context, *AddOutboundRequest) (*AddOutboundResponse, error)\n\tRemoveOutbound(context.Context, *RemoveOutboundRequest) (*RemoveOutboundResponse, error)\n\tAlterOutbound(context.Context, *AlterOutboundRequest) (*AlterOutboundResponse, error)\n\tmustEmbedUnimplementedHandlerServiceServer()\n}\n\n// UnimplementedHandlerServiceServer must be embedded to have forward compatible implementations.\ntype UnimplementedHandlerServiceServer struct {\n}\n\nfunc (UnimplementedHandlerServiceServer) AddInbound(context.Context, *AddInboundRequest) (*AddInboundResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method AddInbound not implemented\")\n}\nfunc (UnimplementedHandlerServiceServer) RemoveInbound(context.Context, *RemoveInboundRequest) (*RemoveInboundResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method RemoveInbound not implemented\")\n}\nfunc (UnimplementedHandlerServiceServer) AlterInbound(context.Context, *AlterInboundRequest) (*AlterInboundResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method AlterInbound not implemented\")\n}\nfunc (UnimplementedHandlerServiceServer) AddOutbound(context.Context, *AddOutboundRequest) (*AddOutboundResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method AddOutbound not implemented\")\n}\nfunc (UnimplementedHandlerServiceServer) RemoveOutbound(context.Context, *RemoveOutboundRequest) (*RemoveOutboundResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method RemoveOutbound not implemented\")\n}\nfunc (UnimplementedHandlerServiceServer) AlterOutbound(context.Context, *AlterOutboundRequest) (*AlterOutboundResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method AlterOutbound not implemented\")\n}\nfunc (UnimplementedHandlerServiceServer) mustEmbedUnimplementedHandlerServiceServer() {}\n\n// UnsafeHandlerServiceServer may be embedded to opt out of forward compatibility for this service.\n// Use of this interface is not recommended, as added methods to HandlerServiceServer will\n// result in compilation errors.\ntype UnsafeHandlerServiceServer interface {\n\tmustEmbedUnimplementedHandlerServiceServer()\n}\n\nfunc RegisterHandlerServiceServer(s *grpc.Server, srv HandlerServiceServer) {\n\ts.RegisterService(&_HandlerService_serviceDesc, srv)\n}\n\nfunc _HandlerService_AddInbound_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(AddInboundRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(HandlerServiceServer).AddInbound(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/v2ray.core.app.proxyman.command.HandlerService/AddInbound\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(HandlerServiceServer).AddInbound(ctx, req.(*AddInboundRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _HandlerService_RemoveInbound_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(RemoveInboundRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(HandlerServiceServer).RemoveInbound(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/v2ray.core.app.proxyman.command.HandlerService/RemoveInbound\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(HandlerServiceServer).RemoveInbound(ctx, req.(*RemoveInboundRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _HandlerService_AlterInbound_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(AlterInboundRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(HandlerServiceServer).AlterInbound(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/v2ray.core.app.proxyman.command.HandlerService/AlterInbound\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(HandlerServiceServer).AlterInbound(ctx, req.(*AlterInboundRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _HandlerService_AddOutbound_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(AddOutboundRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(HandlerServiceServer).AddOutbound(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/v2ray.core.app.proxyman.command.HandlerService/AddOutbound\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(HandlerServiceServer).AddOutbound(ctx, req.(*AddOutboundRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _HandlerService_RemoveOutbound_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(RemoveOutboundRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(HandlerServiceServer).RemoveOutbound(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/v2ray.core.app.proxyman.command.HandlerService/RemoveOutbound\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(HandlerServiceServer).RemoveOutbound(ctx, req.(*RemoveOutboundRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _HandlerService_AlterOutbound_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(AlterOutboundRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(HandlerServiceServer).AlterOutbound(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/v2ray.core.app.proxyman.command.HandlerService/AlterOutbound\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(HandlerServiceServer).AlterOutbound(ctx, req.(*AlterOutboundRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nvar _HandlerService_serviceDesc = grpc.ServiceDesc{\n\tServiceName: \"v2ray.core.app.proxyman.command.HandlerService\",\n\tHandlerType: (*HandlerServiceServer)(nil),\n\tMethods: []grpc.MethodDesc{\n\t\t{\n\t\t\tMethodName: \"AddInbound\",\n\t\t\tHandler:    _HandlerService_AddInbound_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"RemoveInbound\",\n\t\t\tHandler:    _HandlerService_RemoveInbound_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"AlterInbound\",\n\t\t\tHandler:    _HandlerService_AlterInbound_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"AddOutbound\",\n\t\t\tHandler:    _HandlerService_AddOutbound_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"RemoveOutbound\",\n\t\t\tHandler:    _HandlerService_RemoveOutbound_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"AlterOutbound\",\n\t\t\tHandler:    _HandlerService_AlterOutbound_Handler,\n\t\t},\n\t},\n\tStreams:  []grpc.StreamDesc{},\n\tMetadata: \"app/proxyman/command/command.proto\",\n}\n"
  },
  {
    "path": "app/proxyman/command/doc.go",
    "content": "package command\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n"
  },
  {
    "path": "app/proxyman/command/errors.generated.go",
    "content": "package command\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "app/proxyman/config.go",
    "content": "package proxyman\n\nfunc (s *AllocationStrategy) GetConcurrencyValue() uint32 {\n\tif s == nil || s.Concurrency == nil {\n\t\treturn 3\n\t}\n\treturn s.Concurrency.Value\n}\n\nfunc (s *AllocationStrategy) GetRefreshValue() uint32 {\n\tif s == nil || s.Refresh == nil {\n\t\treturn 5\n\t}\n\treturn s.Refresh.Value\n}\n\nfunc (c *ReceiverConfig) GetEffectiveSniffingSettings() *SniffingConfig {\n\tif c.SniffingSettings != nil {\n\t\treturn c.SniffingSettings\n\t}\n\n\tif len(c.DomainOverride) > 0 {\n\t\tvar p []string\n\t\tfor _, kd := range c.DomainOverride {\n\t\t\tswitch kd {\n\t\t\tcase KnownProtocols_HTTP:\n\t\t\t\tp = append(p, \"http\")\n\t\t\tcase KnownProtocols_TLS:\n\t\t\t\tp = append(p, \"tls\")\n\t\t\t}\n\t\t}\n\t\treturn &SniffingConfig{\n\t\t\tEnabled:             true,\n\t\t\tDestinationOverride: p,\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "app/proxyman/config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: app/proxyman/config.proto\n\npackage proxyman\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n\tnet \"v2ray.com/core/common/net\"\n\tserial \"v2ray.com/core/common/serial\"\n\tinternet \"v2ray.com/core/transport/internet\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype KnownProtocols int32\n\nconst (\n\tKnownProtocols_HTTP KnownProtocols = 0\n\tKnownProtocols_TLS  KnownProtocols = 1\n)\n\n// Enum value maps for KnownProtocols.\nvar (\n\tKnownProtocols_name = map[int32]string{\n\t\t0: \"HTTP\",\n\t\t1: \"TLS\",\n\t}\n\tKnownProtocols_value = map[string]int32{\n\t\t\"HTTP\": 0,\n\t\t\"TLS\":  1,\n\t}\n)\n\nfunc (x KnownProtocols) Enum() *KnownProtocols {\n\tp := new(KnownProtocols)\n\t*p = x\n\treturn p\n}\n\nfunc (x KnownProtocols) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (KnownProtocols) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_app_proxyman_config_proto_enumTypes[0].Descriptor()\n}\n\nfunc (KnownProtocols) Type() protoreflect.EnumType {\n\treturn &file_app_proxyman_config_proto_enumTypes[0]\n}\n\nfunc (x KnownProtocols) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use KnownProtocols.Descriptor instead.\nfunc (KnownProtocols) EnumDescriptor() ([]byte, []int) {\n\treturn file_app_proxyman_config_proto_rawDescGZIP(), []int{0}\n}\n\ntype AllocationStrategy_Type int32\n\nconst (\n\t// Always allocate all connection handlers.\n\tAllocationStrategy_Always AllocationStrategy_Type = 0\n\t// Randomly allocate specific range of handlers.\n\tAllocationStrategy_Random AllocationStrategy_Type = 1\n\t// External. Not supported yet.\n\tAllocationStrategy_External AllocationStrategy_Type = 2\n)\n\n// Enum value maps for AllocationStrategy_Type.\nvar (\n\tAllocationStrategy_Type_name = map[int32]string{\n\t\t0: \"Always\",\n\t\t1: \"Random\",\n\t\t2: \"External\",\n\t}\n\tAllocationStrategy_Type_value = map[string]int32{\n\t\t\"Always\":   0,\n\t\t\"Random\":   1,\n\t\t\"External\": 2,\n\t}\n)\n\nfunc (x AllocationStrategy_Type) Enum() *AllocationStrategy_Type {\n\tp := new(AllocationStrategy_Type)\n\t*p = x\n\treturn p\n}\n\nfunc (x AllocationStrategy_Type) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (AllocationStrategy_Type) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_app_proxyman_config_proto_enumTypes[1].Descriptor()\n}\n\nfunc (AllocationStrategy_Type) Type() protoreflect.EnumType {\n\treturn &file_app_proxyman_config_proto_enumTypes[1]\n}\n\nfunc (x AllocationStrategy_Type) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use AllocationStrategy_Type.Descriptor instead.\nfunc (AllocationStrategy_Type) EnumDescriptor() ([]byte, []int) {\n\treturn file_app_proxyman_config_proto_rawDescGZIP(), []int{1, 0}\n}\n\ntype InboundConfig struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *InboundConfig) Reset() {\n\t*x = InboundConfig{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_proxyman_config_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *InboundConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*InboundConfig) ProtoMessage() {}\n\nfunc (x *InboundConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_proxyman_config_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use InboundConfig.ProtoReflect.Descriptor instead.\nfunc (*InboundConfig) Descriptor() ([]byte, []int) {\n\treturn file_app_proxyman_config_proto_rawDescGZIP(), []int{0}\n}\n\ntype AllocationStrategy struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tType AllocationStrategy_Type `protobuf:\"varint,1,opt,name=type,proto3,enum=v2ray.core.app.proxyman.AllocationStrategy_Type\" json:\"type,omitempty\"`\n\t// Number of handlers (ports) running in parallel.\n\t// Default value is 3 if unset.\n\tConcurrency *AllocationStrategy_AllocationStrategyConcurrency `protobuf:\"bytes,2,opt,name=concurrency,proto3\" json:\"concurrency,omitempty\"`\n\t// Number of minutes before a handler is regenerated.\n\t// Default value is 5 if unset.\n\tRefresh *AllocationStrategy_AllocationStrategyRefresh `protobuf:\"bytes,3,opt,name=refresh,proto3\" json:\"refresh,omitempty\"`\n}\n\nfunc (x *AllocationStrategy) Reset() {\n\t*x = AllocationStrategy{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_proxyman_config_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *AllocationStrategy) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AllocationStrategy) ProtoMessage() {}\n\nfunc (x *AllocationStrategy) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_proxyman_config_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AllocationStrategy.ProtoReflect.Descriptor instead.\nfunc (*AllocationStrategy) Descriptor() ([]byte, []int) {\n\treturn file_app_proxyman_config_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *AllocationStrategy) GetType() AllocationStrategy_Type {\n\tif x != nil {\n\t\treturn x.Type\n\t}\n\treturn AllocationStrategy_Always\n}\n\nfunc (x *AllocationStrategy) GetConcurrency() *AllocationStrategy_AllocationStrategyConcurrency {\n\tif x != nil {\n\t\treturn x.Concurrency\n\t}\n\treturn nil\n}\n\nfunc (x *AllocationStrategy) GetRefresh() *AllocationStrategy_AllocationStrategyRefresh {\n\tif x != nil {\n\t\treturn x.Refresh\n\t}\n\treturn nil\n}\n\ntype SniffingConfig struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Whether or not to enable content sniffing on an inbound connection.\n\tEnabled bool `protobuf:\"varint,1,opt,name=enabled,proto3\" json:\"enabled,omitempty\"`\n\t// Override target destination if sniff'ed protocol is in the given list.\n\t// Supported values are \"http\", \"tls\".\n\tDestinationOverride []string `protobuf:\"bytes,2,rep,name=destination_override,json=destinationOverride,proto3\" json:\"destination_override,omitempty\"`\n}\n\nfunc (x *SniffingConfig) Reset() {\n\t*x = SniffingConfig{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_proxyman_config_proto_msgTypes[2]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *SniffingConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SniffingConfig) ProtoMessage() {}\n\nfunc (x *SniffingConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_proxyman_config_proto_msgTypes[2]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SniffingConfig.ProtoReflect.Descriptor instead.\nfunc (*SniffingConfig) Descriptor() ([]byte, []int) {\n\treturn file_app_proxyman_config_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *SniffingConfig) GetEnabled() bool {\n\tif x != nil {\n\t\treturn x.Enabled\n\t}\n\treturn false\n}\n\nfunc (x *SniffingConfig) GetDestinationOverride() []string {\n\tif x != nil {\n\t\treturn x.DestinationOverride\n\t}\n\treturn nil\n}\n\ntype ReceiverConfig struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// PortRange specifies the ports which the Receiver should listen on.\n\tPortRange *net.PortRange `protobuf:\"bytes,1,opt,name=port_range,json=portRange,proto3\" json:\"port_range,omitempty\"`\n\t// Listen specifies the IP address that the Receiver should listen on.\n\tListen                     *net.IPOrDomain        `protobuf:\"bytes,2,opt,name=listen,proto3\" json:\"listen,omitempty\"`\n\tAllocationStrategy         *AllocationStrategy    `protobuf:\"bytes,3,opt,name=allocation_strategy,json=allocationStrategy,proto3\" json:\"allocation_strategy,omitempty\"`\n\tStreamSettings             *internet.StreamConfig `protobuf:\"bytes,4,opt,name=stream_settings,json=streamSettings,proto3\" json:\"stream_settings,omitempty\"`\n\tReceiveOriginalDestination bool                   `protobuf:\"varint,5,opt,name=receive_original_destination,json=receiveOriginalDestination,proto3\" json:\"receive_original_destination,omitempty\"`\n\t// Override domains for the given protocol.\n\t// Deprecated. Use sniffing_settings.\n\t//\n\t// Deprecated: Do not use.\n\tDomainOverride   []KnownProtocols `protobuf:\"varint,7,rep,packed,name=domain_override,json=domainOverride,proto3,enum=v2ray.core.app.proxyman.KnownProtocols\" json:\"domain_override,omitempty\"`\n\tSniffingSettings *SniffingConfig  `protobuf:\"bytes,8,opt,name=sniffing_settings,json=sniffingSettings,proto3\" json:\"sniffing_settings,omitempty\"`\n}\n\nfunc (x *ReceiverConfig) Reset() {\n\t*x = ReceiverConfig{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_proxyman_config_proto_msgTypes[3]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *ReceiverConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ReceiverConfig) ProtoMessage() {}\n\nfunc (x *ReceiverConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_proxyman_config_proto_msgTypes[3]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ReceiverConfig.ProtoReflect.Descriptor instead.\nfunc (*ReceiverConfig) Descriptor() ([]byte, []int) {\n\treturn file_app_proxyman_config_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *ReceiverConfig) GetPortRange() *net.PortRange {\n\tif x != nil {\n\t\treturn x.PortRange\n\t}\n\treturn nil\n}\n\nfunc (x *ReceiverConfig) GetListen() *net.IPOrDomain {\n\tif x != nil {\n\t\treturn x.Listen\n\t}\n\treturn nil\n}\n\nfunc (x *ReceiverConfig) GetAllocationStrategy() *AllocationStrategy {\n\tif x != nil {\n\t\treturn x.AllocationStrategy\n\t}\n\treturn nil\n}\n\nfunc (x *ReceiverConfig) GetStreamSettings() *internet.StreamConfig {\n\tif x != nil {\n\t\treturn x.StreamSettings\n\t}\n\treturn nil\n}\n\nfunc (x *ReceiverConfig) GetReceiveOriginalDestination() bool {\n\tif x != nil {\n\t\treturn x.ReceiveOriginalDestination\n\t}\n\treturn false\n}\n\n// Deprecated: Do not use.\nfunc (x *ReceiverConfig) GetDomainOverride() []KnownProtocols {\n\tif x != nil {\n\t\treturn x.DomainOverride\n\t}\n\treturn nil\n}\n\nfunc (x *ReceiverConfig) GetSniffingSettings() *SniffingConfig {\n\tif x != nil {\n\t\treturn x.SniffingSettings\n\t}\n\treturn nil\n}\n\ntype InboundHandlerConfig struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tTag              string               `protobuf:\"bytes,1,opt,name=tag,proto3\" json:\"tag,omitempty\"`\n\tReceiverSettings *serial.TypedMessage `protobuf:\"bytes,2,opt,name=receiver_settings,json=receiverSettings,proto3\" json:\"receiver_settings,omitempty\"`\n\tProxySettings    *serial.TypedMessage `protobuf:\"bytes,3,opt,name=proxy_settings,json=proxySettings,proto3\" json:\"proxy_settings,omitempty\"`\n}\n\nfunc (x *InboundHandlerConfig) Reset() {\n\t*x = InboundHandlerConfig{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_proxyman_config_proto_msgTypes[4]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *InboundHandlerConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*InboundHandlerConfig) ProtoMessage() {}\n\nfunc (x *InboundHandlerConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_proxyman_config_proto_msgTypes[4]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use InboundHandlerConfig.ProtoReflect.Descriptor instead.\nfunc (*InboundHandlerConfig) Descriptor() ([]byte, []int) {\n\treturn file_app_proxyman_config_proto_rawDescGZIP(), []int{4}\n}\n\nfunc (x *InboundHandlerConfig) GetTag() string {\n\tif x != nil {\n\t\treturn x.Tag\n\t}\n\treturn \"\"\n}\n\nfunc (x *InboundHandlerConfig) GetReceiverSettings() *serial.TypedMessage {\n\tif x != nil {\n\t\treturn x.ReceiverSettings\n\t}\n\treturn nil\n}\n\nfunc (x *InboundHandlerConfig) GetProxySettings() *serial.TypedMessage {\n\tif x != nil {\n\t\treturn x.ProxySettings\n\t}\n\treturn nil\n}\n\ntype OutboundConfig struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *OutboundConfig) Reset() {\n\t*x = OutboundConfig{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_proxyman_config_proto_msgTypes[5]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *OutboundConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*OutboundConfig) ProtoMessage() {}\n\nfunc (x *OutboundConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_proxyman_config_proto_msgTypes[5]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use OutboundConfig.ProtoReflect.Descriptor instead.\nfunc (*OutboundConfig) Descriptor() ([]byte, []int) {\n\treturn file_app_proxyman_config_proto_rawDescGZIP(), []int{5}\n}\n\ntype SenderConfig struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Send traffic through the given IP. Only IP is allowed.\n\tVia               *net.IPOrDomain        `protobuf:\"bytes,1,opt,name=via,proto3\" json:\"via,omitempty\"`\n\tStreamSettings    *internet.StreamConfig `protobuf:\"bytes,2,opt,name=stream_settings,json=streamSettings,proto3\" json:\"stream_settings,omitempty\"`\n\tProxySettings     *internet.ProxyConfig  `protobuf:\"bytes,3,opt,name=proxy_settings,json=proxySettings,proto3\" json:\"proxy_settings,omitempty\"`\n\tMultiplexSettings *MultiplexingConfig    `protobuf:\"bytes,4,opt,name=multiplex_settings,json=multiplexSettings,proto3\" json:\"multiplex_settings,omitempty\"`\n}\n\nfunc (x *SenderConfig) Reset() {\n\t*x = SenderConfig{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_proxyman_config_proto_msgTypes[6]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *SenderConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SenderConfig) ProtoMessage() {}\n\nfunc (x *SenderConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_proxyman_config_proto_msgTypes[6]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SenderConfig.ProtoReflect.Descriptor instead.\nfunc (*SenderConfig) Descriptor() ([]byte, []int) {\n\treturn file_app_proxyman_config_proto_rawDescGZIP(), []int{6}\n}\n\nfunc (x *SenderConfig) GetVia() *net.IPOrDomain {\n\tif x != nil {\n\t\treturn x.Via\n\t}\n\treturn nil\n}\n\nfunc (x *SenderConfig) GetStreamSettings() *internet.StreamConfig {\n\tif x != nil {\n\t\treturn x.StreamSettings\n\t}\n\treturn nil\n}\n\nfunc (x *SenderConfig) GetProxySettings() *internet.ProxyConfig {\n\tif x != nil {\n\t\treturn x.ProxySettings\n\t}\n\treturn nil\n}\n\nfunc (x *SenderConfig) GetMultiplexSettings() *MultiplexingConfig {\n\tif x != nil {\n\t\treturn x.MultiplexSettings\n\t}\n\treturn nil\n}\n\ntype MultiplexingConfig struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Whether or not Mux is enabled.\n\tEnabled bool `protobuf:\"varint,1,opt,name=enabled,proto3\" json:\"enabled,omitempty\"`\n\t// Max number of concurrent connections that one Mux connection can handle.\n\tConcurrency uint32 `protobuf:\"varint,2,opt,name=concurrency,proto3\" json:\"concurrency,omitempty\"`\n}\n\nfunc (x *MultiplexingConfig) Reset() {\n\t*x = MultiplexingConfig{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_proxyman_config_proto_msgTypes[7]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *MultiplexingConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*MultiplexingConfig) ProtoMessage() {}\n\nfunc (x *MultiplexingConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_proxyman_config_proto_msgTypes[7]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use MultiplexingConfig.ProtoReflect.Descriptor instead.\nfunc (*MultiplexingConfig) Descriptor() ([]byte, []int) {\n\treturn file_app_proxyman_config_proto_rawDescGZIP(), []int{7}\n}\n\nfunc (x *MultiplexingConfig) GetEnabled() bool {\n\tif x != nil {\n\t\treturn x.Enabled\n\t}\n\treturn false\n}\n\nfunc (x *MultiplexingConfig) GetConcurrency() uint32 {\n\tif x != nil {\n\t\treturn x.Concurrency\n\t}\n\treturn 0\n}\n\ntype AllocationStrategy_AllocationStrategyConcurrency struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tValue uint32 `protobuf:\"varint,1,opt,name=value,proto3\" json:\"value,omitempty\"`\n}\n\nfunc (x *AllocationStrategy_AllocationStrategyConcurrency) Reset() {\n\t*x = AllocationStrategy_AllocationStrategyConcurrency{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_proxyman_config_proto_msgTypes[8]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *AllocationStrategy_AllocationStrategyConcurrency) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AllocationStrategy_AllocationStrategyConcurrency) ProtoMessage() {}\n\nfunc (x *AllocationStrategy_AllocationStrategyConcurrency) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_proxyman_config_proto_msgTypes[8]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AllocationStrategy_AllocationStrategyConcurrency.ProtoReflect.Descriptor instead.\nfunc (*AllocationStrategy_AllocationStrategyConcurrency) Descriptor() ([]byte, []int) {\n\treturn file_app_proxyman_config_proto_rawDescGZIP(), []int{1, 0}\n}\n\nfunc (x *AllocationStrategy_AllocationStrategyConcurrency) GetValue() uint32 {\n\tif x != nil {\n\t\treturn x.Value\n\t}\n\treturn 0\n}\n\ntype AllocationStrategy_AllocationStrategyRefresh struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tValue uint32 `protobuf:\"varint,1,opt,name=value,proto3\" json:\"value,omitempty\"`\n}\n\nfunc (x *AllocationStrategy_AllocationStrategyRefresh) Reset() {\n\t*x = AllocationStrategy_AllocationStrategyRefresh{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_proxyman_config_proto_msgTypes[9]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *AllocationStrategy_AllocationStrategyRefresh) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AllocationStrategy_AllocationStrategyRefresh) ProtoMessage() {}\n\nfunc (x *AllocationStrategy_AllocationStrategyRefresh) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_proxyman_config_proto_msgTypes[9]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AllocationStrategy_AllocationStrategyRefresh.ProtoReflect.Descriptor instead.\nfunc (*AllocationStrategy_AllocationStrategyRefresh) Descriptor() ([]byte, []int) {\n\treturn file_app_proxyman_config_proto_rawDescGZIP(), []int{1, 1}\n}\n\nfunc (x *AllocationStrategy_AllocationStrategyRefresh) GetValue() uint32 {\n\tif x != nil {\n\t\treturn x.Value\n\t}\n\treturn 0\n}\n\nvar File_app_proxyman_config_proto protoreflect.FileDescriptor\n\nvar file_app_proxyman_config_proto_rawDesc = []byte{\n\t0x0a, 0x19, 0x61, 0x70, 0x70, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2f, 0x63,\n\t0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x17, 0x76, 0x32, 0x72,\n\t0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78,\n\t0x79, 0x6d, 0x61, 0x6e, 0x1a, 0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74,\n\t0x2f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x15,\n\t0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x70, 0x6f, 0x72, 0x74, 0x2e,\n\t0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74,\n\t0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,\n\t0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x73,\n\t0x65, 0x72, 0x69, 0x61, 0x6c, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73,\n\t0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x0f, 0x0a, 0x0d, 0x49, 0x6e, 0x62,\n\t0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0xc0, 0x03, 0x0a, 0x12, 0x41,\n\t0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67,\n\t0x79, 0x12, 0x44, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32,\n\t0x30, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70,\n\t0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61,\n\t0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x2e, 0x54, 0x79, 0x70,\n\t0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x6b, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75,\n\t0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x49, 0x2e, 0x76,\n\t0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72,\n\t0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f,\n\t0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61,\n\t0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x43, 0x6f, 0x6e, 0x63,\n\t0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72,\n\t0x65, 0x6e, 0x63, 0x79, 0x12, 0x5f, 0x0a, 0x07, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x18,\n\t0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,\n\t0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e,\n\t0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65,\n\t0x67, 0x79, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72,\n\t0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x52, 0x07, 0x72, 0x65,\n\t0x66, 0x72, 0x65, 0x73, 0x68, 0x1a, 0x35, 0x0a, 0x1d, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74,\n\t0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x43, 0x6f, 0x6e, 0x63, 0x75,\n\t0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,\n\t0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x31, 0x0a, 0x19,\n\t0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65,\n\t0x67, 0x79, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c,\n\t0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22,\n\t0x2c, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x41, 0x6c, 0x77, 0x61, 0x79,\n\t0x73, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x10, 0x01, 0x12,\n\t0x0c, 0x0a, 0x08, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x10, 0x02, 0x22, 0x5d, 0x0a,\n\t0x0e, 0x53, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,\n\t0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08,\n\t0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x31, 0x0a, 0x14, 0x64, 0x65, 0x73,\n\t0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64,\n\t0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x13, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61,\n\t0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x22, 0xb4, 0x04, 0x0a,\n\t0x0e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,\n\t0x3f, 0x0a, 0x0a, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x01, 0x20,\n\t0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,\n\t0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x6f, 0x72, 0x74,\n\t0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65,\n\t0x12, 0x39, 0x0a, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,\n\t0x32, 0x21, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f,\n\t0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d,\n\t0x61, 0x69, 0x6e, 0x52, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x12, 0x5c, 0x0a, 0x13, 0x61,\n\t0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65,\n\t0x67, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,\n\t0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d,\n\t0x61, 0x6e, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72,\n\t0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x12, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f,\n\t0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x54, 0x0a, 0x0f, 0x73, 0x74, 0x72,\n\t0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x01,\n\t0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,\n\t0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,\n\t0x65, 0x74, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52,\n\t0x0e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12,\n\t0x40, 0x0a, 0x1c, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x5f, 0x6f, 0x72, 0x69, 0x67, 0x69,\n\t0x6e, 0x61, 0x6c, 0x5f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18,\n\t0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x4f, 0x72,\n\t0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f,\n\t0x6e, 0x12, 0x54, 0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x6f, 0x76, 0x65, 0x72,\n\t0x72, 0x69, 0x64, 0x65, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x27, 0x2e, 0x76, 0x32, 0x72,\n\t0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78,\n\t0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63,\n\t0x6f, 0x6c, 0x73, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4f,\n\t0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x54, 0x0a, 0x11, 0x73, 0x6e, 0x69, 0x66, 0x66,\n\t0x69, 0x6e, 0x67, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x08, 0x20, 0x01,\n\t0x28, 0x0b, 0x32, 0x27, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,\n\t0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x53, 0x6e, 0x69,\n\t0x66, 0x66, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x10, 0x73, 0x6e, 0x69,\n\t0x66, 0x66, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x4a, 0x04, 0x08,\n\t0x06, 0x10, 0x07, 0x22, 0xcc, 0x01, 0x0a, 0x14, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x48,\n\t0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a, 0x03,\n\t0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x53,\n\t0x0a, 0x11, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69,\n\t0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x76, 0x32, 0x72, 0x61,\n\t0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65,\n\t0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,\n\t0x65, 0x52, 0x10, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69,\n\t0x6e, 0x67, 0x73, 0x12, 0x4d, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73, 0x65, 0x74,\n\t0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x76, 0x32,\n\t0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e,\n\t0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73,\n\t0x61, 0x67, 0x65, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e,\n\t0x67, 0x73, 0x22, 0x10, 0x0a, 0x0e, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f,\n\t0x6e, 0x66, 0x69, 0x67, 0x22, 0xc8, 0x02, 0x0a, 0x0c, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x43,\n\t0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x33, 0x0a, 0x03, 0x76, 0x69, 0x61, 0x18, 0x01, 0x20, 0x01,\n\t0x28, 0x0b, 0x32, 0x21, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,\n\t0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44,\n\t0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x03, 0x76, 0x69, 0x61, 0x12, 0x54, 0x0a, 0x0f, 0x73, 0x74,\n\t0x72, 0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20,\n\t0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,\n\t0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72,\n\t0x6e, 0x65, 0x74, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,\n\t0x52, 0x0e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,\n\t0x12, 0x51, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e,\n\t0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,\n\t0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e,\n\t0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x43, 0x6f,\n\t0x6e, 0x66, 0x69, 0x67, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69,\n\t0x6e, 0x67, 0x73, 0x12, 0x5a, 0x0a, 0x12, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78,\n\t0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32,\n\t0x2b, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70,\n\t0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70,\n\t0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x11, 0x6d, 0x75,\n\t0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22,\n\t0x50, 0x0a, 0x12, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43,\n\t0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64,\n\t0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12,\n\t0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02,\n\t0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63,\n\t0x79, 0x2a, 0x23, 0x0a, 0x0e, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63,\n\t0x6f, 0x6c, 0x73, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x10, 0x00, 0x12, 0x07, 0x0a,\n\t0x03, 0x54, 0x4c, 0x53, 0x10, 0x01, 0x42, 0x56, 0x0a, 0x1b, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32,\n\t0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f,\n\t0x78, 0x79, 0x6d, 0x61, 0x6e, 0x50, 0x01, 0x5a, 0x1b, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,\n\t0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x70, 0x72, 0x6f, 0x78,\n\t0x79, 0x6d, 0x61, 0x6e, 0xaa, 0x02, 0x17, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72,\n\t0x65, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x62, 0x06,\n\t0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_app_proxyman_config_proto_rawDescOnce sync.Once\n\tfile_app_proxyman_config_proto_rawDescData = file_app_proxyman_config_proto_rawDesc\n)\n\nfunc file_app_proxyman_config_proto_rawDescGZIP() []byte {\n\tfile_app_proxyman_config_proto_rawDescOnce.Do(func() {\n\t\tfile_app_proxyman_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_proxyman_config_proto_rawDescData)\n\t})\n\treturn file_app_proxyman_config_proto_rawDescData\n}\n\nvar file_app_proxyman_config_proto_enumTypes = make([]protoimpl.EnumInfo, 2)\nvar file_app_proxyman_config_proto_msgTypes = make([]protoimpl.MessageInfo, 10)\nvar file_app_proxyman_config_proto_goTypes = []interface{}{\n\t(KnownProtocols)(0),                                      // 0: v2ray.core.app.proxyman.KnownProtocols\n\t(AllocationStrategy_Type)(0),                             // 1: v2ray.core.app.proxyman.AllocationStrategy.Type\n\t(*InboundConfig)(nil),                                    // 2: v2ray.core.app.proxyman.InboundConfig\n\t(*AllocationStrategy)(nil),                               // 3: v2ray.core.app.proxyman.AllocationStrategy\n\t(*SniffingConfig)(nil),                                   // 4: v2ray.core.app.proxyman.SniffingConfig\n\t(*ReceiverConfig)(nil),                                   // 5: v2ray.core.app.proxyman.ReceiverConfig\n\t(*InboundHandlerConfig)(nil),                             // 6: v2ray.core.app.proxyman.InboundHandlerConfig\n\t(*OutboundConfig)(nil),                                   // 7: v2ray.core.app.proxyman.OutboundConfig\n\t(*SenderConfig)(nil),                                     // 8: v2ray.core.app.proxyman.SenderConfig\n\t(*MultiplexingConfig)(nil),                               // 9: v2ray.core.app.proxyman.MultiplexingConfig\n\t(*AllocationStrategy_AllocationStrategyConcurrency)(nil), // 10: v2ray.core.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency\n\t(*AllocationStrategy_AllocationStrategyRefresh)(nil),     // 11: v2ray.core.app.proxyman.AllocationStrategy.AllocationStrategyRefresh\n\t(*net.PortRange)(nil),                                    // 12: v2ray.core.common.net.PortRange\n\t(*net.IPOrDomain)(nil),                                   // 13: v2ray.core.common.net.IPOrDomain\n\t(*internet.StreamConfig)(nil),                            // 14: v2ray.core.transport.internet.StreamConfig\n\t(*serial.TypedMessage)(nil),                              // 15: v2ray.core.common.serial.TypedMessage\n\t(*internet.ProxyConfig)(nil),                             // 16: v2ray.core.transport.internet.ProxyConfig\n}\nvar file_app_proxyman_config_proto_depIdxs = []int32{\n\t1,  // 0: v2ray.core.app.proxyman.AllocationStrategy.type:type_name -> v2ray.core.app.proxyman.AllocationStrategy.Type\n\t10, // 1: v2ray.core.app.proxyman.AllocationStrategy.concurrency:type_name -> v2ray.core.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency\n\t11, // 2: v2ray.core.app.proxyman.AllocationStrategy.refresh:type_name -> v2ray.core.app.proxyman.AllocationStrategy.AllocationStrategyRefresh\n\t12, // 3: v2ray.core.app.proxyman.ReceiverConfig.port_range:type_name -> v2ray.core.common.net.PortRange\n\t13, // 4: v2ray.core.app.proxyman.ReceiverConfig.listen:type_name -> v2ray.core.common.net.IPOrDomain\n\t3,  // 5: v2ray.core.app.proxyman.ReceiverConfig.allocation_strategy:type_name -> v2ray.core.app.proxyman.AllocationStrategy\n\t14, // 6: v2ray.core.app.proxyman.ReceiverConfig.stream_settings:type_name -> v2ray.core.transport.internet.StreamConfig\n\t0,  // 7: v2ray.core.app.proxyman.ReceiverConfig.domain_override:type_name -> v2ray.core.app.proxyman.KnownProtocols\n\t4,  // 8: v2ray.core.app.proxyman.ReceiverConfig.sniffing_settings:type_name -> v2ray.core.app.proxyman.SniffingConfig\n\t15, // 9: v2ray.core.app.proxyman.InboundHandlerConfig.receiver_settings:type_name -> v2ray.core.common.serial.TypedMessage\n\t15, // 10: v2ray.core.app.proxyman.InboundHandlerConfig.proxy_settings:type_name -> v2ray.core.common.serial.TypedMessage\n\t13, // 11: v2ray.core.app.proxyman.SenderConfig.via:type_name -> v2ray.core.common.net.IPOrDomain\n\t14, // 12: v2ray.core.app.proxyman.SenderConfig.stream_settings:type_name -> v2ray.core.transport.internet.StreamConfig\n\t16, // 13: v2ray.core.app.proxyman.SenderConfig.proxy_settings:type_name -> v2ray.core.transport.internet.ProxyConfig\n\t9,  // 14: v2ray.core.app.proxyman.SenderConfig.multiplex_settings:type_name -> v2ray.core.app.proxyman.MultiplexingConfig\n\t15, // [15:15] is the sub-list for method output_type\n\t15, // [15:15] is the sub-list for method input_type\n\t15, // [15:15] is the sub-list for extension type_name\n\t15, // [15:15] is the sub-list for extension extendee\n\t0,  // [0:15] is the sub-list for field type_name\n}\n\nfunc init() { file_app_proxyman_config_proto_init() }\nfunc file_app_proxyman_config_proto_init() {\n\tif File_app_proxyman_config_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_app_proxyman_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*InboundConfig); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_proxyman_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*AllocationStrategy); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_proxyman_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*SniffingConfig); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_proxyman_config_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*ReceiverConfig); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_proxyman_config_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*InboundHandlerConfig); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_proxyman_config_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*OutboundConfig); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_proxyman_config_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*SenderConfig); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_proxyman_config_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*MultiplexingConfig); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_proxyman_config_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*AllocationStrategy_AllocationStrategyConcurrency); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_proxyman_config_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*AllocationStrategy_AllocationStrategyRefresh); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_app_proxyman_config_proto_rawDesc,\n\t\t\tNumEnums:      2,\n\t\t\tNumMessages:   10,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_app_proxyman_config_proto_goTypes,\n\t\tDependencyIndexes: file_app_proxyman_config_proto_depIdxs,\n\t\tEnumInfos:         file_app_proxyman_config_proto_enumTypes,\n\t\tMessageInfos:      file_app_proxyman_config_proto_msgTypes,\n\t}.Build()\n\tFile_app_proxyman_config_proto = out.File\n\tfile_app_proxyman_config_proto_rawDesc = nil\n\tfile_app_proxyman_config_proto_goTypes = nil\n\tfile_app_proxyman_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "app/proxyman/config.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.app.proxyman;\noption csharp_namespace = \"V2Ray.Core.App.Proxyman\";\noption go_package = \"v2ray.com/core/app/proxyman\";\noption java_package = \"com.v2ray.core.app.proxyman\";\noption java_multiple_files = true;\n\nimport \"common/net/address.proto\";\nimport \"common/net/port.proto\";\nimport \"transport/internet/config.proto\";\nimport \"common/serial/typed_message.proto\";\n\nmessage InboundConfig {}\n\nmessage AllocationStrategy {\n  enum Type {\n    // Always allocate all connection handlers.\n    Always = 0;\n\n    // Randomly allocate specific range of handlers.\n    Random = 1;\n\n    // External. Not supported yet.\n    External = 2;\n  }\n\n  Type type = 1;\n\n  message AllocationStrategyConcurrency {\n    uint32 value = 1;\n  }\n\n  // Number of handlers (ports) running in parallel.\n  // Default value is 3 if unset.\n  AllocationStrategyConcurrency concurrency = 2;\n\n  message AllocationStrategyRefresh {\n    uint32 value = 1;\n  }\n\n  // Number of minutes before a handler is regenerated.\n  // Default value is 5 if unset.\n  AllocationStrategyRefresh refresh = 3;\n}\n\nenum KnownProtocols {\n  HTTP = 0;\n  TLS = 1;\n}\n\nmessage SniffingConfig {\n  // Whether or not to enable content sniffing on an inbound connection.\n  bool enabled = 1;\n\n  // Override target destination if sniff'ed protocol is in the given list.\n  // Supported values are \"http\", \"tls\".\n  repeated string destination_override = 2;\n}\n\nmessage ReceiverConfig {\n  // PortRange specifies the ports which the Receiver should listen on.\n  v2ray.core.common.net.PortRange port_range = 1;\n  // Listen specifies the IP address that the Receiver should listen on.\n  v2ray.core.common.net.IPOrDomain listen = 2;\n  AllocationStrategy allocation_strategy = 3;\n  v2ray.core.transport.internet.StreamConfig stream_settings = 4;\n  bool receive_original_destination = 5;\n  reserved 6;\n  // Override domains for the given protocol.\n  // Deprecated. Use sniffing_settings.\n  repeated KnownProtocols domain_override = 7 [deprecated = true];\n  SniffingConfig sniffing_settings = 8;\n}\n\nmessage InboundHandlerConfig {\n  string tag = 1;\n  v2ray.core.common.serial.TypedMessage receiver_settings = 2;\n  v2ray.core.common.serial.TypedMessage proxy_settings = 3;\n}\n\nmessage OutboundConfig {}\n\nmessage SenderConfig {\n  // Send traffic through the given IP. Only IP is allowed.\n  v2ray.core.common.net.IPOrDomain via = 1;\n  v2ray.core.transport.internet.StreamConfig stream_settings = 2;\n  v2ray.core.transport.internet.ProxyConfig proxy_settings = 3;\n  MultiplexingConfig multiplex_settings = 4;\n}\n\nmessage MultiplexingConfig {\n  // Whether or not Mux is enabled.\n  bool enabled = 1;\n  // Max number of concurrent connections that one Mux connection can handle.\n  uint32 concurrency = 2;\n}\n"
  },
  {
    "path": "app/proxyman/inbound/always.go",
    "content": "package inbound\n\nimport (\n\t\"context\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/app/proxyman\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/dice\"\n\t\"v2ray.com/core/common/errors\"\n\t\"v2ray.com/core/common/mux\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/features/policy\"\n\t\"v2ray.com/core/features/stats\"\n\t\"v2ray.com/core/proxy\"\n\t\"v2ray.com/core/transport/internet\"\n)\n\nfunc getStatCounter(v *core.Instance, tag string) (stats.Counter, stats.Counter) {\n\tvar uplinkCounter stats.Counter\n\tvar downlinkCounter stats.Counter\n\n\tpolicy := v.GetFeature(policy.ManagerType()).(policy.Manager)\n\tif len(tag) > 0 && policy.ForSystem().Stats.InboundUplink {\n\t\tstatsManager := v.GetFeature(stats.ManagerType()).(stats.Manager)\n\t\tname := \"inbound>>>\" + tag + \">>>traffic>>>uplink\"\n\t\tc, _ := stats.GetOrRegisterCounter(statsManager, name)\n\t\tif c != nil {\n\t\t\tuplinkCounter = c\n\t\t}\n\t}\n\tif len(tag) > 0 && policy.ForSystem().Stats.InboundDownlink {\n\t\tstatsManager := v.GetFeature(stats.ManagerType()).(stats.Manager)\n\t\tname := \"inbound>>>\" + tag + \">>>traffic>>>downlink\"\n\t\tc, _ := stats.GetOrRegisterCounter(statsManager, name)\n\t\tif c != nil {\n\t\t\tdownlinkCounter = c\n\t\t}\n\t}\n\n\treturn uplinkCounter, downlinkCounter\n}\n\ntype AlwaysOnInboundHandler struct {\n\tproxy   proxy.Inbound\n\tworkers []worker\n\tmux     *mux.Server\n\ttag     string\n}\n\nfunc NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *proxyman.ReceiverConfig, proxyConfig interface{}) (*AlwaysOnInboundHandler, error) {\n\trawProxy, err := common.CreateObject(ctx, proxyConfig)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tp, ok := rawProxy.(proxy.Inbound)\n\tif !ok {\n\t\treturn nil, newError(\"not an inbound proxy.\")\n\t}\n\n\th := &AlwaysOnInboundHandler{\n\t\tproxy: p,\n\t\tmux:   mux.NewServer(ctx),\n\t\ttag:   tag,\n\t}\n\n\tuplinkCounter, downlinkCounter := getStatCounter(core.MustFromContext(ctx), tag)\n\n\tnl := p.Network()\n\tpr := receiverConfig.PortRange\n\taddress := receiverConfig.Listen.AsAddress()\n\tif address == nil {\n\t\taddress = net.AnyIP\n\t}\n\n\tmss, err := internet.ToMemoryStreamConfig(receiverConfig.StreamSettings)\n\tif err != nil {\n\t\treturn nil, newError(\"failed to parse stream config\").Base(err).AtWarning()\n\t}\n\n\tif receiverConfig.ReceiveOriginalDestination {\n\t\tif mss.SocketSettings == nil {\n\t\t\tmss.SocketSettings = &internet.SocketConfig{}\n\t\t}\n\t\tif mss.SocketSettings.Tproxy == internet.SocketConfig_Off {\n\t\t\tmss.SocketSettings.Tproxy = internet.SocketConfig_Redirect\n\t\t}\n\t\tmss.SocketSettings.ReceiveOriginalDestAddress = true\n\t}\n\n\tfor port := pr.From; port <= pr.To; port++ {\n\t\tif net.HasNetwork(nl, net.Network_TCP) {\n\t\t\tnewError(\"creating stream worker on \", address, \":\", port).AtDebug().WriteToLog()\n\n\t\t\tworker := &tcpWorker{\n\t\t\t\taddress:         address,\n\t\t\t\tport:            net.Port(port),\n\t\t\t\tproxy:           p,\n\t\t\t\tstream:          mss,\n\t\t\t\trecvOrigDest:    receiverConfig.ReceiveOriginalDestination,\n\t\t\t\ttag:             tag,\n\t\t\t\tdispatcher:      h.mux,\n\t\t\t\tsniffingConfig:  receiverConfig.GetEffectiveSniffingSettings(),\n\t\t\t\tuplinkCounter:   uplinkCounter,\n\t\t\t\tdownlinkCounter: downlinkCounter,\n\t\t\t\tctx:             ctx,\n\t\t\t}\n\t\t\th.workers = append(h.workers, worker)\n\t\t}\n\n\t\tif net.HasNetwork(nl, net.Network_UDP) {\n\t\t\tworker := &udpWorker{\n\t\t\t\ttag:             tag,\n\t\t\t\tproxy:           p,\n\t\t\t\taddress:         address,\n\t\t\t\tport:            net.Port(port),\n\t\t\t\tdispatcher:      h.mux,\n\t\t\t\tuplinkCounter:   uplinkCounter,\n\t\t\t\tdownlinkCounter: downlinkCounter,\n\t\t\t\tstream:          mss,\n\t\t\t}\n\t\t\th.workers = append(h.workers, worker)\n\t\t}\n\t}\n\n\treturn h, nil\n}\n\n// Start implements common.Runnable.\nfunc (h *AlwaysOnInboundHandler) Start() error {\n\tfor _, worker := range h.workers {\n\t\tif err := worker.Start(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// Close implements common.Closable.\nfunc (h *AlwaysOnInboundHandler) Close() error {\n\tvar errs []error\n\tfor _, worker := range h.workers {\n\t\terrs = append(errs, worker.Close())\n\t}\n\terrs = append(errs, h.mux.Close())\n\tif err := errors.Combine(errs...); err != nil {\n\t\treturn newError(\"failed to close all resources\").Base(err)\n\t}\n\treturn nil\n}\n\nfunc (h *AlwaysOnInboundHandler) GetRandomInboundProxy() (interface{}, net.Port, int) {\n\tif len(h.workers) == 0 {\n\t\treturn nil, 0, 0\n\t}\n\tw := h.workers[dice.Roll(len(h.workers))]\n\treturn w.Proxy(), w.Port(), 9999\n}\n\nfunc (h *AlwaysOnInboundHandler) Tag() string {\n\treturn h.tag\n}\n\nfunc (h *AlwaysOnInboundHandler) GetInbound() proxy.Inbound {\n\treturn h.proxy\n}\n"
  },
  {
    "path": "app/proxyman/inbound/dynamic.go",
    "content": "package inbound\n\nimport (\n\t\"context\"\n\t\"sync\"\n\t\"time\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/app/proxyman\"\n\t\"v2ray.com/core/common/dice\"\n\t\"v2ray.com/core/common/mux\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/task\"\n\t\"v2ray.com/core/proxy\"\n\t\"v2ray.com/core/transport/internet\"\n)\n\ntype DynamicInboundHandler struct {\n\ttag            string\n\tv              *core.Instance\n\tproxyConfig    interface{}\n\treceiverConfig *proxyman.ReceiverConfig\n\tstreamSettings *internet.MemoryStreamConfig\n\tportMutex      sync.Mutex\n\tportsInUse     map[net.Port]bool\n\tworkerMutex    sync.RWMutex\n\tworker         []worker\n\tlastRefresh    time.Time\n\tmux            *mux.Server\n\ttask           *task.Periodic\n\n\tctx context.Context\n}\n\nfunc NewDynamicInboundHandler(ctx context.Context, tag string, receiverConfig *proxyman.ReceiverConfig, proxyConfig interface{}) (*DynamicInboundHandler, error) {\n\tv := core.MustFromContext(ctx)\n\th := &DynamicInboundHandler{\n\t\ttag:            tag,\n\t\tproxyConfig:    proxyConfig,\n\t\treceiverConfig: receiverConfig,\n\t\tportsInUse:     make(map[net.Port]bool),\n\t\tmux:            mux.NewServer(ctx),\n\t\tv:              v,\n\t\tctx:            ctx,\n\t}\n\n\tmss, err := internet.ToMemoryStreamConfig(receiverConfig.StreamSettings)\n\tif err != nil {\n\t\treturn nil, newError(\"failed to parse stream settings\").Base(err).AtWarning()\n\t}\n\tif receiverConfig.ReceiveOriginalDestination {\n\t\tif mss.SocketSettings == nil {\n\t\t\tmss.SocketSettings = &internet.SocketConfig{}\n\t\t}\n\t\tif mss.SocketSettings.Tproxy == internet.SocketConfig_Off {\n\t\t\tmss.SocketSettings.Tproxy = internet.SocketConfig_Redirect\n\t\t}\n\t\tmss.SocketSettings.ReceiveOriginalDestAddress = true\n\t}\n\n\th.streamSettings = mss\n\n\th.task = &task.Periodic{\n\t\tInterval: time.Minute * time.Duration(h.receiverConfig.AllocationStrategy.GetRefreshValue()),\n\t\tExecute:  h.refresh,\n\t}\n\n\treturn h, nil\n}\n\nfunc (h *DynamicInboundHandler) allocatePort() net.Port {\n\tfrom := int(h.receiverConfig.PortRange.From)\n\tdelta := int(h.receiverConfig.PortRange.To) - from + 1\n\n\th.portMutex.Lock()\n\tdefer h.portMutex.Unlock()\n\n\tfor {\n\t\tr := dice.Roll(delta)\n\t\tport := net.Port(from + r)\n\t\t_, used := h.portsInUse[port]\n\t\tif !used {\n\t\t\th.portsInUse[port] = true\n\t\t\treturn port\n\t\t}\n\t}\n}\n\nfunc (h *DynamicInboundHandler) closeWorkers(workers []worker) {\n\tports2Del := make([]net.Port, len(workers))\n\tfor idx, worker := range workers {\n\t\tports2Del[idx] = worker.Port()\n\t\tif err := worker.Close(); err != nil {\n\t\t\tnewError(\"failed to close worker\").Base(err).WriteToLog()\n\t\t}\n\t}\n\n\th.portMutex.Lock()\n\tfor _, port := range ports2Del {\n\t\tdelete(h.portsInUse, port)\n\t}\n\th.portMutex.Unlock()\n}\n\nfunc (h *DynamicInboundHandler) refresh() error {\n\th.lastRefresh = time.Now()\n\n\ttimeout := time.Minute * time.Duration(h.receiverConfig.AllocationStrategy.GetRefreshValue()) * 2\n\tconcurrency := h.receiverConfig.AllocationStrategy.GetConcurrencyValue()\n\tworkers := make([]worker, 0, concurrency)\n\n\taddress := h.receiverConfig.Listen.AsAddress()\n\tif address == nil {\n\t\taddress = net.AnyIP\n\t}\n\n\tuplinkCounter, downlinkCounter := getStatCounter(h.v, h.tag)\n\n\tfor i := uint32(0); i < concurrency; i++ {\n\t\tport := h.allocatePort()\n\t\trawProxy, err := core.CreateObject(h.v, h.proxyConfig)\n\t\tif err != nil {\n\t\t\tnewError(\"failed to create proxy instance\").Base(err).AtWarning().WriteToLog()\n\t\t\tcontinue\n\t\t}\n\t\tp := rawProxy.(proxy.Inbound)\n\t\tnl := p.Network()\n\t\tif net.HasNetwork(nl, net.Network_TCP) {\n\t\t\tworker := &tcpWorker{\n\t\t\t\ttag:             h.tag,\n\t\t\t\taddress:         address,\n\t\t\t\tport:            port,\n\t\t\t\tproxy:           p,\n\t\t\t\tstream:          h.streamSettings,\n\t\t\t\trecvOrigDest:    h.receiverConfig.ReceiveOriginalDestination,\n\t\t\t\tdispatcher:      h.mux,\n\t\t\t\tsniffingConfig:  h.receiverConfig.GetEffectiveSniffingSettings(),\n\t\t\t\tuplinkCounter:   uplinkCounter,\n\t\t\t\tdownlinkCounter: downlinkCounter,\n\t\t\t\tctx:             h.ctx,\n\t\t\t}\n\t\t\tif err := worker.Start(); err != nil {\n\t\t\t\tnewError(\"failed to create TCP worker\").Base(err).AtWarning().WriteToLog()\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tworkers = append(workers, worker)\n\t\t}\n\n\t\tif net.HasNetwork(nl, net.Network_UDP) {\n\t\t\tworker := &udpWorker{\n\t\t\t\ttag:             h.tag,\n\t\t\t\tproxy:           p,\n\t\t\t\taddress:         address,\n\t\t\t\tport:            port,\n\t\t\t\tdispatcher:      h.mux,\n\t\t\t\tuplinkCounter:   uplinkCounter,\n\t\t\t\tdownlinkCounter: downlinkCounter,\n\t\t\t\tstream:          h.streamSettings,\n\t\t\t}\n\t\t\tif err := worker.Start(); err != nil {\n\t\t\t\tnewError(\"failed to create UDP worker\").Base(err).AtWarning().WriteToLog()\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tworkers = append(workers, worker)\n\t\t}\n\t}\n\n\th.workerMutex.Lock()\n\th.worker = workers\n\th.workerMutex.Unlock()\n\n\ttime.AfterFunc(timeout, func() {\n\t\th.closeWorkers(workers)\n\t})\n\n\treturn nil\n}\n\nfunc (h *DynamicInboundHandler) Start() error {\n\treturn h.task.Start()\n}\n\nfunc (h *DynamicInboundHandler) Close() error {\n\treturn h.task.Close()\n}\n\nfunc (h *DynamicInboundHandler) GetRandomInboundProxy() (interface{}, net.Port, int) {\n\th.workerMutex.RLock()\n\tdefer h.workerMutex.RUnlock()\n\n\tif len(h.worker) == 0 {\n\t\treturn nil, 0, 0\n\t}\n\tw := h.worker[dice.Roll(len(h.worker))]\n\texpire := h.receiverConfig.AllocationStrategy.GetRefreshValue() - uint32(time.Since(h.lastRefresh)/time.Minute)\n\treturn w.Proxy(), w.Port(), int(expire)\n}\n\nfunc (h *DynamicInboundHandler) Tag() string {\n\treturn h.tag\n}\n"
  },
  {
    "path": "app/proxyman/inbound/errors.generated.go",
    "content": "package inbound\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "app/proxyman/inbound/inbound.go",
    "content": "package inbound\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n\nimport (\n\t\"context\"\n\t\"sync\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/app/proxyman\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/serial\"\n\t\"v2ray.com/core/common/session\"\n\t\"v2ray.com/core/features/inbound\"\n)\n\n// Manager is to manage all inbound handlers.\ntype Manager struct {\n\taccess          sync.RWMutex\n\tuntaggedHandler []inbound.Handler\n\ttaggedHandlers  map[string]inbound.Handler\n\trunning         bool\n}\n\n// New returns a new Manager for inbound handlers.\nfunc New(ctx context.Context, config *proxyman.InboundConfig) (*Manager, error) {\n\tm := &Manager{\n\t\ttaggedHandlers: make(map[string]inbound.Handler),\n\t}\n\treturn m, nil\n}\n\n// Type implements common.HasType.\nfunc (*Manager) Type() interface{} {\n\treturn inbound.ManagerType()\n}\n\n// AddHandler implements inbound.Manager.\nfunc (m *Manager) AddHandler(ctx context.Context, handler inbound.Handler) error {\n\tm.access.Lock()\n\tdefer m.access.Unlock()\n\n\ttag := handler.Tag()\n\tif len(tag) > 0 {\n\t\tm.taggedHandlers[tag] = handler\n\t} else {\n\t\tm.untaggedHandler = append(m.untaggedHandler, handler)\n\t}\n\n\tif m.running {\n\t\treturn handler.Start()\n\t}\n\n\treturn nil\n}\n\n// GetHandler implements inbound.Manager.\nfunc (m *Manager) GetHandler(ctx context.Context, tag string) (inbound.Handler, error) {\n\tm.access.RLock()\n\tdefer m.access.RUnlock()\n\n\thandler, found := m.taggedHandlers[tag]\n\tif !found {\n\t\treturn nil, newError(\"handler not found: \", tag)\n\t}\n\treturn handler, nil\n}\n\n// RemoveHandler implements inbound.Manager.\nfunc (m *Manager) RemoveHandler(ctx context.Context, tag string) error {\n\tif tag == \"\" {\n\t\treturn common.ErrNoClue\n\t}\n\n\tm.access.Lock()\n\tdefer m.access.Unlock()\n\n\tif handler, found := m.taggedHandlers[tag]; found {\n\t\tif err := handler.Close(); err != nil {\n\t\t\tnewError(\"failed to close handler \", tag).Base(err).AtWarning().WriteToLog(session.ExportIDToError(ctx))\n\t\t}\n\t\tdelete(m.taggedHandlers, tag)\n\t\treturn nil\n\t}\n\n\treturn common.ErrNoClue\n}\n\n// Start implements common.Runnable.\nfunc (m *Manager) Start() error {\n\tm.access.Lock()\n\tdefer m.access.Unlock()\n\n\tm.running = true\n\n\tfor _, handler := range m.taggedHandlers {\n\t\tif err := handler.Start(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tfor _, handler := range m.untaggedHandler {\n\t\tif err := handler.Start(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// Close implements common.Closable.\nfunc (m *Manager) Close() error {\n\tm.access.Lock()\n\tdefer m.access.Unlock()\n\n\tm.running = false\n\n\tvar errors []interface{}\n\tfor _, handler := range m.taggedHandlers {\n\t\tif err := handler.Close(); err != nil {\n\t\t\terrors = append(errors, err)\n\t\t}\n\t}\n\tfor _, handler := range m.untaggedHandler {\n\t\tif err := handler.Close(); err != nil {\n\t\t\terrors = append(errors, err)\n\t\t}\n\t}\n\n\tif len(errors) > 0 {\n\t\treturn newError(\"failed to close all handlers\").Base(newError(serial.Concat(errors...)))\n\t}\n\n\treturn nil\n}\n\n// NewHandler creates a new inbound.Handler based on the given config.\nfunc NewHandler(ctx context.Context, config *core.InboundHandlerConfig) (inbound.Handler, error) {\n\trawReceiverSettings, err := config.ReceiverSettings.GetInstance()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tproxySettings, err := config.ProxySettings.GetInstance()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\ttag := config.Tag\n\n\treceiverSettings, ok := rawReceiverSettings.(*proxyman.ReceiverConfig)\n\tif !ok {\n\t\treturn nil, newError(\"not a ReceiverConfig\").AtError()\n\t}\n\n\tstreamSettings := receiverSettings.StreamSettings\n\tif streamSettings != nil && streamSettings.SocketSettings != nil {\n\t\tctx = session.ContextWithSockopt(ctx, &session.Sockopt{\n\t\t\tMark: streamSettings.SocketSettings.Mark,\n\t\t})\n\t}\n\n\tallocStrategy := receiverSettings.AllocationStrategy\n\tif allocStrategy == nil || allocStrategy.Type == proxyman.AllocationStrategy_Always {\n\t\treturn NewAlwaysOnInboundHandler(ctx, tag, receiverSettings, proxySettings)\n\t}\n\n\tif allocStrategy.Type == proxyman.AllocationStrategy_Random {\n\t\treturn NewDynamicInboundHandler(ctx, tag, receiverSettings, proxySettings)\n\t}\n\treturn nil, newError(\"unknown allocation strategy: \", receiverSettings.AllocationStrategy.Type).AtError()\n}\n\nfunc init() {\n\tcommon.Must(common.RegisterConfig((*proxyman.InboundConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {\n\t\treturn New(ctx, config.(*proxyman.InboundConfig))\n\t}))\n\tcommon.Must(common.RegisterConfig((*core.InboundHandlerConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {\n\t\treturn NewHandler(ctx, config.(*core.InboundHandlerConfig))\n\t}))\n}\n"
  },
  {
    "path": "app/proxyman/inbound/worker.go",
    "content": "package inbound\n\nimport (\n\t\"context\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"v2ray.com/core/app/proxyman\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/serial\"\n\t\"v2ray.com/core/common/session\"\n\t\"v2ray.com/core/common/signal/done\"\n\t\"v2ray.com/core/common/task\"\n\t\"v2ray.com/core/features/routing\"\n\t\"v2ray.com/core/features/stats\"\n\t\"v2ray.com/core/proxy\"\n\t\"v2ray.com/core/transport/internet\"\n\t\"v2ray.com/core/transport/internet/tcp\"\n\t\"v2ray.com/core/transport/internet/udp\"\n\t\"v2ray.com/core/transport/pipe\"\n)\n\ntype worker interface {\n\tStart() error\n\tClose() error\n\tPort() net.Port\n\tProxy() proxy.Inbound\n}\n\ntype tcpWorker struct {\n\taddress         net.Address\n\tport            net.Port\n\tproxy           proxy.Inbound\n\tstream          *internet.MemoryStreamConfig\n\trecvOrigDest    bool\n\ttag             string\n\tdispatcher      routing.Dispatcher\n\tsniffingConfig  *proxyman.SniffingConfig\n\tuplinkCounter   stats.Counter\n\tdownlinkCounter stats.Counter\n\n\thub internet.Listener\n\n\tctx context.Context\n}\n\nfunc getTProxyType(s *internet.MemoryStreamConfig) internet.SocketConfig_TProxyMode {\n\tif s == nil || s.SocketSettings == nil {\n\t\treturn internet.SocketConfig_Off\n\t}\n\treturn s.SocketSettings.Tproxy\n}\n\nfunc (w *tcpWorker) callback(conn internet.Connection) {\n\tctx, cancel := context.WithCancel(w.ctx)\n\tsid := session.NewID()\n\tctx = session.ContextWithID(ctx, sid)\n\n\tif w.recvOrigDest {\n\t\tvar dest net.Destination\n\t\tswitch getTProxyType(w.stream) {\n\t\tcase internet.SocketConfig_Redirect:\n\t\t\td, err := tcp.GetOriginalDestination(conn)\n\t\t\tif err != nil {\n\t\t\t\tnewError(\"failed to get original destination\").Base(err).WriteToLog(session.ExportIDToError(ctx))\n\t\t\t} else {\n\t\t\t\tdest = d\n\t\t\t}\n\t\tcase internet.SocketConfig_TProxy:\n\t\t\tdest = net.DestinationFromAddr(conn.LocalAddr())\n\t\t}\n\t\tif dest.IsValid() {\n\t\t\tctx = session.ContextWithOutbound(ctx, &session.Outbound{\n\t\t\t\tTarget: dest,\n\t\t\t})\n\t\t}\n\t}\n\tctx = session.ContextWithInbound(ctx, &session.Inbound{\n\t\tSource:  net.DestinationFromAddr(conn.RemoteAddr()),\n\t\tGateway: net.TCPDestination(w.address, w.port),\n\t\tTag:     w.tag,\n\t})\n\tcontent := new(session.Content)\n\tif w.sniffingConfig != nil {\n\t\tcontent.SniffingRequest.Enabled = w.sniffingConfig.Enabled\n\t\tcontent.SniffingRequest.OverrideDestinationForProtocol = w.sniffingConfig.DestinationOverride\n\t}\n\tctx = session.ContextWithContent(ctx, content)\n\tif w.uplinkCounter != nil || w.downlinkCounter != nil {\n\t\tconn = &internet.StatCouterConnection{\n\t\t\tConnection:   conn,\n\t\t\tReadCounter:  w.uplinkCounter,\n\t\t\tWriteCounter: w.downlinkCounter,\n\t\t}\n\t}\n\tif err := w.proxy.Process(ctx, net.Network_TCP, conn, w.dispatcher); err != nil {\n\t\tnewError(\"connection ends\").Base(err).WriteToLog(session.ExportIDToError(ctx))\n\t}\n\tcancel()\n\tif err := conn.Close(); err != nil {\n\t\tnewError(\"failed to close connection\").Base(err).WriteToLog(session.ExportIDToError(ctx))\n\t}\n}\n\nfunc (w *tcpWorker) Proxy() proxy.Inbound {\n\treturn w.proxy\n}\n\nfunc (w *tcpWorker) Start() error {\n\tctx := context.Background()\n\thub, err := internet.ListenTCP(ctx, w.address, w.port, w.stream, func(conn internet.Connection) {\n\t\tgo w.callback(conn)\n\t})\n\tif err != nil {\n\t\treturn newError(\"failed to listen TCP on \", w.port).AtWarning().Base(err)\n\t}\n\tw.hub = hub\n\treturn nil\n}\n\nfunc (w *tcpWorker) Close() error {\n\tvar errors []interface{}\n\tif w.hub != nil {\n\t\tif err := common.Close(w.hub); err != nil {\n\t\t\terrors = append(errors, err)\n\t\t}\n\t\tif err := common.Close(w.proxy); err != nil {\n\t\t\terrors = append(errors, err)\n\t\t}\n\t}\n\tif len(errors) > 0 {\n\t\treturn newError(\"failed to close all resources\").Base(newError(serial.Concat(errors...)))\n\t}\n\n\treturn nil\n}\n\nfunc (w *tcpWorker) Port() net.Port {\n\treturn w.port\n}\n\ntype udpConn struct {\n\tlastActivityTime int64 // in seconds\n\treader           buf.Reader\n\twriter           buf.Writer\n\toutput           func([]byte) (int, error)\n\tremote           net.Addr\n\tlocal            net.Addr\n\tdone             *done.Instance\n\tuplink           stats.Counter\n\tdownlink         stats.Counter\n}\n\nfunc (c *udpConn) updateActivity() {\n\tatomic.StoreInt64(&c.lastActivityTime, time.Now().Unix())\n}\n\n// ReadMultiBuffer implements buf.Reader\nfunc (c *udpConn) ReadMultiBuffer() (buf.MultiBuffer, error) {\n\tmb, err := c.reader.ReadMultiBuffer()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tc.updateActivity()\n\n\tif c.uplink != nil {\n\t\tc.uplink.Add(int64(mb.Len()))\n\t}\n\n\treturn mb, nil\n}\n\nfunc (c *udpConn) Read(buf []byte) (int, error) {\n\tpanic(\"not implemented\")\n}\n\n// Write implements io.Writer.\nfunc (c *udpConn) Write(buf []byte) (int, error) {\n\tn, err := c.output(buf)\n\tif c.downlink != nil {\n\t\tc.downlink.Add(int64(n))\n\t}\n\tif err == nil {\n\t\tc.updateActivity()\n\t}\n\treturn n, err\n}\n\nfunc (c *udpConn) Close() error {\n\tcommon.Must(c.done.Close())\n\tcommon.Must(common.Close(c.writer))\n\treturn nil\n}\n\nfunc (c *udpConn) RemoteAddr() net.Addr {\n\treturn c.remote\n}\n\nfunc (c *udpConn) LocalAddr() net.Addr {\n\treturn c.local\n}\n\nfunc (*udpConn) SetDeadline(time.Time) error {\n\treturn nil\n}\n\nfunc (*udpConn) SetReadDeadline(time.Time) error {\n\treturn nil\n}\n\nfunc (*udpConn) SetWriteDeadline(time.Time) error {\n\treturn nil\n}\n\ntype connID struct {\n\tsrc  net.Destination\n\tdest net.Destination\n}\n\ntype udpWorker struct {\n\tsync.RWMutex\n\n\tproxy           proxy.Inbound\n\thub             *udp.Hub\n\taddress         net.Address\n\tport            net.Port\n\ttag             string\n\tstream          *internet.MemoryStreamConfig\n\tdispatcher      routing.Dispatcher\n\tuplinkCounter   stats.Counter\n\tdownlinkCounter stats.Counter\n\n\tchecker    *task.Periodic\n\tactiveConn map[connID]*udpConn\n}\n\nfunc (w *udpWorker) getConnection(id connID) (*udpConn, bool) {\n\tw.Lock()\n\tdefer w.Unlock()\n\n\tif conn, found := w.activeConn[id]; found && !conn.done.Done() {\n\t\treturn conn, true\n\t}\n\n\tpReader, pWriter := pipe.New(pipe.DiscardOverflow(), pipe.WithSizeLimit(16*1024))\n\tconn := &udpConn{\n\t\treader: pReader,\n\t\twriter: pWriter,\n\t\toutput: func(b []byte) (int, error) {\n\t\t\treturn w.hub.WriteTo(b, id.src)\n\t\t},\n\t\tremote: &net.UDPAddr{\n\t\t\tIP:   id.src.Address.IP(),\n\t\t\tPort: int(id.src.Port),\n\t\t},\n\t\tlocal: &net.UDPAddr{\n\t\t\tIP:   w.address.IP(),\n\t\t\tPort: int(w.port),\n\t\t},\n\t\tdone:     done.New(),\n\t\tuplink:   w.uplinkCounter,\n\t\tdownlink: w.downlinkCounter,\n\t}\n\tw.activeConn[id] = conn\n\n\tconn.updateActivity()\n\treturn conn, false\n}\n\nfunc (w *udpWorker) callback(b *buf.Buffer, source net.Destination, originalDest net.Destination) {\n\tid := connID{\n\t\tsrc: source,\n\t}\n\tif originalDest.IsValid() {\n\t\tid.dest = originalDest\n\t}\n\tconn, existing := w.getConnection(id)\n\n\t// payload will be discarded in pipe is full.\n\tconn.writer.WriteMultiBuffer(buf.MultiBuffer{b}) // nolint: errcheck\n\n\tif !existing {\n\t\tcommon.Must(w.checker.Start())\n\n\t\tgo func() {\n\t\t\tctx := context.Background()\n\t\t\tsid := session.NewID()\n\t\t\tctx = session.ContextWithID(ctx, sid)\n\n\t\t\tif originalDest.IsValid() {\n\t\t\t\tctx = session.ContextWithOutbound(ctx, &session.Outbound{\n\t\t\t\t\tTarget: originalDest,\n\t\t\t\t})\n\t\t\t}\n\t\t\tctx = session.ContextWithInbound(ctx, &session.Inbound{\n\t\t\t\tSource:  source,\n\t\t\t\tGateway: net.UDPDestination(w.address, w.port),\n\t\t\t\tTag:     w.tag,\n\t\t\t})\n\t\t\tif err := w.proxy.Process(ctx, net.Network_UDP, conn, w.dispatcher); err != nil {\n\t\t\t\tnewError(\"connection ends\").Base(err).WriteToLog(session.ExportIDToError(ctx))\n\t\t\t}\n\t\t\tconn.Close() // nolint: errcheck\n\t\t\tw.removeConn(id)\n\t\t}()\n\t}\n}\n\nfunc (w *udpWorker) removeConn(id connID) {\n\tw.Lock()\n\tdelete(w.activeConn, id)\n\tw.Unlock()\n}\n\nfunc (w *udpWorker) handlePackets() {\n\treceive := w.hub.Receive()\n\tfor payload := range receive {\n\t\tw.callback(payload.Payload, payload.Source, payload.Target)\n\t}\n}\n\nfunc (w *udpWorker) clean() error {\n\tnowSec := time.Now().Unix()\n\tw.Lock()\n\tdefer w.Unlock()\n\n\tif len(w.activeConn) == 0 {\n\t\treturn newError(\"no more connections. stopping...\")\n\t}\n\n\tfor addr, conn := range w.activeConn {\n\t\tif nowSec-atomic.LoadInt64(&conn.lastActivityTime) > 8 { //TODO Timeout too small\n\t\t\tdelete(w.activeConn, addr)\n\t\t\tconn.Close() // nolint: errcheck\n\t\t}\n\t}\n\n\tif len(w.activeConn) == 0 {\n\t\tw.activeConn = make(map[connID]*udpConn, 16)\n\t}\n\n\treturn nil\n}\n\nfunc (w *udpWorker) Start() error {\n\tw.activeConn = make(map[connID]*udpConn, 16)\n\tctx := context.Background()\n\th, err := udp.ListenUDP(ctx, w.address, w.port, w.stream, udp.HubCapacity(256))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tw.checker = &task.Periodic{\n\t\tInterval: time.Second * 16,\n\t\tExecute:  w.clean,\n\t}\n\n\tw.hub = h\n\tgo w.handlePackets()\n\treturn nil\n}\n\nfunc (w *udpWorker) Close() error {\n\tw.Lock()\n\tdefer w.Unlock()\n\n\tvar errors []interface{}\n\n\tif w.hub != nil {\n\t\tif err := w.hub.Close(); err != nil {\n\t\t\terrors = append(errors, err)\n\t\t}\n\t}\n\n\tif w.checker != nil {\n\t\tif err := w.checker.Close(); err != nil {\n\t\t\terrors = append(errors, err)\n\t\t}\n\t}\n\n\tif err := common.Close(w.proxy); err != nil {\n\t\terrors = append(errors, err)\n\t}\n\n\tif len(errors) > 0 {\n\t\treturn newError(\"failed to close all resources\").Base(newError(serial.Concat(errors...)))\n\t}\n\treturn nil\n}\n\nfunc (w *udpWorker) Port() net.Port {\n\treturn w.port\n}\n\nfunc (w *udpWorker) Proxy() proxy.Inbound {\n\treturn w.proxy\n}\n"
  },
  {
    "path": "app/proxyman/outbound/errors.generated.go",
    "content": "package outbound\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "app/proxyman/outbound/handler.go",
    "content": "package outbound\n\nimport (\n\t\"context\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/app/proxyman\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/mux\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/session\"\n\t\"v2ray.com/core/features/outbound\"\n\t\"v2ray.com/core/features/policy\"\n\t\"v2ray.com/core/features/stats\"\n\t\"v2ray.com/core/proxy\"\n\t\"v2ray.com/core/transport\"\n\t\"v2ray.com/core/transport/internet\"\n\t\"v2ray.com/core/transport/internet/tls\"\n\t\"v2ray.com/core/transport/pipe\"\n)\n\nfunc getStatCounter(v *core.Instance, tag string) (stats.Counter, stats.Counter) {\n\tvar uplinkCounter stats.Counter\n\tvar downlinkCounter stats.Counter\n\n\tpolicy := v.GetFeature(policy.ManagerType()).(policy.Manager)\n\tif len(tag) > 0 && policy.ForSystem().Stats.OutboundUplink {\n\t\tstatsManager := v.GetFeature(stats.ManagerType()).(stats.Manager)\n\t\tname := \"outbound>>>\" + tag + \">>>traffic>>>uplink\"\n\t\tc, _ := stats.GetOrRegisterCounter(statsManager, name)\n\t\tif c != nil {\n\t\t\tuplinkCounter = c\n\t\t}\n\t}\n\tif len(tag) > 0 && policy.ForSystem().Stats.OutboundDownlink {\n\t\tstatsManager := v.GetFeature(stats.ManagerType()).(stats.Manager)\n\t\tname := \"outbound>>>\" + tag + \">>>traffic>>>downlink\"\n\t\tc, _ := stats.GetOrRegisterCounter(statsManager, name)\n\t\tif c != nil {\n\t\t\tdownlinkCounter = c\n\t\t}\n\t}\n\n\treturn uplinkCounter, downlinkCounter\n}\n\n// Handler is an implements of outbound.Handler.\ntype Handler struct {\n\ttag             string\n\tsenderSettings  *proxyman.SenderConfig\n\tstreamSettings  *internet.MemoryStreamConfig\n\tproxy           proxy.Outbound\n\toutboundManager outbound.Manager\n\tmux             *mux.ClientManager\n\tuplinkCounter   stats.Counter\n\tdownlinkCounter stats.Counter\n}\n\n// NewHandler create a new Handler based on the given configuration.\nfunc NewHandler(ctx context.Context, config *core.OutboundHandlerConfig) (outbound.Handler, error) {\n\tv := core.MustFromContext(ctx)\n\tuplinkCounter, downlinkCounter := getStatCounter(v, config.Tag)\n\th := &Handler{\n\t\ttag:             config.Tag,\n\t\toutboundManager: v.GetFeature(outbound.ManagerType()).(outbound.Manager),\n\t\tuplinkCounter:   uplinkCounter,\n\t\tdownlinkCounter: downlinkCounter,\n\t}\n\n\tif config.SenderSettings != nil {\n\t\tsenderSettings, err := config.SenderSettings.GetInstance()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tswitch s := senderSettings.(type) {\n\t\tcase *proxyman.SenderConfig:\n\t\t\th.senderSettings = s\n\t\t\tmss, err := internet.ToMemoryStreamConfig(s.StreamSettings)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, newError(\"failed to parse stream settings\").Base(err).AtWarning()\n\t\t\t}\n\t\t\th.streamSettings = mss\n\t\tdefault:\n\t\t\treturn nil, newError(\"settings is not SenderConfig\")\n\t\t}\n\t}\n\n\tproxyConfig, err := config.ProxySettings.GetInstance()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\trawProxyHandler, err := common.CreateObject(ctx, proxyConfig)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tproxyHandler, ok := rawProxyHandler.(proxy.Outbound)\n\tif !ok {\n\t\treturn nil, newError(\"not an outbound handler\")\n\t}\n\n\tif h.senderSettings != nil && h.senderSettings.MultiplexSettings != nil {\n\t\tconfig := h.senderSettings.MultiplexSettings\n\t\tif config.Concurrency < 1 || config.Concurrency > 1024 {\n\t\t\treturn nil, newError(\"invalid mux concurrency: \", config.Concurrency).AtWarning()\n\t\t}\n\t\th.mux = &mux.ClientManager{\n\t\t\tEnabled: h.senderSettings.MultiplexSettings.Enabled,\n\t\t\tPicker: &mux.IncrementalWorkerPicker{\n\t\t\t\tFactory: &mux.DialingWorkerFactory{\n\t\t\t\t\tProxy:  proxyHandler,\n\t\t\t\t\tDialer: h,\n\t\t\t\t\tStrategy: mux.ClientStrategy{\n\t\t\t\t\t\tMaxConcurrency: config.Concurrency,\n\t\t\t\t\t\tMaxConnection:  128,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t}\n\n\th.proxy = proxyHandler\n\treturn h, nil\n}\n\n// Tag implements outbound.Handler.\nfunc (h *Handler) Tag() string {\n\treturn h.tag\n}\n\n// Dispatch implements proxy.Outbound.Dispatch.\nfunc (h *Handler) Dispatch(ctx context.Context, link *transport.Link) {\n\tif h.mux != nil && (h.mux.Enabled || session.MuxPreferedFromContext(ctx)) {\n\t\tif err := h.mux.Dispatch(ctx, link); err != nil {\n\t\t\tnewError(\"failed to process mux outbound traffic\").Base(err).WriteToLog(session.ExportIDToError(ctx))\n\t\t\tcommon.Interrupt(link.Writer)\n\t\t}\n\t} else {\n\t\tif err := h.proxy.Process(ctx, link, h); err != nil {\n\t\t\t// Ensure outbound ray is properly closed.\n\t\t\tnewError(\"failed to process outbound traffic\").Base(err).WriteToLog(session.ExportIDToError(ctx))\n\t\t\tcommon.Interrupt(link.Writer)\n\t\t} else {\n\t\t\tcommon.Must(common.Close(link.Writer))\n\t\t}\n\t\tcommon.Interrupt(link.Reader)\n\t}\n}\n\n// Address implements internet.Dialer.\nfunc (h *Handler) Address() net.Address {\n\tif h.senderSettings == nil || h.senderSettings.Via == nil {\n\t\treturn nil\n\t}\n\treturn h.senderSettings.Via.AsAddress()\n}\n\n// Dial implements internet.Dialer.\nfunc (h *Handler) Dial(ctx context.Context, dest net.Destination) (internet.Connection, error) {\n\tif h.senderSettings != nil {\n\t\tif h.senderSettings.ProxySettings.HasTag() {\n\t\t\ttag := h.senderSettings.ProxySettings.Tag\n\t\t\thandler := h.outboundManager.GetHandler(tag)\n\t\t\tif handler != nil {\n\t\t\t\tnewError(\"proxying to \", tag, \" for dest \", dest).AtDebug().WriteToLog(session.ExportIDToError(ctx))\n\t\t\t\tctx = session.ContextWithOutbound(ctx, &session.Outbound{\n\t\t\t\t\tTarget: dest,\n\t\t\t\t})\n\n\t\t\t\topts := pipe.OptionsFromContext(ctx)\n\t\t\t\tuplinkReader, uplinkWriter := pipe.New(opts...)\n\t\t\t\tdownlinkReader, downlinkWriter := pipe.New(opts...)\n\n\t\t\t\tgo handler.Dispatch(ctx, &transport.Link{Reader: uplinkReader, Writer: downlinkWriter})\n\t\t\t\tconn := net.NewConnection(net.ConnectionInputMulti(uplinkWriter), net.ConnectionOutputMulti(downlinkReader))\n\n\t\t\t\tif config := tls.ConfigFromStreamSettings(h.streamSettings); config != nil {\n\t\t\t\t\ttlsConfig := config.GetTLSConfig(tls.WithDestination(dest))\n\t\t\t\t\tconn = tls.Client(conn, tlsConfig)\n\t\t\t\t}\n\n\t\t\t\treturn h.getStatCouterConnection(conn), nil\n\t\t\t}\n\n\t\t\tnewError(\"failed to get outbound handler with tag: \", tag).AtWarning().WriteToLog(session.ExportIDToError(ctx))\n\t\t}\n\n\t\tif h.senderSettings.Via != nil {\n\t\t\toutbound := session.OutboundFromContext(ctx)\n\t\t\tif outbound == nil {\n\t\t\t\toutbound = new(session.Outbound)\n\t\t\t\tctx = session.ContextWithOutbound(ctx, outbound)\n\t\t\t}\n\t\t\toutbound.Gateway = h.senderSettings.Via.AsAddress()\n\t\t}\n\t}\n\n\tconn, err := internet.Dial(ctx, dest, h.streamSettings)\n\treturn h.getStatCouterConnection(conn), err\n}\n\nfunc (h *Handler) getStatCouterConnection(conn internet.Connection) internet.Connection {\n\tif h.uplinkCounter != nil || h.downlinkCounter != nil {\n\t\treturn &internet.StatCouterConnection{\n\t\t\tConnection:   conn,\n\t\t\tReadCounter:  h.downlinkCounter,\n\t\t\tWriteCounter: h.uplinkCounter,\n\t\t}\n\t}\n\treturn conn\n}\n\n// GetOutbound implements proxy.GetOutbound.\nfunc (h *Handler) GetOutbound() proxy.Outbound {\n\treturn h.proxy\n}\n\n// Start implements common.Runnable.\nfunc (h *Handler) Start() error {\n\treturn nil\n}\n\n// Close implements common.Closable.\nfunc (h *Handler) Close() error {\n\tcommon.Close(h.mux)\n\treturn nil\n}\n"
  },
  {
    "path": "app/proxyman/outbound/handler_test.go",
    "content": "package outbound_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/app/policy\"\n\t. \"v2ray.com/core/app/proxyman/outbound\"\n\t\"v2ray.com/core/app/stats\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/serial\"\n\t\"v2ray.com/core/features/outbound\"\n\t\"v2ray.com/core/proxy/freedom\"\n\t\"v2ray.com/core/transport/internet\"\n)\n\nfunc TestInterfaces(t *testing.T) {\n\t_ = (outbound.Handler)(new(Handler))\n\t_ = (outbound.Manager)(new(Manager))\n}\n\nconst v2rayKey core.V2rayKey = 1\n\nfunc TestOutboundWithoutStatCounter(t *testing.T) {\n\tconfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&stats.Config{}),\n\t\t\tserial.ToTypedMessage(&policy.Config{\n\t\t\t\tSystem: &policy.SystemPolicy{\n\t\t\t\t\tStats: &policy.SystemPolicy_Stats{\n\t\t\t\t\t\tInboundUplink: true,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}),\n\t\t},\n\t}\n\n\tv, _ := core.New(config)\n\tv.AddFeature((outbound.Manager)(new(Manager)))\n\tctx := context.WithValue(context.Background(), v2rayKey, v)\n\th, _ := NewHandler(ctx, &core.OutboundHandlerConfig{\n\t\tTag:           \"tag\",\n\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t})\n\tconn, _ := h.(*Handler).Dial(ctx, net.TCPDestination(net.DomainAddress(\"localhost\"), 13146))\n\t_, ok := conn.(*internet.StatCouterConnection)\n\tif ok {\n\t\tt.Errorf(\"Expected conn to not be StatCouterConnection\")\n\t}\n}\n\nfunc TestOutboundWithStatCounter(t *testing.T) {\n\tconfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&stats.Config{}),\n\t\t\tserial.ToTypedMessage(&policy.Config{\n\t\t\t\tSystem: &policy.SystemPolicy{\n\t\t\t\t\tStats: &policy.SystemPolicy_Stats{\n\t\t\t\t\t\tOutboundUplink:   true,\n\t\t\t\t\t\tOutboundDownlink: true,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}),\n\t\t},\n\t}\n\n\tv, _ := core.New(config)\n\tv.AddFeature((outbound.Manager)(new(Manager)))\n\tctx := context.WithValue(context.Background(), v2rayKey, v)\n\th, _ := NewHandler(ctx, &core.OutboundHandlerConfig{\n\t\tTag:           \"tag\",\n\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t})\n\tconn, _ := h.(*Handler).Dial(ctx, net.TCPDestination(net.DomainAddress(\"localhost\"), 13146))\n\t_, ok := conn.(*internet.StatCouterConnection)\n\tif !ok {\n\t\tt.Errorf(\"Expected conn to be StatCouterConnection\")\n\t}\n}\n"
  },
  {
    "path": "app/proxyman/outbound/outbound.go",
    "content": "package outbound\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n\nimport (\n\t\"context\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/app/proxyman\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/errors\"\n\t\"v2ray.com/core/features/outbound\"\n)\n\n// Manager is to manage all outbound handlers.\ntype Manager struct {\n\taccess           sync.RWMutex\n\tdefaultHandler   outbound.Handler\n\ttaggedHandler    map[string]outbound.Handler\n\tuntaggedHandlers []outbound.Handler\n\trunning          bool\n}\n\n// New creates a new Manager.\nfunc New(ctx context.Context, config *proxyman.OutboundConfig) (*Manager, error) {\n\tm := &Manager{\n\t\ttaggedHandler: make(map[string]outbound.Handler),\n\t}\n\treturn m, nil\n}\n\n// Type implements common.HasType.\nfunc (m *Manager) Type() interface{} {\n\treturn outbound.ManagerType()\n}\n\n// Start implements core.Feature\nfunc (m *Manager) Start() error {\n\tm.access.Lock()\n\tdefer m.access.Unlock()\n\n\tm.running = true\n\n\tfor _, h := range m.taggedHandler {\n\t\tif err := h.Start(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tfor _, h := range m.untaggedHandlers {\n\t\tif err := h.Start(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Close implements core.Feature\nfunc (m *Manager) Close() error {\n\tm.access.Lock()\n\tdefer m.access.Unlock()\n\n\tm.running = false\n\n\tvar errs []error\n\tfor _, h := range m.taggedHandler {\n\t\terrs = append(errs, h.Close())\n\t}\n\n\tfor _, h := range m.untaggedHandlers {\n\t\terrs = append(errs, h.Close())\n\t}\n\n\treturn errors.Combine(errs...)\n}\n\n// GetDefaultHandler implements outbound.Manager.\nfunc (m *Manager) GetDefaultHandler() outbound.Handler {\n\tm.access.RLock()\n\tdefer m.access.RUnlock()\n\n\tif m.defaultHandler == nil {\n\t\treturn nil\n\t}\n\treturn m.defaultHandler\n}\n\n// GetHandler implements outbound.Manager.\nfunc (m *Manager) GetHandler(tag string) outbound.Handler {\n\tm.access.RLock()\n\tdefer m.access.RUnlock()\n\tif handler, found := m.taggedHandler[tag]; found {\n\t\treturn handler\n\t}\n\treturn nil\n}\n\n// AddHandler implements outbound.Manager.\nfunc (m *Manager) AddHandler(ctx context.Context, handler outbound.Handler) error {\n\tm.access.Lock()\n\tdefer m.access.Unlock()\n\n\tif m.defaultHandler == nil {\n\t\tm.defaultHandler = handler\n\t}\n\n\ttag := handler.Tag()\n\tif len(tag) > 0 {\n\t\tm.taggedHandler[tag] = handler\n\t} else {\n\t\tm.untaggedHandlers = append(m.untaggedHandlers, handler)\n\t}\n\n\tif m.running {\n\t\treturn handler.Start()\n\t}\n\n\treturn nil\n}\n\n// RemoveHandler implements outbound.Manager.\nfunc (m *Manager) RemoveHandler(ctx context.Context, tag string) error {\n\tif tag == \"\" {\n\t\treturn common.ErrNoClue\n\t}\n\tm.access.Lock()\n\tdefer m.access.Unlock()\n\n\tdelete(m.taggedHandler, tag)\n\tif m.defaultHandler != nil && m.defaultHandler.Tag() == tag {\n\t\tm.defaultHandler = nil\n\t}\n\n\treturn nil\n}\n\n// Select implements outbound.HandlerSelector.\nfunc (m *Manager) Select(selectors []string) []string {\n\tm.access.RLock()\n\tdefer m.access.RUnlock()\n\n\ttags := make([]string, 0, len(selectors))\n\n\tfor tag := range m.taggedHandler {\n\t\tmatch := false\n\t\tfor _, selector := range selectors {\n\t\t\tif strings.HasPrefix(tag, selector) {\n\t\t\t\tmatch = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif match {\n\t\t\ttags = append(tags, tag)\n\t\t}\n\t}\n\n\treturn tags\n}\n\nfunc init() {\n\tcommon.Must(common.RegisterConfig((*proxyman.OutboundConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {\n\t\treturn New(ctx, config.(*proxyman.OutboundConfig))\n\t}))\n\tcommon.Must(common.RegisterConfig((*core.OutboundHandlerConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {\n\t\treturn NewHandler(ctx, config.(*core.OutboundHandlerConfig))\n\t}))\n}\n"
  },
  {
    "path": "app/proxyman/proxyman.go",
    "content": "// Package proxyman defines applications for managing inbound and outbound proxies.\npackage proxyman\n\nimport (\n\t\"context\"\n\n\t\"v2ray.com/core/common/session\"\n)\n\n// ContextWithSniffingConfig is a wrapper of session.ContextWithContent.\n// Deprecated. Use session.ContextWithContent directly.\nfunc ContextWithSniffingConfig(ctx context.Context, c *SniffingConfig) context.Context {\n\tcontent := session.ContentFromContext(ctx)\n\tif content == nil {\n\t\tcontent = new(session.Content)\n\t\tctx = session.ContextWithContent(ctx, content)\n\t}\n\tcontent.SniffingRequest.Enabled = c.Enabled\n\tcontent.SniffingRequest.OverrideDestinationForProtocol = c.DestinationOverride\n\treturn ctx\n}\n"
  },
  {
    "path": "app/reverse/bridge.go",
    "content": "// +build !confonly\n\npackage reverse\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/golang/protobuf/proto\"\n\t\"v2ray.com/core/common/mux\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/session\"\n\t\"v2ray.com/core/common/task\"\n\t\"v2ray.com/core/features/routing\"\n\t\"v2ray.com/core/transport\"\n\t\"v2ray.com/core/transport/pipe\"\n)\n\n// Bridge is a component in reverse proxy, that relays connections from Portal to local address.\ntype Bridge struct {\n\tdispatcher  routing.Dispatcher\n\ttag         string\n\tdomain      string\n\tworkers     []*BridgeWorker\n\tmonitorTask *task.Periodic\n}\n\n// NewBridge creates a new Bridge instance.\nfunc NewBridge(config *BridgeConfig, dispatcher routing.Dispatcher) (*Bridge, error) {\n\tif config.Tag == \"\" {\n\t\treturn nil, newError(\"bridge tag is empty\")\n\t}\n\tif config.Domain == \"\" {\n\t\treturn nil, newError(\"bridge domain is empty\")\n\t}\n\n\tb := &Bridge{\n\t\tdispatcher: dispatcher,\n\t\ttag:        config.Tag,\n\t\tdomain:     config.Domain,\n\t}\n\tb.monitorTask = &task.Periodic{\n\t\tExecute:  b.monitor,\n\t\tInterval: time.Second * 2,\n\t}\n\treturn b, nil\n}\n\nfunc (b *Bridge) cleanup() {\n\tvar activeWorkers []*BridgeWorker\n\n\tfor _, w := range b.workers {\n\t\tif w.IsActive() {\n\t\t\tactiveWorkers = append(activeWorkers, w)\n\t\t}\n\t}\n\n\tif len(activeWorkers) != len(b.workers) {\n\t\tb.workers = activeWorkers\n\t}\n}\n\nfunc (b *Bridge) monitor() error {\n\tb.cleanup()\n\n\tvar numConnections uint32\n\tvar numWorker uint32\n\n\tfor _, w := range b.workers {\n\t\tif w.IsActive() {\n\t\t\tnumConnections += w.Connections()\n\t\t\tnumWorker++\n\t\t}\n\t}\n\n\tif numWorker == 0 || numConnections/numWorker > 16 {\n\t\tworker, err := NewBridgeWorker(b.domain, b.tag, b.dispatcher)\n\t\tif err != nil {\n\t\t\tnewError(\"failed to create bridge worker\").Base(err).AtWarning().WriteToLog()\n\t\t\treturn nil\n\t\t}\n\t\tb.workers = append(b.workers, worker)\n\t}\n\n\treturn nil\n}\n\nfunc (b *Bridge) Start() error {\n\treturn b.monitorTask.Start()\n}\n\nfunc (b *Bridge) Close() error {\n\treturn b.monitorTask.Close()\n}\n\ntype BridgeWorker struct {\n\ttag        string\n\tworker     *mux.ServerWorker\n\tdispatcher routing.Dispatcher\n\tstate      Control_State\n}\n\nfunc NewBridgeWorker(domain string, tag string, d routing.Dispatcher) (*BridgeWorker, error) {\n\tctx := context.Background()\n\tctx = session.ContextWithInbound(ctx, &session.Inbound{\n\t\tTag: tag,\n\t})\n\tlink, err := d.Dispatch(ctx, net.Destination{\n\t\tNetwork: net.Network_TCP,\n\t\tAddress: net.DomainAddress(domain),\n\t\tPort:    0,\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tw := &BridgeWorker{\n\t\tdispatcher: d,\n\t\ttag:        tag,\n\t}\n\n\tworker, err := mux.NewServerWorker(context.Background(), w, link)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tw.worker = worker\n\n\treturn w, nil\n}\n\nfunc (w *BridgeWorker) Type() interface{} {\n\treturn routing.DispatcherType()\n}\n\nfunc (w *BridgeWorker) Start() error {\n\treturn nil\n}\n\nfunc (w *BridgeWorker) Close() error {\n\treturn nil\n}\n\nfunc (w *BridgeWorker) IsActive() bool {\n\treturn w.state == Control_ACTIVE && !w.worker.Closed()\n}\n\nfunc (w *BridgeWorker) Connections() uint32 {\n\treturn w.worker.ActiveConnections()\n}\n\nfunc (w *BridgeWorker) handleInternalConn(link transport.Link) {\n\tgo func() {\n\t\treader := link.Reader\n\t\tfor {\n\t\t\tmb, err := reader.ReadMultiBuffer()\n\t\t\tif err != nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tfor _, b := range mb {\n\t\t\t\tvar ctl Control\n\t\t\t\tif err := proto.Unmarshal(b.Bytes(), &ctl); err != nil {\n\t\t\t\t\tnewError(\"failed to parse proto message\").Base(err).WriteToLog()\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tif ctl.State != w.state {\n\t\t\t\t\tw.state = ctl.State\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}()\n}\n\nfunc (w *BridgeWorker) Dispatch(ctx context.Context, dest net.Destination) (*transport.Link, error) {\n\tif !isInternalDomain(dest) {\n\t\tctx = session.ContextWithInbound(ctx, &session.Inbound{\n\t\t\tTag: w.tag,\n\t\t})\n\t\treturn w.dispatcher.Dispatch(ctx, dest)\n\t}\n\n\topt := []pipe.Option{pipe.WithSizeLimit(16 * 1024)}\n\tuplinkReader, uplinkWriter := pipe.New(opt...)\n\tdownlinkReader, downlinkWriter := pipe.New(opt...)\n\n\tw.handleInternalConn(transport.Link{\n\t\tReader: downlinkReader,\n\t\tWriter: uplinkWriter,\n\t})\n\n\treturn &transport.Link{\n\t\tReader: uplinkReader,\n\t\tWriter: downlinkWriter,\n\t}, nil\n}\n"
  },
  {
    "path": "app/reverse/config.go",
    "content": "// +build !confonly\n\npackage reverse\n\nimport (\n\t\"crypto/rand\"\n\t\"io\"\n\n\t\"v2ray.com/core/common/dice\"\n)\n\nfunc (c *Control) FillInRandom() {\n\trandomLength := dice.Roll(64)\n\tc.Random = make([]byte, randomLength)\n\tio.ReadFull(rand.Reader, c.Random)\n}\n"
  },
  {
    "path": "app/reverse/config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: app/reverse/config.proto\n\npackage reverse\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype Control_State int32\n\nconst (\n\tControl_ACTIVE Control_State = 0\n\tControl_DRAIN  Control_State = 1\n)\n\n// Enum value maps for Control_State.\nvar (\n\tControl_State_name = map[int32]string{\n\t\t0: \"ACTIVE\",\n\t\t1: \"DRAIN\",\n\t}\n\tControl_State_value = map[string]int32{\n\t\t\"ACTIVE\": 0,\n\t\t\"DRAIN\":  1,\n\t}\n)\n\nfunc (x Control_State) Enum() *Control_State {\n\tp := new(Control_State)\n\t*p = x\n\treturn p\n}\n\nfunc (x Control_State) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (Control_State) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_app_reverse_config_proto_enumTypes[0].Descriptor()\n}\n\nfunc (Control_State) Type() protoreflect.EnumType {\n\treturn &file_app_reverse_config_proto_enumTypes[0]\n}\n\nfunc (x Control_State) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use Control_State.Descriptor instead.\nfunc (Control_State) EnumDescriptor() ([]byte, []int) {\n\treturn file_app_reverse_config_proto_rawDescGZIP(), []int{0, 0}\n}\n\ntype Control struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tState  Control_State `protobuf:\"varint,1,opt,name=state,proto3,enum=v2ray.core.app.reverse.Control_State\" json:\"state,omitempty\"`\n\tRandom []byte        `protobuf:\"bytes,99,opt,name=random,proto3\" json:\"random,omitempty\"`\n}\n\nfunc (x *Control) Reset() {\n\t*x = Control{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_reverse_config_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Control) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Control) ProtoMessage() {}\n\nfunc (x *Control) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_reverse_config_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Control.ProtoReflect.Descriptor instead.\nfunc (*Control) Descriptor() ([]byte, []int) {\n\treturn file_app_reverse_config_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *Control) GetState() Control_State {\n\tif x != nil {\n\t\treturn x.State\n\t}\n\treturn Control_ACTIVE\n}\n\nfunc (x *Control) GetRandom() []byte {\n\tif x != nil {\n\t\treturn x.Random\n\t}\n\treturn nil\n}\n\ntype BridgeConfig struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tTag    string `protobuf:\"bytes,1,opt,name=tag,proto3\" json:\"tag,omitempty\"`\n\tDomain string `protobuf:\"bytes,2,opt,name=domain,proto3\" json:\"domain,omitempty\"`\n}\n\nfunc (x *BridgeConfig) Reset() {\n\t*x = BridgeConfig{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_reverse_config_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *BridgeConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*BridgeConfig) ProtoMessage() {}\n\nfunc (x *BridgeConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_reverse_config_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use BridgeConfig.ProtoReflect.Descriptor instead.\nfunc (*BridgeConfig) Descriptor() ([]byte, []int) {\n\treturn file_app_reverse_config_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *BridgeConfig) GetTag() string {\n\tif x != nil {\n\t\treturn x.Tag\n\t}\n\treturn \"\"\n}\n\nfunc (x *BridgeConfig) GetDomain() string {\n\tif x != nil {\n\t\treturn x.Domain\n\t}\n\treturn \"\"\n}\n\ntype PortalConfig struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tTag    string `protobuf:\"bytes,1,opt,name=tag,proto3\" json:\"tag,omitempty\"`\n\tDomain string `protobuf:\"bytes,2,opt,name=domain,proto3\" json:\"domain,omitempty\"`\n}\n\nfunc (x *PortalConfig) Reset() {\n\t*x = PortalConfig{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_reverse_config_proto_msgTypes[2]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *PortalConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*PortalConfig) ProtoMessage() {}\n\nfunc (x *PortalConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_reverse_config_proto_msgTypes[2]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use PortalConfig.ProtoReflect.Descriptor instead.\nfunc (*PortalConfig) Descriptor() ([]byte, []int) {\n\treturn file_app_reverse_config_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *PortalConfig) GetTag() string {\n\tif x != nil {\n\t\treturn x.Tag\n\t}\n\treturn \"\"\n}\n\nfunc (x *PortalConfig) GetDomain() string {\n\tif x != nil {\n\t\treturn x.Domain\n\t}\n\treturn \"\"\n}\n\ntype Config struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tBridgeConfig []*BridgeConfig `protobuf:\"bytes,1,rep,name=bridge_config,json=bridgeConfig,proto3\" json:\"bridge_config,omitempty\"`\n\tPortalConfig []*PortalConfig `protobuf:\"bytes,2,rep,name=portal_config,json=portalConfig,proto3\" json:\"portal_config,omitempty\"`\n}\n\nfunc (x *Config) Reset() {\n\t*x = Config{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_reverse_config_proto_msgTypes[3]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Config) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Config) ProtoMessage() {}\n\nfunc (x *Config) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_reverse_config_proto_msgTypes[3]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Config.ProtoReflect.Descriptor instead.\nfunc (*Config) Descriptor() ([]byte, []int) {\n\treturn file_app_reverse_config_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *Config) GetBridgeConfig() []*BridgeConfig {\n\tif x != nil {\n\t\treturn x.BridgeConfig\n\t}\n\treturn nil\n}\n\nfunc (x *Config) GetPortalConfig() []*PortalConfig {\n\tif x != nil {\n\t\treturn x.PortalConfig\n\t}\n\treturn nil\n}\n\nvar File_app_reverse_config_proto protoreflect.FileDescriptor\n\nvar file_app_reverse_config_proto_rawDesc = []byte{\n\t0x0a, 0x18, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x2f, 0x63, 0x6f,\n\t0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x16, 0x76, 0x32, 0x72, 0x61,\n\t0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x65, 0x76, 0x65, 0x72,\n\t0x73, 0x65, 0x22, 0x7e, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x12, 0x3b, 0x0a,\n\t0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x25, 0x2e, 0x76,\n\t0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x65,\n\t0x76, 0x65, 0x72, 0x73, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x53, 0x74,\n\t0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x61,\n\t0x6e, 0x64, 0x6f, 0x6d, 0x18, 0x63, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x72, 0x61, 0x6e, 0x64,\n\t0x6f, 0x6d, 0x22, 0x1e, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x41,\n\t0x43, 0x54, 0x49, 0x56, 0x45, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x44, 0x52, 0x41, 0x49, 0x4e,\n\t0x10, 0x01, 0x22, 0x38, 0x0a, 0x0c, 0x42, 0x72, 0x69, 0x64, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66,\n\t0x69, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,\n\t0x03, 0x74, 0x61, 0x67, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02,\n\t0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x22, 0x38, 0x0a, 0x0c,\n\t0x50, 0x6f, 0x72, 0x74, 0x61, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a, 0x03,\n\t0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x16,\n\t0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,\n\t0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x22, 0x9e, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69,\n\t0x67, 0x12, 0x49, 0x0a, 0x0d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66,\n\t0x69, 0x67, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,\n\t0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x65, 0x76, 0x65, 0x72, 0x73,\n\t0x65, 0x2e, 0x42, 0x72, 0x69, 0x64, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0c,\n\t0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x49, 0x0a, 0x0d,\n\t0x70, 0x6f, 0x72, 0x74, 0x61, 0x6c, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20,\n\t0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,\n\t0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x2e, 0x50, 0x6f, 0x72,\n\t0x74, 0x61, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0c, 0x70, 0x6f, 0x72, 0x74, 0x61,\n\t0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x57, 0x0a, 0x1c, 0x63, 0x6f, 0x6d, 0x2e, 0x76,\n\t0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e,\n\t0x72, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x50, 0x01, 0x5a, 0x1a, 0x76, 0x32, 0x72, 0x61, 0x79,\n\t0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x65,\n\t0x76, 0x65, 0x72, 0x73, 0x65, 0xaa, 0x02, 0x18, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f,\n\t0x72, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x52, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65,\n\t0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_app_reverse_config_proto_rawDescOnce sync.Once\n\tfile_app_reverse_config_proto_rawDescData = file_app_reverse_config_proto_rawDesc\n)\n\nfunc file_app_reverse_config_proto_rawDescGZIP() []byte {\n\tfile_app_reverse_config_proto_rawDescOnce.Do(func() {\n\t\tfile_app_reverse_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_reverse_config_proto_rawDescData)\n\t})\n\treturn file_app_reverse_config_proto_rawDescData\n}\n\nvar file_app_reverse_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1)\nvar file_app_reverse_config_proto_msgTypes = make([]protoimpl.MessageInfo, 4)\nvar file_app_reverse_config_proto_goTypes = []interface{}{\n\t(Control_State)(0),   // 0: v2ray.core.app.reverse.Control.State\n\t(*Control)(nil),      // 1: v2ray.core.app.reverse.Control\n\t(*BridgeConfig)(nil), // 2: v2ray.core.app.reverse.BridgeConfig\n\t(*PortalConfig)(nil), // 3: v2ray.core.app.reverse.PortalConfig\n\t(*Config)(nil),       // 4: v2ray.core.app.reverse.Config\n}\nvar file_app_reverse_config_proto_depIdxs = []int32{\n\t0, // 0: v2ray.core.app.reverse.Control.state:type_name -> v2ray.core.app.reverse.Control.State\n\t2, // 1: v2ray.core.app.reverse.Config.bridge_config:type_name -> v2ray.core.app.reverse.BridgeConfig\n\t3, // 2: v2ray.core.app.reverse.Config.portal_config:type_name -> v2ray.core.app.reverse.PortalConfig\n\t3, // [3:3] is the sub-list for method output_type\n\t3, // [3:3] is the sub-list for method input_type\n\t3, // [3:3] is the sub-list for extension type_name\n\t3, // [3:3] is the sub-list for extension extendee\n\t0, // [0:3] is the sub-list for field type_name\n}\n\nfunc init() { file_app_reverse_config_proto_init() }\nfunc file_app_reverse_config_proto_init() {\n\tif File_app_reverse_config_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_app_reverse_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Control); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_reverse_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*BridgeConfig); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_reverse_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*PortalConfig); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_reverse_config_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Config); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_app_reverse_config_proto_rawDesc,\n\t\t\tNumEnums:      1,\n\t\t\tNumMessages:   4,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_app_reverse_config_proto_goTypes,\n\t\tDependencyIndexes: file_app_reverse_config_proto_depIdxs,\n\t\tEnumInfos:         file_app_reverse_config_proto_enumTypes,\n\t\tMessageInfos:      file_app_reverse_config_proto_msgTypes,\n\t}.Build()\n\tFile_app_reverse_config_proto = out.File\n\tfile_app_reverse_config_proto_rawDesc = nil\n\tfile_app_reverse_config_proto_goTypes = nil\n\tfile_app_reverse_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "app/reverse/config.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.app.reverse;\noption csharp_namespace = \"V2Ray.Core.Proxy.Reverse\";\noption go_package = \"v2ray.com/core/app/reverse\";\noption java_package = \"com.v2ray.core.proxy.reverse\";\noption java_multiple_files = true;\n\nmessage Control {\n  enum State {\n    ACTIVE = 0;\n    DRAIN = 1;\n  }\n\n  State state = 1;\n  bytes random = 99;\n}\n\nmessage BridgeConfig {\n  string tag = 1;\n  string domain = 2;\n}\n\nmessage PortalConfig {\n  string tag = 1;\n  string domain = 2;\n}\n\nmessage Config {\n  repeated BridgeConfig bridge_config = 1;\n  repeated PortalConfig portal_config = 2;\n}\n"
  },
  {
    "path": "app/reverse/errors.generated.go",
    "content": "package reverse\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "app/reverse/portal.go",
    "content": "// +build !confonly\n\npackage reverse\n\nimport (\n\t\"context\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/golang/protobuf/proto\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/mux\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/session\"\n\t\"v2ray.com/core/common/task\"\n\t\"v2ray.com/core/features/outbound\"\n\t\"v2ray.com/core/transport\"\n\t\"v2ray.com/core/transport/pipe\"\n)\n\ntype Portal struct {\n\tohm    outbound.Manager\n\ttag    string\n\tdomain string\n\tpicker *StaticMuxPicker\n\tclient *mux.ClientManager\n}\n\nfunc NewPortal(config *PortalConfig, ohm outbound.Manager) (*Portal, error) {\n\tif config.Tag == \"\" {\n\t\treturn nil, newError(\"portal tag is empty\")\n\t}\n\n\tif config.Domain == \"\" {\n\t\treturn nil, newError(\"portal domain is empty\")\n\t}\n\n\tpicker, err := NewStaticMuxPicker()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &Portal{\n\t\tohm:    ohm,\n\t\ttag:    config.Tag,\n\t\tdomain: config.Domain,\n\t\tpicker: picker,\n\t\tclient: &mux.ClientManager{\n\t\t\tPicker: picker,\n\t\t},\n\t}, nil\n}\n\nfunc (p *Portal) Start() error {\n\treturn p.ohm.AddHandler(context.Background(), &Outbound{\n\t\tportal: p,\n\t\ttag:    p.tag,\n\t})\n}\n\nfunc (p *Portal) Close() error {\n\treturn p.ohm.RemoveHandler(context.Background(), p.tag)\n}\n\nfunc (p *Portal) HandleConnection(ctx context.Context, link *transport.Link) error {\n\toutboundMeta := session.OutboundFromContext(ctx)\n\tif outboundMeta == nil {\n\t\treturn newError(\"outbound metadata not found\").AtError()\n\t}\n\n\tif isDomain(outboundMeta.Target, p.domain) {\n\t\tmuxClient, err := mux.NewClientWorker(*link, mux.ClientStrategy{})\n\t\tif err != nil {\n\t\t\treturn newError(\"failed to create mux client worker\").Base(err).AtWarning()\n\t\t}\n\n\t\tworker, err := NewPortalWorker(muxClient)\n\t\tif err != nil {\n\t\t\treturn newError(\"failed to create portal worker\").Base(err)\n\t\t}\n\n\t\tp.picker.AddWorker(worker)\n\t\treturn nil\n\t}\n\n\treturn p.client.Dispatch(ctx, link)\n}\n\ntype Outbound struct {\n\tportal *Portal\n\ttag    string\n}\n\nfunc (o *Outbound) Tag() string {\n\treturn o.tag\n}\n\nfunc (o *Outbound) Dispatch(ctx context.Context, link *transport.Link) {\n\tif err := o.portal.HandleConnection(ctx, link); err != nil {\n\t\tnewError(\"failed to process reverse connection\").Base(err).WriteToLog(session.ExportIDToError(ctx))\n\t\tcommon.Interrupt(link.Writer)\n\t}\n}\n\nfunc (o *Outbound) Start() error {\n\treturn nil\n}\n\nfunc (o *Outbound) Close() error {\n\treturn nil\n}\n\ntype StaticMuxPicker struct {\n\taccess  sync.Mutex\n\tworkers []*PortalWorker\n\tcTask   *task.Periodic\n}\n\nfunc NewStaticMuxPicker() (*StaticMuxPicker, error) {\n\tp := &StaticMuxPicker{}\n\tp.cTask = &task.Periodic{\n\t\tExecute:  p.cleanup,\n\t\tInterval: time.Second * 30,\n\t}\n\tp.cTask.Start()\n\treturn p, nil\n}\n\nfunc (p *StaticMuxPicker) cleanup() error {\n\tp.access.Lock()\n\tdefer p.access.Unlock()\n\n\tvar activeWorkers []*PortalWorker\n\tfor _, w := range p.workers {\n\t\tif !w.Closed() {\n\t\t\tactiveWorkers = append(activeWorkers, w)\n\t\t}\n\t}\n\n\tif len(activeWorkers) != len(p.workers) {\n\t\tp.workers = activeWorkers\n\t}\n\n\treturn nil\n}\n\nfunc (p *StaticMuxPicker) PickAvailable() (*mux.ClientWorker, error) {\n\tp.access.Lock()\n\tdefer p.access.Unlock()\n\n\tif len(p.workers) == 0 {\n\t\treturn nil, newError(\"empty worker list\")\n\t}\n\n\tvar minIdx int = -1\n\tvar minConn uint32 = 9999\n\tfor i, w := range p.workers {\n\t\tif w.draining {\n\t\t\tcontinue\n\t\t}\n\t\tif w.client.ActiveConnections() < minConn {\n\t\t\tminConn = w.client.ActiveConnections()\n\t\t\tminIdx = i\n\t\t}\n\t}\n\n\tif minIdx == -1 {\n\t\tfor i, w := range p.workers {\n\t\t\tif w.IsFull() {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif w.client.ActiveConnections() < minConn {\n\t\t\t\tminConn = w.client.ActiveConnections()\n\t\t\t\tminIdx = i\n\t\t\t}\n\t\t}\n\t}\n\n\tif minIdx != -1 {\n\t\treturn p.workers[minIdx].client, nil\n\t}\n\n\treturn nil, newError(\"no mux client worker available\")\n}\n\nfunc (p *StaticMuxPicker) AddWorker(worker *PortalWorker) {\n\tp.access.Lock()\n\tdefer p.access.Unlock()\n\n\tp.workers = append(p.workers, worker)\n}\n\ntype PortalWorker struct {\n\tclient   *mux.ClientWorker\n\tcontrol  *task.Periodic\n\twriter   buf.Writer\n\treader   buf.Reader\n\tdraining bool\n}\n\nfunc NewPortalWorker(client *mux.ClientWorker) (*PortalWorker, error) {\n\topt := []pipe.Option{pipe.WithSizeLimit(16 * 1024)}\n\tuplinkReader, uplinkWriter := pipe.New(opt...)\n\tdownlinkReader, downlinkWriter := pipe.New(opt...)\n\n\tctx := context.Background()\n\tctx = session.ContextWithOutbound(ctx, &session.Outbound{\n\t\tTarget: net.UDPDestination(net.DomainAddress(internalDomain), 0),\n\t})\n\tf := client.Dispatch(ctx, &transport.Link{\n\t\tReader: uplinkReader,\n\t\tWriter: downlinkWriter,\n\t})\n\tif !f {\n\t\treturn nil, newError(\"unable to dispatch control connection\")\n\t}\n\tw := &PortalWorker{\n\t\tclient: client,\n\t\treader: downlinkReader,\n\t\twriter: uplinkWriter,\n\t}\n\tw.control = &task.Periodic{\n\t\tExecute:  w.heartbeat,\n\t\tInterval: time.Second * 2,\n\t}\n\tw.control.Start()\n\treturn w, nil\n}\n\nfunc (w *PortalWorker) heartbeat() error {\n\tif w.client.Closed() {\n\t\treturn newError(\"client worker stopped\")\n\t}\n\n\tif w.draining || w.writer == nil {\n\t\treturn newError(\"already disposed\")\n\t}\n\n\tmsg := &Control{}\n\tmsg.FillInRandom()\n\n\tif w.client.TotalConnections() > 256 {\n\t\tw.draining = true\n\t\tmsg.State = Control_DRAIN\n\n\t\tdefer func() {\n\t\t\tcommon.Close(w.writer)\n\t\t\tcommon.Interrupt(w.reader)\n\t\t\tw.writer = nil\n\t\t}()\n\t}\n\n\tb, err := proto.Marshal(msg)\n\tcommon.Must(err)\n\tmb := buf.MergeBytes(nil, b)\n\treturn w.writer.WriteMultiBuffer(mb)\n}\n\nfunc (w *PortalWorker) IsFull() bool {\n\treturn w.client.IsFull()\n}\n\nfunc (w *PortalWorker) Closed() bool {\n\treturn w.client.Closed()\n}\n"
  },
  {
    "path": "app/reverse/portal_test.go",
    "content": "package reverse_test\n\nimport (\n\t\"testing\"\n\n\t\"v2ray.com/core/app/reverse\"\n\t\"v2ray.com/core/common\"\n)\n\nfunc TestStaticPickerEmpty(t *testing.T) {\n\tpicker, err := reverse.NewStaticMuxPicker()\n\tcommon.Must(err)\n\tworker, err := picker.PickAvailable()\n\tif err == nil {\n\t\tt.Error(\"expected error, but nil\")\n\t}\n\tif worker != nil {\n\t\tt.Error(\"expected nil worker, but not nil\")\n\t}\n}\n"
  },
  {
    "path": "app/reverse/reverse.go",
    "content": "// +build !confonly\n\npackage reverse\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n\nimport (\n\t\"context\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/errors\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/features/outbound\"\n\t\"v2ray.com/core/features/routing\"\n)\n\nconst (\n\tinternalDomain = \"reverse.internal.v2ray.com\"\n)\n\nfunc isDomain(dest net.Destination, domain string) bool {\n\treturn dest.Address.Family().IsDomain() && dest.Address.Domain() == domain\n}\n\nfunc isInternalDomain(dest net.Destination) bool {\n\treturn isDomain(dest, internalDomain)\n}\n\nfunc init() {\n\tcommon.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {\n\t\tr := new(Reverse)\n\t\tif err := core.RequireFeatures(ctx, func(d routing.Dispatcher, om outbound.Manager) error {\n\t\t\treturn r.Init(config.(*Config), d, om)\n\t\t}); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn r, nil\n\t}))\n}\n\ntype Reverse struct {\n\tbridges []*Bridge\n\tportals []*Portal\n}\n\nfunc (r *Reverse) Init(config *Config, d routing.Dispatcher, ohm outbound.Manager) error {\n\tfor _, bConfig := range config.BridgeConfig {\n\t\tb, err := NewBridge(bConfig, d)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tr.bridges = append(r.bridges, b)\n\t}\n\n\tfor _, pConfig := range config.PortalConfig {\n\t\tp, err := NewPortal(pConfig, ohm)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tr.portals = append(r.portals, p)\n\t}\n\n\treturn nil\n}\n\nfunc (r *Reverse) Type() interface{} {\n\treturn (*Reverse)(nil)\n}\n\nfunc (r *Reverse) Start() error {\n\tfor _, b := range r.bridges {\n\t\tif err := b.Start(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tfor _, p := range r.portals {\n\t\tif err := p.Start(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (r *Reverse) Close() error {\n\tvar errs []error\n\tfor _, b := range r.bridges {\n\t\terrs = append(errs, b.Close())\n\t}\n\n\tfor _, p := range r.portals {\n\t\terrs = append(errs, p.Close())\n\t}\n\n\treturn errors.Combine(errs...)\n}\n"
  },
  {
    "path": "app/router/balancing.go",
    "content": "// +build !confonly\n\npackage router\n\nimport (\n\t\"v2ray.com/core/common/dice\"\n\t\"v2ray.com/core/features/outbound\"\n)\n\ntype BalancingStrategy interface {\n\tPickOutbound([]string) string\n}\n\ntype RandomStrategy struct {\n}\n\nfunc (s *RandomStrategy) PickOutbound(tags []string) string {\n\tn := len(tags)\n\tif n == 0 {\n\t\tpanic(\"0 tags\")\n\t}\n\n\treturn tags[dice.Roll(n)]\n}\n\ntype Balancer struct {\n\tselectors []string\n\tstrategy  BalancingStrategy\n\tohm       outbound.Manager\n}\n\nfunc (b *Balancer) PickOutbound() (string, error) {\n\ths, ok := b.ohm.(outbound.HandlerSelector)\n\tif !ok {\n\t\treturn \"\", newError(\"outbound.Manager is not a HandlerSelector\")\n\t}\n\ttags := hs.Select(b.selectors)\n\tif len(tags) == 0 {\n\t\treturn \"\", newError(\"no available outbounds selected\")\n\t}\n\ttag := b.strategy.PickOutbound(tags)\n\tif tag == \"\" {\n\t\treturn \"\", newError(\"balancing strategy returns empty tag\")\n\t}\n\treturn tag, nil\n}\n"
  },
  {
    "path": "app/router/command/command.go",
    "content": "// +build !confonly\n\npackage command\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"google.golang.org/grpc\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/features/routing\"\n\t\"v2ray.com/core/features/stats\"\n)\n\n// routingServer is an implementation of RoutingService.\ntype routingServer struct {\n\trouter       routing.Router\n\troutingStats stats.Channel\n}\n\n// NewRoutingServer creates a statistics service with statistics manager.\nfunc NewRoutingServer(router routing.Router, routingStats stats.Channel) RoutingServiceServer {\n\treturn &routingServer{\n\t\trouter:       router,\n\t\troutingStats: routingStats,\n\t}\n}\n\nfunc (s *routingServer) TestRoute(ctx context.Context, request *TestRouteRequest) (*RoutingContext, error) {\n\tif request.RoutingContext == nil {\n\t\treturn nil, newError(\"Invalid routing request.\")\n\t}\n\troute, err := s.router.PickRoute(AsRoutingContext(request.RoutingContext))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif request.PublishResult && s.routingStats != nil {\n\t\tctx, _ := context.WithTimeout(context.Background(), 4*time.Second) // nolint: govet\n\t\ts.routingStats.Publish(ctx, route)\n\t}\n\treturn AsProtobufMessage(request.FieldSelectors)(route), nil\n}\n\nfunc (s *routingServer) SubscribeRoutingStats(request *SubscribeRoutingStatsRequest, stream RoutingService_SubscribeRoutingStatsServer) error {\n\tif s.routingStats == nil {\n\t\treturn newError(\"Routing statistics not enabled.\")\n\t}\n\tgenMessage := AsProtobufMessage(request.FieldSelectors)\n\tsubscriber, err := stats.SubscribeRunnableChannel(s.routingStats)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer stats.UnsubscribeClosableChannel(s.routingStats, subscriber) // nolint: errcheck\n\tfor {\n\t\tselect {\n\t\tcase value, ok := <-subscriber:\n\t\t\tif !ok {\n\t\t\t\treturn newError(\"Upstream closed the subscriber channel.\")\n\t\t\t}\n\t\t\troute, ok := value.(routing.Route)\n\t\t\tif !ok {\n\t\t\t\treturn newError(\"Upstream sent malformed statistics.\")\n\t\t\t}\n\t\t\terr := stream.Send(genMessage(route))\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tcase <-stream.Context().Done():\n\t\t\treturn stream.Context().Err()\n\t\t}\n\t}\n}\n\nfunc (s *routingServer) mustEmbedUnimplementedRoutingServiceServer() {}\n\ntype service struct {\n\tv *core.Instance\n}\n\nfunc (s *service) Register(server *grpc.Server) {\n\tcommon.Must(s.v.RequireFeatures(func(router routing.Router, stats stats.Manager) {\n\t\tRegisterRoutingServiceServer(server, NewRoutingServer(router, nil))\n\t}))\n}\n\nfunc init() {\n\tcommon.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, cfg interface{}) (interface{}, error) {\n\t\ts := core.MustFromContext(ctx)\n\t\treturn &service{v: s}, nil\n\t}))\n}\n"
  },
  {
    "path": "app/router/command/command.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: app/router/command/command.proto\n\npackage command\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n\tnet \"v2ray.com/core/common/net\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\n// RoutingContext is the context with information relative to routing process.\n// It conforms to the structure of v2ray.core.features.routing.Context and\n// v2ray.core.features.routing.Route.\ntype RoutingContext struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tInboundTag        string            `protobuf:\"bytes,1,opt,name=InboundTag,proto3\" json:\"InboundTag,omitempty\"`\n\tNetwork           net.Network       `protobuf:\"varint,2,opt,name=Network,proto3,enum=v2ray.core.common.net.Network\" json:\"Network,omitempty\"`\n\tSourceIPs         [][]byte          `protobuf:\"bytes,3,rep,name=SourceIPs,proto3\" json:\"SourceIPs,omitempty\"`\n\tTargetIPs         [][]byte          `protobuf:\"bytes,4,rep,name=TargetIPs,proto3\" json:\"TargetIPs,omitempty\"`\n\tSourcePort        uint32            `protobuf:\"varint,5,opt,name=SourcePort,proto3\" json:\"SourcePort,omitempty\"`\n\tTargetPort        uint32            `protobuf:\"varint,6,opt,name=TargetPort,proto3\" json:\"TargetPort,omitempty\"`\n\tTargetDomain      string            `protobuf:\"bytes,7,opt,name=TargetDomain,proto3\" json:\"TargetDomain,omitempty\"`\n\tProtocol          string            `protobuf:\"bytes,8,opt,name=Protocol,proto3\" json:\"Protocol,omitempty\"`\n\tUser              string            `protobuf:\"bytes,9,opt,name=User,proto3\" json:\"User,omitempty\"`\n\tAttributes        map[string]string `protobuf:\"bytes,10,rep,name=Attributes,proto3\" json:\"Attributes,omitempty\" protobuf_key:\"bytes,1,opt,name=key,proto3\" protobuf_val:\"bytes,2,opt,name=value,proto3\"`\n\tOutboundGroupTags []string          `protobuf:\"bytes,11,rep,name=OutboundGroupTags,proto3\" json:\"OutboundGroupTags,omitempty\"`\n\tOutboundTag       string            `protobuf:\"bytes,12,opt,name=OutboundTag,proto3\" json:\"OutboundTag,omitempty\"`\n}\n\nfunc (x *RoutingContext) Reset() {\n\t*x = RoutingContext{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_router_command_command_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *RoutingContext) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RoutingContext) ProtoMessage() {}\n\nfunc (x *RoutingContext) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_router_command_command_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RoutingContext.ProtoReflect.Descriptor instead.\nfunc (*RoutingContext) Descriptor() ([]byte, []int) {\n\treturn file_app_router_command_command_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *RoutingContext) GetInboundTag() string {\n\tif x != nil {\n\t\treturn x.InboundTag\n\t}\n\treturn \"\"\n}\n\nfunc (x *RoutingContext) GetNetwork() net.Network {\n\tif x != nil {\n\t\treturn x.Network\n\t}\n\treturn net.Network_Unknown\n}\n\nfunc (x *RoutingContext) GetSourceIPs() [][]byte {\n\tif x != nil {\n\t\treturn x.SourceIPs\n\t}\n\treturn nil\n}\n\nfunc (x *RoutingContext) GetTargetIPs() [][]byte {\n\tif x != nil {\n\t\treturn x.TargetIPs\n\t}\n\treturn nil\n}\n\nfunc (x *RoutingContext) GetSourcePort() uint32 {\n\tif x != nil {\n\t\treturn x.SourcePort\n\t}\n\treturn 0\n}\n\nfunc (x *RoutingContext) GetTargetPort() uint32 {\n\tif x != nil {\n\t\treturn x.TargetPort\n\t}\n\treturn 0\n}\n\nfunc (x *RoutingContext) GetTargetDomain() string {\n\tif x != nil {\n\t\treturn x.TargetDomain\n\t}\n\treturn \"\"\n}\n\nfunc (x *RoutingContext) GetProtocol() string {\n\tif x != nil {\n\t\treturn x.Protocol\n\t}\n\treturn \"\"\n}\n\nfunc (x *RoutingContext) GetUser() string {\n\tif x != nil {\n\t\treturn x.User\n\t}\n\treturn \"\"\n}\n\nfunc (x *RoutingContext) GetAttributes() map[string]string {\n\tif x != nil {\n\t\treturn x.Attributes\n\t}\n\treturn nil\n}\n\nfunc (x *RoutingContext) GetOutboundGroupTags() []string {\n\tif x != nil {\n\t\treturn x.OutboundGroupTags\n\t}\n\treturn nil\n}\n\nfunc (x *RoutingContext) GetOutboundTag() string {\n\tif x != nil {\n\t\treturn x.OutboundTag\n\t}\n\treturn \"\"\n}\n\n// SubscribeRoutingStatsRequest subscribes to routing statistics channel if\n// opened by v2ray-core.\n// * FieldSelectors selects a subset of fields in routing statistics to return.\n// Valid selectors:\n//  - inbound: Selects connection's inbound tag.\n//  - network: Selects connection's network.\n//  - ip: Equivalent as \"ip_source\" and \"ip_target\", selects both source and\n//  target IP.\n//  - port: Equivalent as \"port_source\" and \"port_target\", selects both source\n//  and target port.\n//  - domain: Selects target domain.\n//  - protocol: Select connection's protocol.\n//  - user: Select connection's inbound user email.\n//  - attributes: Select connection's additional attributes.\n//  - outbound: Equivalent as \"outbound\" and \"outbound_group\", select both\n//  outbound tag and outbound group tags.\n// * If FieldSelectors is left empty, all fields will be returned.\ntype SubscribeRoutingStatsRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tFieldSelectors []string `protobuf:\"bytes,1,rep,name=FieldSelectors,proto3\" json:\"FieldSelectors,omitempty\"`\n}\n\nfunc (x *SubscribeRoutingStatsRequest) Reset() {\n\t*x = SubscribeRoutingStatsRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_router_command_command_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *SubscribeRoutingStatsRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SubscribeRoutingStatsRequest) ProtoMessage() {}\n\nfunc (x *SubscribeRoutingStatsRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_router_command_command_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SubscribeRoutingStatsRequest.ProtoReflect.Descriptor instead.\nfunc (*SubscribeRoutingStatsRequest) Descriptor() ([]byte, []int) {\n\treturn file_app_router_command_command_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *SubscribeRoutingStatsRequest) GetFieldSelectors() []string {\n\tif x != nil {\n\t\treturn x.FieldSelectors\n\t}\n\treturn nil\n}\n\n// TestRouteRequest manually tests a routing result according to the routing\n// context message.\n// * RoutingContext is the routing message without outbound information.\n// * FieldSelectors selects the fields to return in the routing result. All\n// fields are returned if left empty.\n// * PublishResult broadcasts the routing result to routing statistics channel\n// if set true.\ntype TestRouteRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tRoutingContext *RoutingContext `protobuf:\"bytes,1,opt,name=RoutingContext,proto3\" json:\"RoutingContext,omitempty\"`\n\tFieldSelectors []string        `protobuf:\"bytes,2,rep,name=FieldSelectors,proto3\" json:\"FieldSelectors,omitempty\"`\n\tPublishResult  bool            `protobuf:\"varint,3,opt,name=PublishResult,proto3\" json:\"PublishResult,omitempty\"`\n}\n\nfunc (x *TestRouteRequest) Reset() {\n\t*x = TestRouteRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_router_command_command_proto_msgTypes[2]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *TestRouteRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*TestRouteRequest) ProtoMessage() {}\n\nfunc (x *TestRouteRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_router_command_command_proto_msgTypes[2]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use TestRouteRequest.ProtoReflect.Descriptor instead.\nfunc (*TestRouteRequest) Descriptor() ([]byte, []int) {\n\treturn file_app_router_command_command_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *TestRouteRequest) GetRoutingContext() *RoutingContext {\n\tif x != nil {\n\t\treturn x.RoutingContext\n\t}\n\treturn nil\n}\n\nfunc (x *TestRouteRequest) GetFieldSelectors() []string {\n\tif x != nil {\n\t\treturn x.FieldSelectors\n\t}\n\treturn nil\n}\n\nfunc (x *TestRouteRequest) GetPublishResult() bool {\n\tif x != nil {\n\t\treturn x.PublishResult\n\t}\n\treturn false\n}\n\ntype Config struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *Config) Reset() {\n\t*x = Config{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_router_command_command_proto_msgTypes[3]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Config) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Config) ProtoMessage() {}\n\nfunc (x *Config) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_router_command_command_proto_msgTypes[3]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Config.ProtoReflect.Descriptor instead.\nfunc (*Config) Descriptor() ([]byte, []int) {\n\treturn file_app_router_command_command_proto_rawDescGZIP(), []int{3}\n}\n\nvar File_app_router_command_command_proto protoreflect.FileDescriptor\n\nvar file_app_router_command_command_proto_rawDesc = []byte{\n\t0x0a, 0x20, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x6d,\n\t0x6d, 0x61, 0x6e, 0x64, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x70, 0x72, 0x6f,\n\t0x74, 0x6f, 0x12, 0x1d, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61,\n\t0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e,\n\t0x64, 0x1a, 0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x6e, 0x65,\n\t0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xa8, 0x04, 0x0a, 0x0e,\n\t0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x1e,\n\t0x0a, 0x0a, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01,\n\t0x28, 0x09, 0x52, 0x0a, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x67, 0x12, 0x38,\n\t0x0a, 0x07, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32,\n\t0x1e, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d,\n\t0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52,\n\t0x07, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x1c, 0x0a, 0x09, 0x53, 0x6f, 0x75, 0x72,\n\t0x63, 0x65, 0x49, 0x50, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x09, 0x53, 0x6f, 0x75,\n\t0x72, 0x63, 0x65, 0x49, 0x50, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74,\n\t0x49, 0x50, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x09, 0x54, 0x61, 0x72, 0x67, 0x65,\n\t0x74, 0x49, 0x50, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x50, 0x6f,\n\t0x72, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65,\n\t0x50, 0x6f, 0x72, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x50, 0x6f,\n\t0x72, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74,\n\t0x50, 0x6f, 0x72, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x44, 0x6f,\n\t0x6d, 0x61, 0x69, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x54, 0x61, 0x72, 0x67,\n\t0x65, 0x74, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x74,\n\t0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x72, 0x6f, 0x74,\n\t0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x18, 0x09, 0x20, 0x01,\n\t0x28, 0x09, 0x52, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, 0x5d, 0x0a, 0x0a, 0x41, 0x74, 0x74, 0x72,\n\t0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3d, 0x2e, 0x76,\n\t0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f,\n\t0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x6f, 0x75,\n\t0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x72,\n\t0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x41, 0x74, 0x74,\n\t0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x2c, 0x0a, 0x11, 0x4f, 0x75, 0x74, 0x62, 0x6f,\n\t0x75, 0x6e, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x54, 0x61, 0x67, 0x73, 0x18, 0x0b, 0x20, 0x03,\n\t0x28, 0x09, 0x52, 0x11, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x47, 0x72, 0x6f, 0x75,\n\t0x70, 0x54, 0x61, 0x67, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e,\n\t0x64, 0x54, 0x61, 0x67, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x4f, 0x75, 0x74, 0x62,\n\t0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x67, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69,\n\t0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,\n\t0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05,\n\t0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c,\n\t0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x46, 0x0a, 0x1c, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72,\n\t0x69, 0x62, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52,\n\t0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x53,\n\t0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e,\n\t0x46, 0x69, 0x65, 0x6c, 0x64, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x22, 0xb7,\n\t0x01, 0x0a, 0x10, 0x54, 0x65, 0x73, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75,\n\t0x65, 0x73, 0x74, 0x12, 0x55, 0x0a, 0x0e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f,\n\t0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x76, 0x32,\n\t0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75,\n\t0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x6f, 0x75, 0x74,\n\t0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x0e, 0x52, 0x6f, 0x75, 0x74,\n\t0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x46, 0x69,\n\t0x65, 0x6c, 0x64, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03,\n\t0x28, 0x09, 0x52, 0x0e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f,\n\t0x72, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x73,\n\t0x75, 0x6c, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x50, 0x75, 0x62, 0x6c, 0x69,\n\t0x73, 0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x08, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66,\n\t0x69, 0x67, 0x32, 0x89, 0x02, 0x0a, 0x0e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x65,\n\t0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x87, 0x01, 0x0a, 0x15, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72,\n\t0x69, 0x62, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12,\n\t0x3b, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70,\n\t0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e,\n\t0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67,\n\t0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x76,\n\t0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f,\n\t0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x6f, 0x75,\n\t0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, 0x00, 0x30, 0x01, 0x12,\n\t0x6d, 0x0a, 0x09, 0x54, 0x65, 0x73, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x2f, 0x2e, 0x76,\n\t0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f,\n\t0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x54, 0x65, 0x73,\n\t0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e,\n\t0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72,\n\t0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x6f,\n\t0x75, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, 0x00, 0x42, 0x68,\n\t0x0a, 0x21, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,\n\t0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,\n\t0x61, 0x6e, 0x64, 0x50, 0x01, 0x5a, 0x21, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d,\n\t0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72,\n\t0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0xaa, 0x02, 0x1d, 0x56, 0x32, 0x52, 0x61, 0x79,\n\t0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x72,\n\t0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_app_router_command_command_proto_rawDescOnce sync.Once\n\tfile_app_router_command_command_proto_rawDescData = file_app_router_command_command_proto_rawDesc\n)\n\nfunc file_app_router_command_command_proto_rawDescGZIP() []byte {\n\tfile_app_router_command_command_proto_rawDescOnce.Do(func() {\n\t\tfile_app_router_command_command_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_router_command_command_proto_rawDescData)\n\t})\n\treturn file_app_router_command_command_proto_rawDescData\n}\n\nvar file_app_router_command_command_proto_msgTypes = make([]protoimpl.MessageInfo, 5)\nvar file_app_router_command_command_proto_goTypes = []interface{}{\n\t(*RoutingContext)(nil),               // 0: v2ray.core.app.router.command.RoutingContext\n\t(*SubscribeRoutingStatsRequest)(nil), // 1: v2ray.core.app.router.command.SubscribeRoutingStatsRequest\n\t(*TestRouteRequest)(nil),             // 2: v2ray.core.app.router.command.TestRouteRequest\n\t(*Config)(nil),                       // 3: v2ray.core.app.router.command.Config\n\tnil,                                  // 4: v2ray.core.app.router.command.RoutingContext.AttributesEntry\n\t(net.Network)(0),                     // 5: v2ray.core.common.net.Network\n}\nvar file_app_router_command_command_proto_depIdxs = []int32{\n\t5, // 0: v2ray.core.app.router.command.RoutingContext.Network:type_name -> v2ray.core.common.net.Network\n\t4, // 1: v2ray.core.app.router.command.RoutingContext.Attributes:type_name -> v2ray.core.app.router.command.RoutingContext.AttributesEntry\n\t0, // 2: v2ray.core.app.router.command.TestRouteRequest.RoutingContext:type_name -> v2ray.core.app.router.command.RoutingContext\n\t1, // 3: v2ray.core.app.router.command.RoutingService.SubscribeRoutingStats:input_type -> v2ray.core.app.router.command.SubscribeRoutingStatsRequest\n\t2, // 4: v2ray.core.app.router.command.RoutingService.TestRoute:input_type -> v2ray.core.app.router.command.TestRouteRequest\n\t0, // 5: v2ray.core.app.router.command.RoutingService.SubscribeRoutingStats:output_type -> v2ray.core.app.router.command.RoutingContext\n\t0, // 6: v2ray.core.app.router.command.RoutingService.TestRoute:output_type -> v2ray.core.app.router.command.RoutingContext\n\t5, // [5:7] is the sub-list for method output_type\n\t3, // [3:5] is the sub-list for method input_type\n\t3, // [3:3] is the sub-list for extension type_name\n\t3, // [3:3] is the sub-list for extension extendee\n\t0, // [0:3] is the sub-list for field type_name\n}\n\nfunc init() { file_app_router_command_command_proto_init() }\nfunc file_app_router_command_command_proto_init() {\n\tif File_app_router_command_command_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_app_router_command_command_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*RoutingContext); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_router_command_command_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*SubscribeRoutingStatsRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_router_command_command_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*TestRouteRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_router_command_command_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Config); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_app_router_command_command_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   5,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   1,\n\t\t},\n\t\tGoTypes:           file_app_router_command_command_proto_goTypes,\n\t\tDependencyIndexes: file_app_router_command_command_proto_depIdxs,\n\t\tMessageInfos:      file_app_router_command_command_proto_msgTypes,\n\t}.Build()\n\tFile_app_router_command_command_proto = out.File\n\tfile_app_router_command_command_proto_rawDesc = nil\n\tfile_app_router_command_command_proto_goTypes = nil\n\tfile_app_router_command_command_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "app/router/command/command.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.app.router.command;\noption csharp_namespace = \"V2Ray.Core.App.Router.Command\";\noption go_package = \"v2ray.com/core/app/router/command\";\noption java_package = \"com.v2ray.core.app.router.command\";\noption java_multiple_files = true;\n\nimport \"common/net/network.proto\";\n\n// RoutingContext is the context with information relative to routing process.\n// It conforms to the structure of v2ray.core.features.routing.Context and\n// v2ray.core.features.routing.Route.\nmessage RoutingContext {\n  string InboundTag = 1;\n  v2ray.core.common.net.Network Network = 2;\n  repeated bytes SourceIPs = 3;\n  repeated bytes TargetIPs = 4;\n  uint32 SourcePort = 5;\n  uint32 TargetPort = 6;\n  string TargetDomain = 7;\n  string Protocol = 8;\n  string User = 9;\n  map<string, string> Attributes = 10;\n  repeated string OutboundGroupTags = 11;\n  string OutboundTag = 12;\n}\n\n// SubscribeRoutingStatsRequest subscribes to routing statistics channel if\n// opened by v2ray-core.\n// * FieldSelectors selects a subset of fields in routing statistics to return.\n// Valid selectors:\n//  - inbound: Selects connection's inbound tag.\n//  - network: Selects connection's network.\n//  - ip: Equivalent as \"ip_source\" and \"ip_target\", selects both source and\n//  target IP.\n//  - port: Equivalent as \"port_source\" and \"port_target\", selects both source\n//  and target port.\n//  - domain: Selects target domain.\n//  - protocol: Select connection's protocol.\n//  - user: Select connection's inbound user email.\n//  - attributes: Select connection's additional attributes.\n//  - outbound: Equivalent as \"outbound\" and \"outbound_group\", select both\n//  outbound tag and outbound group tags.\n// * If FieldSelectors is left empty, all fields will be returned.\nmessage SubscribeRoutingStatsRequest {\n  repeated string FieldSelectors = 1;\n}\n\n// TestRouteRequest manually tests a routing result according to the routing\n// context message.\n// * RoutingContext is the routing message without outbound information.\n// * FieldSelectors selects the fields to return in the routing result. All\n// fields are returned if left empty.\n// * PublishResult broadcasts the routing result to routing statistics channel\n// if set true.\nmessage TestRouteRequest {\n  RoutingContext RoutingContext = 1;\n  repeated string FieldSelectors = 2;\n  bool PublishResult = 3;\n}\n\nservice RoutingService {\n  rpc SubscribeRoutingStats(SubscribeRoutingStatsRequest)\n      returns (stream RoutingContext) {}\n  rpc TestRoute(TestRouteRequest) returns (RoutingContext) {}\n}\n\nmessage Config {}\n"
  },
  {
    "path": "app/router/command/command_grpc.pb.go",
    "content": "// Code generated by protoc-gen-go-grpc. DO NOT EDIT.\n\npackage command\n\nimport (\n\tcontext \"context\"\n\tgrpc \"google.golang.org/grpc\"\n\tcodes \"google.golang.org/grpc/codes\"\n\tstatus \"google.golang.org/grpc/status\"\n)\n\n// This is a compile-time assertion to ensure that this generated file\n// is compatible with the grpc package it is being compiled against.\nconst _ = grpc.SupportPackageIsVersion7\n\n// RoutingServiceClient is the client API for RoutingService service.\n//\n// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.\ntype RoutingServiceClient interface {\n\tSubscribeRoutingStats(ctx context.Context, in *SubscribeRoutingStatsRequest, opts ...grpc.CallOption) (RoutingService_SubscribeRoutingStatsClient, error)\n\tTestRoute(ctx context.Context, in *TestRouteRequest, opts ...grpc.CallOption) (*RoutingContext, error)\n}\n\ntype routingServiceClient struct {\n\tcc grpc.ClientConnInterface\n}\n\nfunc NewRoutingServiceClient(cc grpc.ClientConnInterface) RoutingServiceClient {\n\treturn &routingServiceClient{cc}\n}\n\nfunc (c *routingServiceClient) SubscribeRoutingStats(ctx context.Context, in *SubscribeRoutingStatsRequest, opts ...grpc.CallOption) (RoutingService_SubscribeRoutingStatsClient, error) {\n\tstream, err := c.cc.NewStream(ctx, &_RoutingService_serviceDesc.Streams[0], \"/v2ray.core.app.router.command.RoutingService/SubscribeRoutingStats\", opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tx := &routingServiceSubscribeRoutingStatsClient{stream}\n\tif err := x.ClientStream.SendMsg(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := x.ClientStream.CloseSend(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn x, nil\n}\n\ntype RoutingService_SubscribeRoutingStatsClient interface {\n\tRecv() (*RoutingContext, error)\n\tgrpc.ClientStream\n}\n\ntype routingServiceSubscribeRoutingStatsClient struct {\n\tgrpc.ClientStream\n}\n\nfunc (x *routingServiceSubscribeRoutingStatsClient) Recv() (*RoutingContext, error) {\n\tm := new(RoutingContext)\n\tif err := x.ClientStream.RecvMsg(m); err != nil {\n\t\treturn nil, err\n\t}\n\treturn m, nil\n}\n\nfunc (c *routingServiceClient) TestRoute(ctx context.Context, in *TestRouteRequest, opts ...grpc.CallOption) (*RoutingContext, error) {\n\tout := new(RoutingContext)\n\terr := c.cc.Invoke(ctx, \"/v2ray.core.app.router.command.RoutingService/TestRoute\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\n// RoutingServiceServer is the server API for RoutingService service.\n// All implementations must embed UnimplementedRoutingServiceServer\n// for forward compatibility\ntype RoutingServiceServer interface {\n\tSubscribeRoutingStats(*SubscribeRoutingStatsRequest, RoutingService_SubscribeRoutingStatsServer) error\n\tTestRoute(context.Context, *TestRouteRequest) (*RoutingContext, error)\n\tmustEmbedUnimplementedRoutingServiceServer()\n}\n\n// UnimplementedRoutingServiceServer must be embedded to have forward compatible implementations.\ntype UnimplementedRoutingServiceServer struct {\n}\n\nfunc (UnimplementedRoutingServiceServer) SubscribeRoutingStats(*SubscribeRoutingStatsRequest, RoutingService_SubscribeRoutingStatsServer) error {\n\treturn status.Errorf(codes.Unimplemented, \"method SubscribeRoutingStats not implemented\")\n}\nfunc (UnimplementedRoutingServiceServer) TestRoute(context.Context, *TestRouteRequest) (*RoutingContext, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method TestRoute not implemented\")\n}\nfunc (UnimplementedRoutingServiceServer) mustEmbedUnimplementedRoutingServiceServer() {}\n\n// UnsafeRoutingServiceServer may be embedded to opt out of forward compatibility for this service.\n// Use of this interface is not recommended, as added methods to RoutingServiceServer will\n// result in compilation errors.\ntype UnsafeRoutingServiceServer interface {\n\tmustEmbedUnimplementedRoutingServiceServer()\n}\n\nfunc RegisterRoutingServiceServer(s *grpc.Server, srv RoutingServiceServer) {\n\ts.RegisterService(&_RoutingService_serviceDesc, srv)\n}\n\nfunc _RoutingService_SubscribeRoutingStats_Handler(srv interface{}, stream grpc.ServerStream) error {\n\tm := new(SubscribeRoutingStatsRequest)\n\tif err := stream.RecvMsg(m); err != nil {\n\t\treturn err\n\t}\n\treturn srv.(RoutingServiceServer).SubscribeRoutingStats(m, &routingServiceSubscribeRoutingStatsServer{stream})\n}\n\ntype RoutingService_SubscribeRoutingStatsServer interface {\n\tSend(*RoutingContext) error\n\tgrpc.ServerStream\n}\n\ntype routingServiceSubscribeRoutingStatsServer struct {\n\tgrpc.ServerStream\n}\n\nfunc (x *routingServiceSubscribeRoutingStatsServer) Send(m *RoutingContext) error {\n\treturn x.ServerStream.SendMsg(m)\n}\n\nfunc _RoutingService_TestRoute_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(TestRouteRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(RoutingServiceServer).TestRoute(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/v2ray.core.app.router.command.RoutingService/TestRoute\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(RoutingServiceServer).TestRoute(ctx, req.(*TestRouteRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nvar _RoutingService_serviceDesc = grpc.ServiceDesc{\n\tServiceName: \"v2ray.core.app.router.command.RoutingService\",\n\tHandlerType: (*RoutingServiceServer)(nil),\n\tMethods: []grpc.MethodDesc{\n\t\t{\n\t\t\tMethodName: \"TestRoute\",\n\t\t\tHandler:    _RoutingService_TestRoute_Handler,\n\t\t},\n\t},\n\tStreams: []grpc.StreamDesc{\n\t\t{\n\t\t\tStreamName:    \"SubscribeRoutingStats\",\n\t\t\tHandler:       _RoutingService_SubscribeRoutingStats_Handler,\n\t\t\tServerStreams: true,\n\t\t},\n\t},\n\tMetadata: \"app/router/command/command.proto\",\n}\n"
  },
  {
    "path": "app/router/command/command_test.go",
    "content": "package command_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/golang/mock/gomock\"\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/google/go-cmp/cmp/cmpopts\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/test/bufconn\"\n\t\"v2ray.com/core/app/router\"\n\t. \"v2ray.com/core/app/router/command\"\n\t\"v2ray.com/core/app/stats\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/features/routing\"\n\t\"v2ray.com/core/testing/mocks\"\n)\n\nfunc TestServiceSubscribeRoutingStats(t *testing.T) {\n\tc := stats.NewChannel(&stats.ChannelConfig{\n\t\tSubscriberLimit: 1,\n\t\tBufferSize:      0,\n\t\tBlocking:        true,\n\t})\n\tcommon.Must(c.Start())\n\tdefer c.Close()\n\n\tlis := bufconn.Listen(1024 * 1024)\n\tbufDialer := func(context.Context, string) (net.Conn, error) {\n\t\treturn lis.Dial()\n\t}\n\n\ttestCases := []*RoutingContext{\n\t\t{InboundTag: \"in\", OutboundTag: \"out\"},\n\t\t{TargetIPs: [][]byte{{1, 2, 3, 4}}, TargetPort: 8080, OutboundTag: \"out\"},\n\t\t{TargetDomain: \"example.com\", TargetPort: 443, OutboundTag: \"out\"},\n\t\t{SourcePort: 9999, TargetPort: 9999, OutboundTag: \"out\"},\n\t\t{Network: net.Network_UDP, OutboundGroupTags: []string{\"outergroup\", \"innergroup\"}, OutboundTag: \"out\"},\n\t\t{Protocol: \"bittorrent\", OutboundTag: \"blocked\"},\n\t\t{User: \"example@v2fly.org\", OutboundTag: \"out\"},\n\t\t{SourceIPs: [][]byte{{127, 0, 0, 1}}, Attributes: map[string]string{\"attr\": \"value\"}, OutboundTag: \"out\"},\n\t}\n\terrCh := make(chan error)\n\tnextPub := make(chan struct{})\n\n\t// Server goroutine\n\tgo func() {\n\t\tserver := grpc.NewServer()\n\t\tRegisterRoutingServiceServer(server, NewRoutingServer(nil, c))\n\t\terrCh <- server.Serve(lis)\n\t}()\n\n\t// Publisher goroutine\n\tgo func() {\n\t\tpublishTestCases := func() error {\n\t\t\tctx, cancel := context.WithTimeout(context.Background(), time.Second)\n\t\t\tdefer cancel()\n\t\t\tfor { // Wait until there's one subscriber in routing stats channel\n\t\t\t\tif len(c.Subscribers()) > 0 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tif ctx.Err() != nil {\n\t\t\t\t\treturn ctx.Err()\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor _, tc := range testCases {\n\t\t\t\tc.Publish(context.Background(), AsRoutingRoute(tc))\n\t\t\t\ttime.Sleep(time.Millisecond)\n\t\t\t}\n\t\t\treturn nil\n\t\t}\n\n\t\tif err := publishTestCases(); err != nil {\n\t\t\terrCh <- err\n\t\t}\n\n\t\t// Wait for next round of publishing\n\t\t<-nextPub\n\n\t\tif err := publishTestCases(); err != nil {\n\t\t\terrCh <- err\n\t\t}\n\t}()\n\n\t// Client goroutine\n\tgo func() {\n\t\tdefer lis.Close()\n\t\tconn, err := grpc.DialContext(context.Background(), \"bufnet\", grpc.WithContextDialer(bufDialer), grpc.WithInsecure())\n\t\tif err != nil {\n\t\t\terrCh <- err\n\t\t\treturn\n\t\t}\n\t\tdefer conn.Close()\n\t\tclient := NewRoutingServiceClient(conn)\n\n\t\t// Test retrieving all fields\n\t\ttestRetrievingAllFields := func() error {\n\t\t\tstreamCtx, streamClose := context.WithCancel(context.Background())\n\n\t\t\t// Test the unsubscription of stream works well\n\t\t\tdefer func() {\n\t\t\t\tstreamClose()\n\t\t\t\ttimeOutCtx, timeout := context.WithTimeout(context.Background(), time.Second)\n\t\t\t\tdefer timeout()\n\t\t\t\tfor { // Wait until there's no subscriber in routing stats channel\n\t\t\t\t\tif len(c.Subscribers()) == 0 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tif timeOutCtx.Err() != nil {\n\t\t\t\t\t\tt.Error(\"unexpected subscribers not decreased in channel\", timeOutCtx.Err())\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}()\n\n\t\t\tstream, err := client.SubscribeRoutingStats(streamCtx, &SubscribeRoutingStatsRequest{})\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tfor _, tc := range testCases {\n\t\t\t\tmsg, err := stream.Recv()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tif r := cmp.Diff(msg, tc, cmpopts.IgnoreUnexported(RoutingContext{})); r != \"\" {\n\t\t\t\t\tt.Error(r)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Test that double subscription will fail\n\t\t\terrStream, err := client.SubscribeRoutingStats(context.Background(), &SubscribeRoutingStatsRequest{\n\t\t\t\tFieldSelectors: []string{\"ip\", \"port\", \"domain\", \"outbound\"},\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif _, err := errStream.Recv(); err == nil {\n\t\t\t\tt.Error(\"unexpected successful subscription\")\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}\n\n\t\t// Test retrieving only a subset of fields\n\t\ttestRetrievingSubsetOfFields := func() error {\n\t\t\tstreamCtx, streamClose := context.WithCancel(context.Background())\n\t\t\tdefer streamClose()\n\t\t\tstream, err := client.SubscribeRoutingStats(streamCtx, &SubscribeRoutingStatsRequest{\n\t\t\t\tFieldSelectors: []string{\"ip\", \"port\", \"domain\", \"outbound\"},\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\t// Send nextPub signal to start next round of publishing\n\t\t\tclose(nextPub)\n\n\t\t\tfor _, tc := range testCases {\n\t\t\t\tmsg, err := stream.Recv()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tstat := &RoutingContext{ // Only a subset of stats is retrieved\n\t\t\t\t\tSourceIPs:         tc.SourceIPs,\n\t\t\t\t\tTargetIPs:         tc.TargetIPs,\n\t\t\t\t\tSourcePort:        tc.SourcePort,\n\t\t\t\t\tTargetPort:        tc.TargetPort,\n\t\t\t\t\tTargetDomain:      tc.TargetDomain,\n\t\t\t\t\tOutboundGroupTags: tc.OutboundGroupTags,\n\t\t\t\t\tOutboundTag:       tc.OutboundTag,\n\t\t\t\t}\n\t\t\t\tif r := cmp.Diff(msg, stat, cmpopts.IgnoreUnexported(RoutingContext{})); r != \"\" {\n\t\t\t\t\tt.Error(r)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}\n\n\t\tif err := testRetrievingAllFields(); err != nil {\n\t\t\terrCh <- err\n\t\t}\n\t\tif err := testRetrievingSubsetOfFields(); err != nil {\n\t\t\terrCh <- err\n\t\t}\n\t\terrCh <- nil // Client passed all tests successfully\n\t}()\n\n\t// Wait for goroutines to complete\n\tselect {\n\tcase <-time.After(2 * time.Second):\n\t\tt.Fatal(\"Test timeout after 2s\")\n\tcase err := <-errCh:\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t}\n}\n\nfunc TestSerivceTestRoute(t *testing.T) {\n\tc := stats.NewChannel(&stats.ChannelConfig{\n\t\tSubscriberLimit: 1,\n\t\tBufferSize:      16,\n\t\tBlocking:        true,\n\t})\n\tcommon.Must(c.Start())\n\tdefer c.Close()\n\n\tr := new(router.Router)\n\tmockCtl := gomock.NewController(t)\n\tdefer mockCtl.Finish()\n\tcommon.Must(r.Init(&router.Config{\n\t\tRule: []*router.RoutingRule{\n\t\t\t{\n\t\t\t\tInboundTag: []string{\"in\"},\n\t\t\t\tTargetTag:  &router.RoutingRule_Tag{Tag: \"out\"},\n\t\t\t},\n\t\t\t{\n\t\t\t\tProtocol:  []string{\"bittorrent\"},\n\t\t\t\tTargetTag: &router.RoutingRule_Tag{Tag: \"blocked\"},\n\t\t\t},\n\t\t\t{\n\t\t\t\tPortList:  &net.PortList{Range: []*net.PortRange{{From: 8080, To: 8080}}},\n\t\t\t\tTargetTag: &router.RoutingRule_Tag{Tag: \"out\"},\n\t\t\t},\n\t\t\t{\n\t\t\t\tSourcePortList: &net.PortList{Range: []*net.PortRange{{From: 9999, To: 9999}}},\n\t\t\t\tTargetTag:      &router.RoutingRule_Tag{Tag: \"out\"},\n\t\t\t},\n\t\t\t{\n\t\t\t\tDomain:    []*router.Domain{{Type: router.Domain_Domain, Value: \"com\"}},\n\t\t\t\tTargetTag: &router.RoutingRule_Tag{Tag: \"out\"},\n\t\t\t},\n\t\t\t{\n\t\t\t\tSourceGeoip: []*router.GeoIP{{CountryCode: \"private\", Cidr: []*router.CIDR{{Ip: []byte{127, 0, 0, 0}, Prefix: 8}}}},\n\t\t\t\tTargetTag:   &router.RoutingRule_Tag{Tag: \"out\"},\n\t\t\t},\n\t\t\t{\n\t\t\t\tUserEmail: []string{\"example@v2fly.org\"},\n\t\t\t\tTargetTag: &router.RoutingRule_Tag{Tag: \"out\"},\n\t\t\t},\n\t\t\t{\n\t\t\t\tNetworks:  []net.Network{net.Network_UDP, net.Network_TCP},\n\t\t\t\tTargetTag: &router.RoutingRule_Tag{Tag: \"out\"},\n\t\t\t},\n\t\t},\n\t}, mocks.NewDNSClient(mockCtl), mocks.NewOutboundManager(mockCtl)))\n\n\tlis := bufconn.Listen(1024 * 1024)\n\tbufDialer := func(context.Context, string) (net.Conn, error) {\n\t\treturn lis.Dial()\n\t}\n\n\terrCh := make(chan error)\n\n\t// Server goroutine\n\tgo func() {\n\t\tserver := grpc.NewServer()\n\t\tRegisterRoutingServiceServer(server, NewRoutingServer(r, c))\n\t\terrCh <- server.Serve(lis)\n\t}()\n\n\t// Client goroutine\n\tgo func() {\n\t\tdefer lis.Close()\n\t\tconn, err := grpc.DialContext(context.Background(), \"bufnet\", grpc.WithContextDialer(bufDialer), grpc.WithInsecure())\n\t\tif err != nil {\n\t\t\terrCh <- err\n\t\t}\n\t\tdefer conn.Close()\n\t\tclient := NewRoutingServiceClient(conn)\n\n\t\ttestCases := []*RoutingContext{\n\t\t\t{InboundTag: \"in\", OutboundTag: \"out\"},\n\t\t\t{TargetIPs: [][]byte{{1, 2, 3, 4}}, TargetPort: 8080, OutboundTag: \"out\"},\n\t\t\t{TargetDomain: \"example.com\", TargetPort: 443, OutboundTag: \"out\"},\n\t\t\t{SourcePort: 9999, TargetPort: 9999, OutboundTag: \"out\"},\n\t\t\t{Network: net.Network_UDP, Protocol: \"bittorrent\", OutboundTag: \"blocked\"},\n\t\t\t{User: \"example@v2fly.org\", OutboundTag: \"out\"},\n\t\t\t{SourceIPs: [][]byte{{127, 0, 0, 1}}, Attributes: map[string]string{\"attr\": \"value\"}, OutboundTag: \"out\"},\n\t\t}\n\n\t\t// Test simple TestRoute\n\t\ttestSimple := func() error {\n\t\t\tfor _, tc := range testCases {\n\t\t\t\troute, err := client.TestRoute(context.Background(), &TestRouteRequest{RoutingContext: tc})\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tif r := cmp.Diff(route, tc, cmpopts.IgnoreUnexported(RoutingContext{})); r != \"\" {\n\t\t\t\t\tt.Error(r)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t}\n\n\t\t// Test TestRoute with special options\n\t\ttestOptions := func() error {\n\t\t\tsub, err := c.Subscribe()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, tc := range testCases {\n\t\t\t\troute, err := client.TestRoute(context.Background(), &TestRouteRequest{\n\t\t\t\t\tRoutingContext: tc,\n\t\t\t\t\tFieldSelectors: []string{\"ip\", \"port\", \"domain\", \"outbound\"},\n\t\t\t\t\tPublishResult:  true,\n\t\t\t\t})\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tstat := &RoutingContext{ // Only a subset of stats is retrieved\n\t\t\t\t\tSourceIPs:         tc.SourceIPs,\n\t\t\t\t\tTargetIPs:         tc.TargetIPs,\n\t\t\t\t\tSourcePort:        tc.SourcePort,\n\t\t\t\t\tTargetPort:        tc.TargetPort,\n\t\t\t\t\tTargetDomain:      tc.TargetDomain,\n\t\t\t\t\tOutboundGroupTags: tc.OutboundGroupTags,\n\t\t\t\t\tOutboundTag:       tc.OutboundTag,\n\t\t\t\t}\n\t\t\t\tif r := cmp.Diff(route, stat, cmpopts.IgnoreUnexported(RoutingContext{})); r != \"\" {\n\t\t\t\t\tt.Error(r)\n\t\t\t\t}\n\t\t\t\tselect { // Check that routing result has been published to statistics channel\n\t\t\t\tcase msg, received := <-sub:\n\t\t\t\t\tif route, ok := msg.(routing.Route); received && ok {\n\t\t\t\t\t\tif r := cmp.Diff(AsProtobufMessage(nil)(route), tc, cmpopts.IgnoreUnexported(RoutingContext{})); r != \"\" {\n\t\t\t\t\t\t\tt.Error(r)\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tt.Error(\"unexpected failure in receiving published routing result for testcase\", tc)\n\t\t\t\t\t}\n\t\t\t\tcase <-time.After(100 * time.Millisecond):\n\t\t\t\t\tt.Error(\"unexpected failure in receiving published routing result\", tc)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t}\n\n\t\tif err := testSimple(); err != nil {\n\t\t\terrCh <- err\n\t\t}\n\t\tif err := testOptions(); err != nil {\n\t\t\terrCh <- err\n\t\t}\n\t\terrCh <- nil // Client passed all tests successfully\n\t}()\n\n\t// Wait for goroutines to complete\n\tselect {\n\tcase <-time.After(2 * time.Second):\n\t\tt.Fatal(\"Test timeout after 2s\")\n\tcase err := <-errCh:\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "app/router/command/config.go",
    "content": "package command\n\nimport (\n\t\"strings\"\n\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/features/routing\"\n)\n\n// routingContext is an wrapper of protobuf RoutingContext as implementation of routing.Context and routing.Route.\ntype routingContext struct {\n\t*RoutingContext\n}\n\nfunc (c routingContext) GetSourceIPs() []net.IP {\n\treturn mapBytesToIPs(c.RoutingContext.GetSourceIPs())\n}\n\nfunc (c routingContext) GetSourcePort() net.Port {\n\treturn net.Port(c.RoutingContext.GetSourcePort())\n}\n\nfunc (c routingContext) GetTargetIPs() []net.IP {\n\treturn mapBytesToIPs(c.RoutingContext.GetTargetIPs())\n}\n\nfunc (c routingContext) GetTargetPort() net.Port {\n\treturn net.Port(c.RoutingContext.GetTargetPort())\n}\n\n// AsRoutingContext converts a protobuf RoutingContext into an implementation of routing.Context.\nfunc AsRoutingContext(r *RoutingContext) routing.Context {\n\treturn routingContext{r}\n}\n\n// AsRoutingRoute converts a protobuf RoutingContext into an implementation of routing.Route.\nfunc AsRoutingRoute(r *RoutingContext) routing.Route {\n\treturn routingContext{r}\n}\n\nvar fieldMap = map[string]func(*RoutingContext, routing.Route){\n\t\"inbound\":        func(s *RoutingContext, r routing.Route) { s.InboundTag = r.GetInboundTag() },\n\t\"network\":        func(s *RoutingContext, r routing.Route) { s.Network = r.GetNetwork() },\n\t\"ip_source\":      func(s *RoutingContext, r routing.Route) { s.SourceIPs = mapIPsToBytes(r.GetSourceIPs()) },\n\t\"ip_target\":      func(s *RoutingContext, r routing.Route) { s.TargetIPs = mapIPsToBytes(r.GetTargetIPs()) },\n\t\"port_source\":    func(s *RoutingContext, r routing.Route) { s.SourcePort = uint32(r.GetSourcePort()) },\n\t\"port_target\":    func(s *RoutingContext, r routing.Route) { s.TargetPort = uint32(r.GetTargetPort()) },\n\t\"domain\":         func(s *RoutingContext, r routing.Route) { s.TargetDomain = r.GetTargetDomain() },\n\t\"protocol\":       func(s *RoutingContext, r routing.Route) { s.Protocol = r.GetProtocol() },\n\t\"user\":           func(s *RoutingContext, r routing.Route) { s.User = r.GetUser() },\n\t\"attributes\":     func(s *RoutingContext, r routing.Route) { s.Attributes = r.GetAttributes() },\n\t\"outbound_group\": func(s *RoutingContext, r routing.Route) { s.OutboundGroupTags = r.GetOutboundGroupTags() },\n\t\"outbound\":       func(s *RoutingContext, r routing.Route) { s.OutboundTag = r.GetOutboundTag() },\n}\n\n// AsProtobufMessage takes selectors of fields and returns a function to convert routing.Route to protobuf RoutingContext.\nfunc AsProtobufMessage(fieldSelectors []string) func(routing.Route) *RoutingContext {\n\tinitializers := []func(*RoutingContext, routing.Route){}\n\tfor field, init := range fieldMap {\n\t\tif len(fieldSelectors) == 0 { // If selectors not set, retrieve all fields\n\t\t\tinitializers = append(initializers, init)\n\t\t\tcontinue\n\t\t}\n\t\tfor _, selector := range fieldSelectors {\n\t\t\tif strings.HasPrefix(field, selector) {\n\t\t\t\tinitializers = append(initializers, init)\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\treturn func(ctx routing.Route) *RoutingContext {\n\t\tmessage := new(RoutingContext)\n\t\tfor _, init := range initializers {\n\t\t\tinit(message, ctx)\n\t\t}\n\t\treturn message\n\t}\n}\n\nfunc mapBytesToIPs(bytes [][]byte) []net.IP {\n\tvar ips []net.IP\n\tfor _, rawIP := range bytes {\n\t\tips = append(ips, net.IP(rawIP))\n\t}\n\treturn ips\n}\n\nfunc mapIPsToBytes(ips []net.IP) [][]byte {\n\tvar bytes [][]byte\n\tfor _, ip := range ips {\n\t\tbytes = append(bytes, []byte(ip))\n\t}\n\treturn bytes\n}\n"
  },
  {
    "path": "app/router/command/errors.generated.go",
    "content": "package command\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "app/router/condition.go",
    "content": "// +build !confonly\n\npackage router\n\nimport (\n\t\"strings\"\n\n\t\"go.starlark.net/starlark\"\n\t\"go.starlark.net/syntax\"\n\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/strmatcher\"\n\t\"v2ray.com/core/features/routing\"\n)\n\ntype Condition interface {\n\tApply(ctx routing.Context) bool\n}\n\ntype ConditionChan []Condition\n\nfunc NewConditionChan() *ConditionChan {\n\tvar condChan ConditionChan = make([]Condition, 0, 8)\n\treturn &condChan\n}\n\nfunc (v *ConditionChan) Add(cond Condition) *ConditionChan {\n\t*v = append(*v, cond)\n\treturn v\n}\n\n// Apply applies all conditions registered in this chan.\nfunc (v *ConditionChan) Apply(ctx routing.Context) bool {\n\tfor _, cond := range *v {\n\t\tif !cond.Apply(ctx) {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\nfunc (v *ConditionChan) Len() int {\n\treturn len(*v)\n}\n\nvar matcherTypeMap = map[Domain_Type]strmatcher.Type{\n\tDomain_Plain:  strmatcher.Substr,\n\tDomain_Regex:  strmatcher.Regex,\n\tDomain_Domain: strmatcher.Domain,\n\tDomain_Full:   strmatcher.Full,\n}\n\nfunc domainToMatcher(domain *Domain) (strmatcher.Matcher, error) {\n\tmatcherType, f := matcherTypeMap[domain.Type]\n\tif !f {\n\t\treturn nil, newError(\"unsupported domain type\", domain.Type)\n\t}\n\n\tmatcher, err := matcherType.New(domain.Value)\n\tif err != nil {\n\t\treturn nil, newError(\"failed to create domain matcher\").Base(err)\n\t}\n\n\treturn matcher, nil\n}\n\ntype DomainMatcher struct {\n\tmatchers strmatcher.IndexMatcher\n}\n\nfunc NewDomainMatcher(domains []*Domain) (*DomainMatcher, error) {\n\tg := new(strmatcher.MatcherGroup)\n\tfor _, d := range domains {\n\t\tm, err := domainToMatcher(d)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tg.Add(m)\n\t}\n\n\treturn &DomainMatcher{\n\t\tmatchers: g,\n\t}, nil\n}\n\nfunc (m *DomainMatcher) ApplyDomain(domain string) bool {\n\treturn len(m.matchers.Match(domain)) > 0\n}\n\n// Apply implements Condition.\nfunc (m *DomainMatcher) Apply(ctx routing.Context) bool {\n\tdomain := ctx.GetTargetDomain()\n\tif len(domain) == 0 {\n\t\treturn false\n\t}\n\treturn m.ApplyDomain(domain)\n}\n\ntype MultiGeoIPMatcher struct {\n\tmatchers []*GeoIPMatcher\n\tonSource bool\n}\n\nfunc NewMultiGeoIPMatcher(geoips []*GeoIP, onSource bool) (*MultiGeoIPMatcher, error) {\n\tvar matchers []*GeoIPMatcher\n\tfor _, geoip := range geoips {\n\t\tmatcher, err := globalGeoIPContainer.Add(geoip)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tmatchers = append(matchers, matcher)\n\t}\n\n\tmatcher := &MultiGeoIPMatcher{\n\t\tmatchers: matchers,\n\t\tonSource: onSource,\n\t}\n\n\treturn matcher, nil\n}\n\n// Apply implements Condition.\nfunc (m *MultiGeoIPMatcher) Apply(ctx routing.Context) bool {\n\tvar ips []net.IP\n\tif m.onSource {\n\t\tips = ctx.GetSourceIPs()\n\t} else {\n\t\tips = ctx.GetTargetIPs()\n\t}\n\tfor _, ip := range ips {\n\t\tfor _, matcher := range m.matchers {\n\t\t\tif matcher.Match(ip) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t}\n\treturn false\n}\n\ntype PortMatcher struct {\n\tport     net.MemoryPortList\n\tonSource bool\n}\n\n// NewPortMatcher create a new port matcher that can match source or destination port\nfunc NewPortMatcher(list *net.PortList, onSource bool) *PortMatcher {\n\treturn &PortMatcher{\n\t\tport:     net.PortListFromProto(list),\n\t\tonSource: onSource,\n\t}\n}\n\n// Apply implements Condition.\nfunc (v *PortMatcher) Apply(ctx routing.Context) bool {\n\tif v.onSource {\n\t\treturn v.port.Contains(ctx.GetSourcePort())\n\t} else {\n\t\treturn v.port.Contains(ctx.GetTargetPort())\n\t}\n}\n\ntype NetworkMatcher struct {\n\tlist [8]bool\n}\n\nfunc NewNetworkMatcher(network []net.Network) NetworkMatcher {\n\tvar matcher NetworkMatcher\n\tfor _, n := range network {\n\t\tmatcher.list[int(n)] = true\n\t}\n\treturn matcher\n}\n\n// Apply implements Condition.\nfunc (v NetworkMatcher) Apply(ctx routing.Context) bool {\n\treturn v.list[int(ctx.GetNetwork())]\n}\n\ntype UserMatcher struct {\n\tuser []string\n}\n\nfunc NewUserMatcher(users []string) *UserMatcher {\n\tusersCopy := make([]string, 0, len(users))\n\tfor _, user := range users {\n\t\tif len(user) > 0 {\n\t\t\tusersCopy = append(usersCopy, user)\n\t\t}\n\t}\n\treturn &UserMatcher{\n\t\tuser: usersCopy,\n\t}\n}\n\n// Apply implements Condition.\nfunc (v *UserMatcher) Apply(ctx routing.Context) bool {\n\tuser := ctx.GetUser()\n\tif len(user) == 0 {\n\t\treturn false\n\t}\n\tfor _, u := range v.user {\n\t\tif u == user {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\ntype InboundTagMatcher struct {\n\ttags []string\n}\n\nfunc NewInboundTagMatcher(tags []string) *InboundTagMatcher {\n\ttagsCopy := make([]string, 0, len(tags))\n\tfor _, tag := range tags {\n\t\tif len(tag) > 0 {\n\t\t\ttagsCopy = append(tagsCopy, tag)\n\t\t}\n\t}\n\treturn &InboundTagMatcher{\n\t\ttags: tagsCopy,\n\t}\n}\n\n// Apply implements Condition.\nfunc (v *InboundTagMatcher) Apply(ctx routing.Context) bool {\n\ttag := ctx.GetInboundTag()\n\tif len(tag) == 0 {\n\t\treturn false\n\t}\n\tfor _, t := range v.tags {\n\t\tif t == tag {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\ntype ProtocolMatcher struct {\n\tprotocols []string\n}\n\nfunc NewProtocolMatcher(protocols []string) *ProtocolMatcher {\n\tpCopy := make([]string, 0, len(protocols))\n\n\tfor _, p := range protocols {\n\t\tif len(p) > 0 {\n\t\t\tpCopy = append(pCopy, p)\n\t\t}\n\t}\n\n\treturn &ProtocolMatcher{\n\t\tprotocols: pCopy,\n\t}\n}\n\n// Apply implements Condition.\nfunc (m *ProtocolMatcher) Apply(ctx routing.Context) bool {\n\tprotocol := ctx.GetProtocol()\n\tif len(protocol) == 0 {\n\t\treturn false\n\t}\n\tfor _, p := range m.protocols {\n\t\tif strings.HasPrefix(protocol, p) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\ntype AttributeMatcher struct {\n\tprogram *starlark.Program\n}\n\nfunc NewAttributeMatcher(code string) (*AttributeMatcher, error) {\n\tstarFile, err := syntax.Parse(\"attr.star\", \"satisfied=(\"+code+\")\", 0)\n\tif err != nil {\n\t\treturn nil, newError(\"attr rule\").Base(err)\n\t}\n\tp, err := starlark.FileProgram(starFile, func(name string) bool {\n\t\treturn name == \"attrs\"\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &AttributeMatcher{\n\t\tprogram: p,\n\t}, nil\n}\n\n// Match implements attributes matching.\nfunc (m *AttributeMatcher) Match(attrs map[string]string) bool {\n\tattrsDict := new(starlark.Dict)\n\tfor key, value := range attrs {\n\t\tattrsDict.SetKey(starlark.String(key), starlark.String(value))\n\t}\n\n\tpredefined := make(starlark.StringDict)\n\tpredefined[\"attrs\"] = attrsDict\n\n\tthread := &starlark.Thread{\n\t\tName: \"matcher\",\n\t}\n\tresults, err := m.program.Init(thread, predefined)\n\tif err != nil {\n\t\tnewError(\"attr matcher\").Base(err).WriteToLog()\n\t}\n\tsatisfied := results[\"satisfied\"]\n\treturn satisfied != nil && bool(satisfied.Truth())\n}\n\n// Apply implements Condition.\nfunc (m *AttributeMatcher) Apply(ctx routing.Context) bool {\n\tattributes := ctx.GetAttributes()\n\tif attributes == nil {\n\t\treturn false\n\t}\n\treturn m.Match(attributes)\n}\n"
  },
  {
    "path": "app/router/condition_geoip.go",
    "content": "// +build !confonly\n\npackage router\n\nimport (\n\t\"encoding/binary\"\n\t\"sort\"\n\n\t\"v2ray.com/core/common/net\"\n)\n\ntype ipv6 struct {\n\ta uint64\n\tb uint64\n}\n\ntype GeoIPMatcher struct {\n\tcountryCode string\n\tip4         []uint32\n\tprefix4     []uint8\n\tip6         []ipv6\n\tprefix6     []uint8\n}\n\nfunc normalize4(ip uint32, prefix uint8) uint32 {\n\treturn (ip >> (32 - prefix)) << (32 - prefix)\n}\n\nfunc normalize6(ip ipv6, prefix uint8) ipv6 {\n\tif prefix <= 64 {\n\t\tip.a = (ip.a >> (64 - prefix)) << (64 - prefix)\n\t\tip.b = 0\n\t} else {\n\t\tip.b = (ip.b >> (128 - prefix)) << (128 - prefix)\n\t}\n\treturn ip\n}\n\nfunc (m *GeoIPMatcher) Init(cidrs []*CIDR) error {\n\tip4Count := 0\n\tip6Count := 0\n\n\tfor _, cidr := range cidrs {\n\t\tip := cidr.Ip\n\t\tswitch len(ip) {\n\t\tcase 4:\n\t\t\tip4Count++\n\t\tcase 16:\n\t\t\tip6Count++\n\t\tdefault:\n\t\t\treturn newError(\"unexpect ip length: \", len(ip))\n\t\t}\n\t}\n\n\tcidrList := CIDRList(cidrs)\n\tsort.Sort(&cidrList)\n\n\tm.ip4 = make([]uint32, 0, ip4Count)\n\tm.prefix4 = make([]uint8, 0, ip4Count)\n\tm.ip6 = make([]ipv6, 0, ip6Count)\n\tm.prefix6 = make([]uint8, 0, ip6Count)\n\n\tfor _, cidr := range cidrs {\n\t\tip := cidr.Ip\n\t\tprefix := uint8(cidr.Prefix)\n\t\tswitch len(ip) {\n\t\tcase 4:\n\t\t\tm.ip4 = append(m.ip4, normalize4(binary.BigEndian.Uint32(ip), prefix))\n\t\t\tm.prefix4 = append(m.prefix4, prefix)\n\t\tcase 16:\n\t\t\tip6 := ipv6{\n\t\t\t\ta: binary.BigEndian.Uint64(ip[0:8]),\n\t\t\t\tb: binary.BigEndian.Uint64(ip[8:16]),\n\t\t\t}\n\t\t\tip6 = normalize6(ip6, prefix)\n\n\t\t\tm.ip6 = append(m.ip6, ip6)\n\t\t\tm.prefix6 = append(m.prefix6, prefix)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (m *GeoIPMatcher) match4(ip uint32) bool {\n\tif len(m.ip4) == 0 {\n\t\treturn false\n\t}\n\n\tif ip < m.ip4[0] {\n\t\treturn false\n\t}\n\n\tsize := uint32(len(m.ip4))\n\tl := uint32(0)\n\tr := size\n\tfor l < r {\n\t\tx := ((l + r) >> 1)\n\t\tif ip < m.ip4[x] {\n\t\t\tr = x\n\t\t\tcontinue\n\t\t}\n\n\t\tnip := normalize4(ip, m.prefix4[x])\n\t\tif nip == m.ip4[x] {\n\t\t\treturn true\n\t\t}\n\n\t\tl = x + 1\n\t}\n\n\treturn l > 0 && normalize4(ip, m.prefix4[l-1]) == m.ip4[l-1]\n}\n\nfunc less6(a ipv6, b ipv6) bool {\n\treturn a.a < b.a || (a.a == b.a && a.b < b.b)\n}\n\nfunc (m *GeoIPMatcher) match6(ip ipv6) bool {\n\tif len(m.ip6) == 0 {\n\t\treturn false\n\t}\n\n\tif less6(ip, m.ip6[0]) {\n\t\treturn false\n\t}\n\n\tsize := uint32(len(m.ip6))\n\tl := uint32(0)\n\tr := size\n\tfor l < r {\n\t\tx := (l + r) / 2\n\t\tif less6(ip, m.ip6[x]) {\n\t\t\tr = x\n\t\t\tcontinue\n\t\t}\n\n\t\tif normalize6(ip, m.prefix6[x]) == m.ip6[x] {\n\t\t\treturn true\n\t\t}\n\n\t\tl = x + 1\n\t}\n\n\treturn l > 0 && normalize6(ip, m.prefix6[l-1]) == m.ip6[l-1]\n}\n\n// Match returns true if the given ip is included by the GeoIP.\nfunc (m *GeoIPMatcher) Match(ip net.IP) bool {\n\tswitch len(ip) {\n\tcase 4:\n\t\treturn m.match4(binary.BigEndian.Uint32(ip))\n\tcase 16:\n\t\treturn m.match6(ipv6{\n\t\t\ta: binary.BigEndian.Uint64(ip[0:8]),\n\t\t\tb: binary.BigEndian.Uint64(ip[8:16]),\n\t\t})\n\tdefault:\n\t\treturn false\n\t}\n}\n\n// GeoIPMatcherContainer is a container for GeoIPMatchers. It keeps unique copies of GeoIPMatcher by country code.\ntype GeoIPMatcherContainer struct {\n\tmatchers []*GeoIPMatcher\n}\n\n// Add adds a new GeoIP set into the container.\n// If the country code of GeoIP is not empty, GeoIPMatcherContainer will try to find an existing one, instead of adding a new one.\nfunc (c *GeoIPMatcherContainer) Add(geoip *GeoIP) (*GeoIPMatcher, error) {\n\tif len(geoip.CountryCode) > 0 {\n\t\tfor _, m := range c.matchers {\n\t\t\tif m.countryCode == geoip.CountryCode {\n\t\t\t\treturn m, nil\n\t\t\t}\n\t\t}\n\t}\n\n\tm := &GeoIPMatcher{\n\t\tcountryCode: geoip.CountryCode,\n\t}\n\tif err := m.Init(geoip.Cidr); err != nil {\n\t\treturn nil, err\n\t}\n\tif len(geoip.CountryCode) > 0 {\n\t\tc.matchers = append(c.matchers, m)\n\t}\n\treturn m, nil\n}\n\nvar (\n\tglobalGeoIPContainer GeoIPMatcherContainer\n)\n"
  },
  {
    "path": "app/router/condition_geoip_test.go",
    "content": "package router_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\tproto \"github.com/golang/protobuf/proto\"\n\t\"v2ray.com/core/app/router\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/platform\"\n\t\"v2ray.com/core/common/platform/filesystem\"\n)\n\nfunc init() {\n\twd, err := os.Getwd()\n\tcommon.Must(err)\n\n\tif _, err := os.Stat(platform.GetAssetLocation(\"geoip.dat\")); err != nil && os.IsNotExist(err) {\n\t\tcommon.Must(filesystem.CopyFile(platform.GetAssetLocation(\"geoip.dat\"), filepath.Join(wd, \"..\", \"..\", \"release\", \"config\", \"geoip.dat\")))\n\t}\n\tif _, err := os.Stat(platform.GetAssetLocation(\"geosite.dat\")); err != nil && os.IsNotExist(err) {\n\t\tcommon.Must(filesystem.CopyFile(platform.GetAssetLocation(\"geosite.dat\"), filepath.Join(wd, \"..\", \"..\", \"release\", \"config\", \"geosite.dat\")))\n\t}\n}\n\nfunc TestGeoIPMatcherContainer(t *testing.T) {\n\tcontainer := &router.GeoIPMatcherContainer{}\n\n\tm1, err := container.Add(&router.GeoIP{\n\t\tCountryCode: \"CN\",\n\t})\n\tcommon.Must(err)\n\n\tm2, err := container.Add(&router.GeoIP{\n\t\tCountryCode: \"US\",\n\t})\n\tcommon.Must(err)\n\n\tm3, err := container.Add(&router.GeoIP{\n\t\tCountryCode: \"CN\",\n\t})\n\tcommon.Must(err)\n\n\tif m1 != m3 {\n\t\tt.Error(\"expect same matcher for same geoip, but not\")\n\t}\n\n\tif m1 == m2 {\n\t\tt.Error(\"expect different matcher for different geoip, but actually same\")\n\t}\n}\n\nfunc TestGeoIPMatcher(t *testing.T) {\n\tcidrList := router.CIDRList{\n\t\t{Ip: []byte{0, 0, 0, 0}, Prefix: 8},\n\t\t{Ip: []byte{10, 0, 0, 0}, Prefix: 8},\n\t\t{Ip: []byte{100, 64, 0, 0}, Prefix: 10},\n\t\t{Ip: []byte{127, 0, 0, 0}, Prefix: 8},\n\t\t{Ip: []byte{169, 254, 0, 0}, Prefix: 16},\n\t\t{Ip: []byte{172, 16, 0, 0}, Prefix: 12},\n\t\t{Ip: []byte{192, 0, 0, 0}, Prefix: 24},\n\t\t{Ip: []byte{192, 0, 2, 0}, Prefix: 24},\n\t\t{Ip: []byte{192, 168, 0, 0}, Prefix: 16},\n\t\t{Ip: []byte{192, 18, 0, 0}, Prefix: 15},\n\t\t{Ip: []byte{198, 51, 100, 0}, Prefix: 24},\n\t\t{Ip: []byte{203, 0, 113, 0}, Prefix: 24},\n\t\t{Ip: []byte{8, 8, 8, 8}, Prefix: 32},\n\t\t{Ip: []byte{91, 108, 4, 0}, Prefix: 16},\n\t}\n\n\tmatcher := &router.GeoIPMatcher{}\n\tcommon.Must(matcher.Init(cidrList))\n\n\ttestCases := []struct {\n\t\tInput  string\n\t\tOutput bool\n\t}{\n\t\t{\n\t\t\tInput:  \"192.168.1.1\",\n\t\t\tOutput: true,\n\t\t},\n\t\t{\n\t\t\tInput:  \"192.0.0.0\",\n\t\t\tOutput: true,\n\t\t},\n\t\t{\n\t\t\tInput:  \"192.0.1.0\",\n\t\t\tOutput: false,\n\t\t}, {\n\t\t\tInput:  \"0.1.0.0\",\n\t\t\tOutput: true,\n\t\t},\n\t\t{\n\t\t\tInput:  \"1.0.0.1\",\n\t\t\tOutput: false,\n\t\t},\n\t\t{\n\t\t\tInput:  \"8.8.8.7\",\n\t\t\tOutput: false,\n\t\t},\n\t\t{\n\t\t\tInput:  \"8.8.8.8\",\n\t\t\tOutput: true,\n\t\t},\n\t\t{\n\t\t\tInput:  \"2001:cdba::3257:9652\",\n\t\t\tOutput: false,\n\t\t},\n\t\t{\n\t\t\tInput:  \"91.108.255.254\",\n\t\t\tOutput: true,\n\t\t},\n\t}\n\n\tfor _, testCase := range testCases {\n\t\tip := net.ParseAddress(testCase.Input).IP()\n\t\tactual := matcher.Match(ip)\n\t\tif actual != testCase.Output {\n\t\t\tt.Error(\"expect input\", testCase.Input, \"to be\", testCase.Output, \", but actually\", actual)\n\t\t}\n\t}\n}\n\nfunc TestGeoIPMatcher4CN(t *testing.T) {\n\tips, err := loadGeoIP(\"CN\")\n\tcommon.Must(err)\n\n\tmatcher := &router.GeoIPMatcher{}\n\tcommon.Must(matcher.Init(ips))\n\n\tif matcher.Match([]byte{8, 8, 8, 8}) {\n\t\tt.Error(\"expect CN geoip doesn't contain 8.8.8.8, but actually does\")\n\t}\n}\n\nfunc TestGeoIPMatcher6US(t *testing.T) {\n\tips, err := loadGeoIP(\"US\")\n\tcommon.Must(err)\n\n\tmatcher := &router.GeoIPMatcher{}\n\tcommon.Must(matcher.Init(ips))\n\n\tif !matcher.Match(net.ParseAddress(\"2001:4860:4860::8888\").IP()) {\n\t\tt.Error(\"expect US geoip contain 2001:4860:4860::8888, but actually not\")\n\t}\n}\n\nfunc loadGeoIP(country string) ([]*router.CIDR, error) {\n\tgeoipBytes, err := filesystem.ReadAsset(\"geoip.dat\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar geoipList router.GeoIPList\n\tif err := proto.Unmarshal(geoipBytes, &geoipList); err != nil {\n\t\treturn nil, err\n\t}\n\n\tfor _, geoip := range geoipList.Entry {\n\t\tif geoip.CountryCode == country {\n\t\t\treturn geoip.Cidr, nil\n\t\t}\n\t}\n\n\tpanic(\"country not found: \" + country)\n}\n\nfunc BenchmarkGeoIPMatcher4CN(b *testing.B) {\n\tips, err := loadGeoIP(\"CN\")\n\tcommon.Must(err)\n\n\tmatcher := &router.GeoIPMatcher{}\n\tcommon.Must(matcher.Init(ips))\n\n\tb.ResetTimer()\n\n\tfor i := 0; i < b.N; i++ {\n\t\t_ = matcher.Match([]byte{8, 8, 8, 8})\n\t}\n}\n\nfunc BenchmarkGeoIPMatcher6US(b *testing.B) {\n\tips, err := loadGeoIP(\"US\")\n\tcommon.Must(err)\n\n\tmatcher := &router.GeoIPMatcher{}\n\tcommon.Must(matcher.Init(ips))\n\n\tb.ResetTimer()\n\n\tfor i := 0; i < b.N; i++ {\n\t\t_ = matcher.Match(net.ParseAddress(\"2001:4860:4860::8888\").IP())\n\t}\n}\n"
  },
  {
    "path": "app/router/condition_test.go",
    "content": "package router_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"testing\"\n\n\tproto \"github.com/golang/protobuf/proto\"\n\n\t. \"v2ray.com/core/app/router\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/errors\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/platform\"\n\t\"v2ray.com/core/common/platform/filesystem\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/protocol/http\"\n\t\"v2ray.com/core/common/session\"\n\t\"v2ray.com/core/features/routing\"\n\trouting_session \"v2ray.com/core/features/routing/session\"\n)\n\nfunc init() {\n\twd, err := os.Getwd()\n\tcommon.Must(err)\n\n\tif _, err := os.Stat(platform.GetAssetLocation(\"geoip.dat\")); err != nil && os.IsNotExist(err) {\n\t\tcommon.Must(filesystem.CopyFile(platform.GetAssetLocation(\"geoip.dat\"), filepath.Join(wd, \"..\", \"..\", \"release\", \"config\", \"geoip.dat\")))\n\t}\n\tif _, err := os.Stat(platform.GetAssetLocation(\"geosite.dat\")); err != nil && os.IsNotExist(err) {\n\t\tcommon.Must(filesystem.CopyFile(platform.GetAssetLocation(\"geosite.dat\"), filepath.Join(wd, \"..\", \"..\", \"release\", \"config\", \"geosite.dat\")))\n\t}\n}\n\nfunc withBackground() routing.Context {\n\treturn &routing_session.Context{}\n}\n\nfunc withOutbound(outbound *session.Outbound) routing.Context {\n\treturn &routing_session.Context{Outbound: outbound}\n}\n\nfunc withInbound(inbound *session.Inbound) routing.Context {\n\treturn &routing_session.Context{Inbound: inbound}\n}\n\nfunc withContent(content *session.Content) routing.Context {\n\treturn &routing_session.Context{Content: content}\n}\n\nfunc TestRoutingRule(t *testing.T) {\n\ttype ruleTest struct {\n\t\tinput  routing.Context\n\t\toutput bool\n\t}\n\n\tcases := []struct {\n\t\trule *RoutingRule\n\t\ttest []ruleTest\n\t}{\n\t\t{\n\t\t\trule: &RoutingRule{\n\t\t\t\tDomain: []*Domain{\n\t\t\t\t\t{\n\t\t\t\t\t\tValue: \"v2ray.com\",\n\t\t\t\t\t\tType:  Domain_Plain,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tValue: \"google.com\",\n\t\t\t\t\t\tType:  Domain_Domain,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tValue: \"^facebook\\\\.com$\",\n\t\t\t\t\t\tType:  Domain_Regex,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\ttest: []ruleTest{\n\t\t\t\t{\n\t\t\t\t\tinput:  withOutbound(&session.Outbound{Target: net.TCPDestination(net.DomainAddress(\"v2ray.com\"), 80)}),\n\t\t\t\t\toutput: true,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tinput:  withOutbound(&session.Outbound{Target: net.TCPDestination(net.DomainAddress(\"www.v2ray.com.www\"), 80)}),\n\t\t\t\t\toutput: true,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tinput:  withOutbound(&session.Outbound{Target: net.TCPDestination(net.DomainAddress(\"v2ray.co\"), 80)}),\n\t\t\t\t\toutput: false,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tinput:  withOutbound(&session.Outbound{Target: net.TCPDestination(net.DomainAddress(\"www.google.com\"), 80)}),\n\t\t\t\t\toutput: true,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tinput:  withOutbound(&session.Outbound{Target: net.TCPDestination(net.DomainAddress(\"facebook.com\"), 80)}),\n\t\t\t\t\toutput: true,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tinput:  withOutbound(&session.Outbound{Target: net.TCPDestination(net.DomainAddress(\"www.facebook.com\"), 80)}),\n\t\t\t\t\toutput: false,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tinput:  withBackground(),\n\t\t\t\t\toutput: false,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\trule: &RoutingRule{\n\t\t\t\tCidr: []*CIDR{\n\t\t\t\t\t{\n\t\t\t\t\t\tIp:     []byte{8, 8, 8, 8},\n\t\t\t\t\t\tPrefix: 32,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tIp:     []byte{8, 8, 8, 8},\n\t\t\t\t\t\tPrefix: 32,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tIp:     net.ParseAddress(\"2001:0db8:85a3:0000:0000:8a2e:0370:7334\").IP(),\n\t\t\t\t\t\tPrefix: 128,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\ttest: []ruleTest{\n\t\t\t\t{\n\t\t\t\t\tinput:  withOutbound(&session.Outbound{Target: net.TCPDestination(net.ParseAddress(\"8.8.8.8\"), 80)}),\n\t\t\t\t\toutput: true,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tinput:  withOutbound(&session.Outbound{Target: net.TCPDestination(net.ParseAddress(\"8.8.4.4\"), 80)}),\n\t\t\t\t\toutput: false,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tinput:  withOutbound(&session.Outbound{Target: net.TCPDestination(net.ParseAddress(\"2001:0db8:85a3:0000:0000:8a2e:0370:7334\"), 80)}),\n\t\t\t\t\toutput: true,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tinput:  withBackground(),\n\t\t\t\t\toutput: false,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\trule: &RoutingRule{\n\t\t\t\tGeoip: []*GeoIP{\n\t\t\t\t\t{\n\t\t\t\t\t\tCidr: []*CIDR{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tIp:     []byte{8, 8, 8, 8},\n\t\t\t\t\t\t\t\tPrefix: 32,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tIp:     []byte{8, 8, 8, 8},\n\t\t\t\t\t\t\t\tPrefix: 32,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tIp:     net.ParseAddress(\"2001:0db8:85a3:0000:0000:8a2e:0370:7334\").IP(),\n\t\t\t\t\t\t\t\tPrefix: 128,\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\ttest: []ruleTest{\n\t\t\t\t{\n\t\t\t\t\tinput:  withOutbound(&session.Outbound{Target: net.TCPDestination(net.ParseAddress(\"8.8.8.8\"), 80)}),\n\t\t\t\t\toutput: true,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tinput:  withOutbound(&session.Outbound{Target: net.TCPDestination(net.ParseAddress(\"8.8.4.4\"), 80)}),\n\t\t\t\t\toutput: false,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tinput:  withOutbound(&session.Outbound{Target: net.TCPDestination(net.ParseAddress(\"2001:0db8:85a3:0000:0000:8a2e:0370:7334\"), 80)}),\n\t\t\t\t\toutput: true,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tinput:  withBackground(),\n\t\t\t\t\toutput: false,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\trule: &RoutingRule{\n\t\t\t\tSourceCidr: []*CIDR{\n\t\t\t\t\t{\n\t\t\t\t\t\tIp:     []byte{192, 168, 0, 0},\n\t\t\t\t\t\tPrefix: 16,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\ttest: []ruleTest{\n\t\t\t\t{\n\t\t\t\t\tinput:  withInbound(&session.Inbound{Source: net.TCPDestination(net.ParseAddress(\"192.168.0.1\"), 80)}),\n\t\t\t\t\toutput: true,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tinput:  withInbound(&session.Inbound{Source: net.TCPDestination(net.ParseAddress(\"10.0.0.1\"), 80)}),\n\t\t\t\t\toutput: false,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\trule: &RoutingRule{\n\t\t\t\tUserEmail: []string{\n\t\t\t\t\t\"admin@v2ray.com\",\n\t\t\t\t},\n\t\t\t},\n\t\t\ttest: []ruleTest{\n\t\t\t\t{\n\t\t\t\t\tinput:  withInbound(&session.Inbound{User: &protocol.MemoryUser{Email: \"admin@v2ray.com\"}}),\n\t\t\t\t\toutput: true,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tinput:  withInbound(&session.Inbound{User: &protocol.MemoryUser{Email: \"love@v2ray.com\"}}),\n\t\t\t\t\toutput: false,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tinput:  withBackground(),\n\t\t\t\t\toutput: false,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\trule: &RoutingRule{\n\t\t\t\tProtocol: []string{\"http\"},\n\t\t\t},\n\t\t\ttest: []ruleTest{\n\t\t\t\t{\n\t\t\t\t\tinput:  withContent(&session.Content{Protocol: (&http.SniffHeader{}).Protocol()}),\n\t\t\t\t\toutput: true,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\trule: &RoutingRule{\n\t\t\t\tInboundTag: []string{\"test\", \"test1\"},\n\t\t\t},\n\t\t\ttest: []ruleTest{\n\t\t\t\t{\n\t\t\t\t\tinput:  withInbound(&session.Inbound{Tag: \"test\"}),\n\t\t\t\t\toutput: true,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tinput:  withInbound(&session.Inbound{Tag: \"test2\"}),\n\t\t\t\t\toutput: false,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\trule: &RoutingRule{\n\t\t\t\tPortList: &net.PortList{\n\t\t\t\t\tRange: []*net.PortRange{\n\t\t\t\t\t\t{From: 443, To: 443},\n\t\t\t\t\t\t{From: 1000, To: 1100},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\ttest: []ruleTest{\n\t\t\t\t{\n\t\t\t\t\tinput:  withOutbound(&session.Outbound{Target: net.TCPDestination(net.LocalHostIP, 443)}),\n\t\t\t\t\toutput: true,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tinput:  withOutbound(&session.Outbound{Target: net.TCPDestination(net.LocalHostIP, 1100)}),\n\t\t\t\t\toutput: true,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tinput:  withOutbound(&session.Outbound{Target: net.TCPDestination(net.LocalHostIP, 1005)}),\n\t\t\t\t\toutput: true,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tinput:  withOutbound(&session.Outbound{Target: net.TCPDestination(net.LocalHostIP, 53)}),\n\t\t\t\t\toutput: false,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\trule: &RoutingRule{\n\t\t\t\tSourcePortList: &net.PortList{\n\t\t\t\t\tRange: []*net.PortRange{\n\t\t\t\t\t\t{From: 123, To: 123},\n\t\t\t\t\t\t{From: 9993, To: 9999},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\ttest: []ruleTest{\n\t\t\t\t{\n\t\t\t\t\tinput:  withInbound(&session.Inbound{Source: net.UDPDestination(net.LocalHostIP, 123)}),\n\t\t\t\t\toutput: true,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tinput:  withInbound(&session.Inbound{Source: net.UDPDestination(net.LocalHostIP, 9999)}),\n\t\t\t\t\toutput: true,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tinput:  withInbound(&session.Inbound{Source: net.UDPDestination(net.LocalHostIP, 9994)}),\n\t\t\t\t\toutput: true,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tinput:  withInbound(&session.Inbound{Source: net.UDPDestination(net.LocalHostIP, 53)}),\n\t\t\t\t\toutput: false,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\trule: &RoutingRule{\n\t\t\t\tProtocol:   []string{\"http\"},\n\t\t\t\tAttributes: \"attrs[':path'].startswith('/test')\",\n\t\t\t},\n\t\t\ttest: []ruleTest{\n\t\t\t\t{\n\t\t\t\t\tinput:  withContent(&session.Content{Protocol: \"http/1.1\", Attributes: map[string]string{\":path\": \"/test/1\"}}),\n\t\t\t\t\toutput: true,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, test := range cases {\n\t\tcond, err := test.rule.BuildCondition()\n\t\tcommon.Must(err)\n\n\t\tfor _, subtest := range test.test {\n\t\t\tactual := cond.Apply(subtest.input)\n\t\t\tif actual != subtest.output {\n\t\t\t\tt.Error(\"test case failed: \", subtest.input, \" expected \", subtest.output, \" but got \", actual)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc loadGeoSite(country string) ([]*Domain, error) {\n\tgeositeBytes, err := filesystem.ReadAsset(\"geosite.dat\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar geositeList GeoSiteList\n\tif err := proto.Unmarshal(geositeBytes, &geositeList); err != nil {\n\t\treturn nil, err\n\t}\n\n\tfor _, site := range geositeList.Entry {\n\t\tif site.CountryCode == country {\n\t\t\treturn site.Domain, nil\n\t\t}\n\t}\n\n\treturn nil, errors.New(\"country not found: \" + country)\n}\n\nfunc TestChinaSites(t *testing.T) {\n\tdomains, err := loadGeoSite(\"CN\")\n\tcommon.Must(err)\n\n\tmatcher, err := NewDomainMatcher(domains)\n\tcommon.Must(err)\n\n\ttype TestCase struct {\n\t\tDomain string\n\t\tOutput bool\n\t}\n\ttestCases := []TestCase{\n\t\t{\n\t\t\tDomain: \"163.com\",\n\t\t\tOutput: true,\n\t\t},\n\t\t{\n\t\t\tDomain: \"163.com\",\n\t\t\tOutput: true,\n\t\t},\n\t\t{\n\t\t\tDomain: \"164.com\",\n\t\t\tOutput: false,\n\t\t},\n\t\t{\n\t\t\tDomain: \"164.com\",\n\t\t\tOutput: false,\n\t\t},\n\t}\n\n\tfor i := 0; i < 1024; i++ {\n\t\ttestCases = append(testCases, TestCase{Domain: strconv.Itoa(i) + \".not-exists.com\", Output: false})\n\t}\n\n\tfor _, testCase := range testCases {\n\t\tr := matcher.ApplyDomain(testCase.Domain)\n\t\tif r != testCase.Output {\n\t\t\tt.Error(\"expected output \", testCase.Output, \" for domain \", testCase.Domain, \" but got \", r)\n\t\t}\n\t}\n}\n\nfunc BenchmarkMultiGeoIPMatcher(b *testing.B) {\n\tvar geoips []*GeoIP\n\n\t{\n\t\tips, err := loadGeoIP(\"CN\")\n\t\tcommon.Must(err)\n\t\tgeoips = append(geoips, &GeoIP{\n\t\t\tCountryCode: \"CN\",\n\t\t\tCidr:        ips,\n\t\t})\n\t}\n\n\t{\n\t\tips, err := loadGeoIP(\"JP\")\n\t\tcommon.Must(err)\n\t\tgeoips = append(geoips, &GeoIP{\n\t\t\tCountryCode: \"JP\",\n\t\t\tCidr:        ips,\n\t\t})\n\t}\n\n\t{\n\t\tips, err := loadGeoIP(\"CA\")\n\t\tcommon.Must(err)\n\t\tgeoips = append(geoips, &GeoIP{\n\t\t\tCountryCode: \"CA\",\n\t\t\tCidr:        ips,\n\t\t})\n\t}\n\n\t{\n\t\tips, err := loadGeoIP(\"US\")\n\t\tcommon.Must(err)\n\t\tgeoips = append(geoips, &GeoIP{\n\t\t\tCountryCode: \"US\",\n\t\t\tCidr:        ips,\n\t\t})\n\t}\n\n\tmatcher, err := NewMultiGeoIPMatcher(geoips, false)\n\tcommon.Must(err)\n\n\tctx := withOutbound(&session.Outbound{Target: net.TCPDestination(net.ParseAddress(\"8.8.8.8\"), 80)})\n\n\tb.ResetTimer()\n\n\tfor i := 0; i < b.N; i++ {\n\t\t_ = matcher.Apply(ctx)\n\t}\n}\n"
  },
  {
    "path": "app/router/config.go",
    "content": "// +build !confonly\n\npackage router\n\nimport (\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/features/outbound\"\n\t\"v2ray.com/core/features/routing\"\n)\n\n// CIDRList is an alias of []*CIDR to provide sort.Interface.\ntype CIDRList []*CIDR\n\n// Len implements sort.Interface.\nfunc (l *CIDRList) Len() int {\n\treturn len(*l)\n}\n\n// Less implements sort.Interface.\nfunc (l *CIDRList) Less(i int, j int) bool {\n\tci := (*l)[i]\n\tcj := (*l)[j]\n\n\tif len(ci.Ip) < len(cj.Ip) {\n\t\treturn true\n\t}\n\n\tif len(ci.Ip) > len(cj.Ip) {\n\t\treturn false\n\t}\n\n\tfor k := 0; k < len(ci.Ip); k++ {\n\t\tif ci.Ip[k] < cj.Ip[k] {\n\t\t\treturn true\n\t\t}\n\n\t\tif ci.Ip[k] > cj.Ip[k] {\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn ci.Prefix < cj.Prefix\n}\n\n// Swap implements sort.Interface.\nfunc (l *CIDRList) Swap(i int, j int) {\n\t(*l)[i], (*l)[j] = (*l)[j], (*l)[i]\n}\n\ntype Rule struct {\n\tTag       string\n\tBalancer  *Balancer\n\tCondition Condition\n}\n\nfunc (r *Rule) GetTag() (string, error) {\n\tif r.Balancer != nil {\n\t\treturn r.Balancer.PickOutbound()\n\t}\n\treturn r.Tag, nil\n}\n\n// Apply checks rule matching of current routing context.\nfunc (r *Rule) Apply(ctx routing.Context) bool {\n\treturn r.Condition.Apply(ctx)\n}\n\nfunc (rr *RoutingRule) BuildCondition() (Condition, error) {\n\tconds := NewConditionChan()\n\n\tif len(rr.Domain) > 0 {\n\t\tmatcher, err := NewDomainMatcher(rr.Domain)\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"failed to build domain condition\").Base(err)\n\t\t}\n\t\tconds.Add(matcher)\n\t}\n\n\tif len(rr.UserEmail) > 0 {\n\t\tconds.Add(NewUserMatcher(rr.UserEmail))\n\t}\n\n\tif len(rr.InboundTag) > 0 {\n\t\tconds.Add(NewInboundTagMatcher(rr.InboundTag))\n\t}\n\n\tif rr.PortList != nil {\n\t\tconds.Add(NewPortMatcher(rr.PortList, false))\n\t} else if rr.PortRange != nil {\n\t\tconds.Add(NewPortMatcher(&net.PortList{Range: []*net.PortRange{rr.PortRange}}, false))\n\t}\n\n\tif rr.SourcePortList != nil {\n\t\tconds.Add(NewPortMatcher(rr.SourcePortList, true))\n\t}\n\n\tif len(rr.Networks) > 0 {\n\t\tconds.Add(NewNetworkMatcher(rr.Networks))\n\t} else if rr.NetworkList != nil {\n\t\tconds.Add(NewNetworkMatcher(rr.NetworkList.Network))\n\t}\n\n\tif len(rr.Geoip) > 0 {\n\t\tcond, err := NewMultiGeoIPMatcher(rr.Geoip, false)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tconds.Add(cond)\n\t} else if len(rr.Cidr) > 0 {\n\t\tcond, err := NewMultiGeoIPMatcher([]*GeoIP{{Cidr: rr.Cidr}}, false)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tconds.Add(cond)\n\t}\n\n\tif len(rr.SourceGeoip) > 0 {\n\t\tcond, err := NewMultiGeoIPMatcher(rr.SourceGeoip, true)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tconds.Add(cond)\n\t} else if len(rr.SourceCidr) > 0 {\n\t\tcond, err := NewMultiGeoIPMatcher([]*GeoIP{{Cidr: rr.SourceCidr}}, true)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tconds.Add(cond)\n\t}\n\n\tif len(rr.Protocol) > 0 {\n\t\tconds.Add(NewProtocolMatcher(rr.Protocol))\n\t}\n\n\tif len(rr.Attributes) > 0 {\n\t\tcond, err := NewAttributeMatcher(rr.Attributes)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tconds.Add(cond)\n\t}\n\n\tif conds.Len() == 0 {\n\t\treturn nil, newError(\"this rule has no effective fields\").AtWarning()\n\t}\n\n\treturn conds, nil\n}\n\nfunc (br *BalancingRule) Build(ohm outbound.Manager) (*Balancer, error) {\n\treturn &Balancer{\n\t\tselectors: br.OutboundSelector,\n\t\tstrategy:  &RandomStrategy{},\n\t\tohm:       ohm,\n\t}, nil\n}\n"
  },
  {
    "path": "app/router/config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: app/router/config.proto\n\npackage router\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n\tnet \"v2ray.com/core/common/net\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\n// Type of domain value.\ntype Domain_Type int32\n\nconst (\n\t// The value is used as is.\n\tDomain_Plain Domain_Type = 0\n\t// The value is used as a regular expression.\n\tDomain_Regex Domain_Type = 1\n\t// The value is a root domain.\n\tDomain_Domain Domain_Type = 2\n\t// The value is a domain.\n\tDomain_Full Domain_Type = 3\n)\n\n// Enum value maps for Domain_Type.\nvar (\n\tDomain_Type_name = map[int32]string{\n\t\t0: \"Plain\",\n\t\t1: \"Regex\",\n\t\t2: \"Domain\",\n\t\t3: \"Full\",\n\t}\n\tDomain_Type_value = map[string]int32{\n\t\t\"Plain\":  0,\n\t\t\"Regex\":  1,\n\t\t\"Domain\": 2,\n\t\t\"Full\":   3,\n\t}\n)\n\nfunc (x Domain_Type) Enum() *Domain_Type {\n\tp := new(Domain_Type)\n\t*p = x\n\treturn p\n}\n\nfunc (x Domain_Type) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (Domain_Type) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_app_router_config_proto_enumTypes[0].Descriptor()\n}\n\nfunc (Domain_Type) Type() protoreflect.EnumType {\n\treturn &file_app_router_config_proto_enumTypes[0]\n}\n\nfunc (x Domain_Type) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use Domain_Type.Descriptor instead.\nfunc (Domain_Type) EnumDescriptor() ([]byte, []int) {\n\treturn file_app_router_config_proto_rawDescGZIP(), []int{0, 0}\n}\n\ntype Config_DomainStrategy int32\n\nconst (\n\t// Use domain as is.\n\tConfig_AsIs Config_DomainStrategy = 0\n\t// Always resolve IP for domains.\n\tConfig_UseIp Config_DomainStrategy = 1\n\t// Resolve to IP if the domain doesn't match any rules.\n\tConfig_IpIfNonMatch Config_DomainStrategy = 2\n\t// Resolve to IP if any rule requires IP matching.\n\tConfig_IpOnDemand Config_DomainStrategy = 3\n)\n\n// Enum value maps for Config_DomainStrategy.\nvar (\n\tConfig_DomainStrategy_name = map[int32]string{\n\t\t0: \"AsIs\",\n\t\t1: \"UseIp\",\n\t\t2: \"IpIfNonMatch\",\n\t\t3: \"IpOnDemand\",\n\t}\n\tConfig_DomainStrategy_value = map[string]int32{\n\t\t\"AsIs\":         0,\n\t\t\"UseIp\":        1,\n\t\t\"IpIfNonMatch\": 2,\n\t\t\"IpOnDemand\":   3,\n\t}\n)\n\nfunc (x Config_DomainStrategy) Enum() *Config_DomainStrategy {\n\tp := new(Config_DomainStrategy)\n\t*p = x\n\treturn p\n}\n\nfunc (x Config_DomainStrategy) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (Config_DomainStrategy) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_app_router_config_proto_enumTypes[1].Descriptor()\n}\n\nfunc (Config_DomainStrategy) Type() protoreflect.EnumType {\n\treturn &file_app_router_config_proto_enumTypes[1]\n}\n\nfunc (x Config_DomainStrategy) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use Config_DomainStrategy.Descriptor instead.\nfunc (Config_DomainStrategy) EnumDescriptor() ([]byte, []int) {\n\treturn file_app_router_config_proto_rawDescGZIP(), []int{8, 0}\n}\n\n// Domain for routing decision.\ntype Domain struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Domain matching type.\n\tType Domain_Type `protobuf:\"varint,1,opt,name=type,proto3,enum=v2ray.core.app.router.Domain_Type\" json:\"type,omitempty\"`\n\t// Domain value.\n\tValue string `protobuf:\"bytes,2,opt,name=value,proto3\" json:\"value,omitempty\"`\n\t// Attributes of this domain. May be used for filtering.\n\tAttribute []*Domain_Attribute `protobuf:\"bytes,3,rep,name=attribute,proto3\" json:\"attribute,omitempty\"`\n}\n\nfunc (x *Domain) Reset() {\n\t*x = Domain{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_router_config_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Domain) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Domain) ProtoMessage() {}\n\nfunc (x *Domain) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_router_config_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Domain.ProtoReflect.Descriptor instead.\nfunc (*Domain) Descriptor() ([]byte, []int) {\n\treturn file_app_router_config_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *Domain) GetType() Domain_Type {\n\tif x != nil {\n\t\treturn x.Type\n\t}\n\treturn Domain_Plain\n}\n\nfunc (x *Domain) GetValue() string {\n\tif x != nil {\n\t\treturn x.Value\n\t}\n\treturn \"\"\n}\n\nfunc (x *Domain) GetAttribute() []*Domain_Attribute {\n\tif x != nil {\n\t\treturn x.Attribute\n\t}\n\treturn nil\n}\n\n// IP for routing decision, in CIDR form.\ntype CIDR struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// IP address, should be either 4 or 16 bytes.\n\tIp []byte `protobuf:\"bytes,1,opt,name=ip,proto3\" json:\"ip,omitempty\"`\n\t// Number of leading ones in the network mask.\n\tPrefix uint32 `protobuf:\"varint,2,opt,name=prefix,proto3\" json:\"prefix,omitempty\"`\n}\n\nfunc (x *CIDR) Reset() {\n\t*x = CIDR{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_router_config_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *CIDR) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*CIDR) ProtoMessage() {}\n\nfunc (x *CIDR) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_router_config_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use CIDR.ProtoReflect.Descriptor instead.\nfunc (*CIDR) Descriptor() ([]byte, []int) {\n\treturn file_app_router_config_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *CIDR) GetIp() []byte {\n\tif x != nil {\n\t\treturn x.Ip\n\t}\n\treturn nil\n}\n\nfunc (x *CIDR) GetPrefix() uint32 {\n\tif x != nil {\n\t\treturn x.Prefix\n\t}\n\treturn 0\n}\n\ntype GeoIP struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tCountryCode string  `protobuf:\"bytes,1,opt,name=country_code,json=countryCode,proto3\" json:\"country_code,omitempty\"`\n\tCidr        []*CIDR `protobuf:\"bytes,2,rep,name=cidr,proto3\" json:\"cidr,omitempty\"`\n}\n\nfunc (x *GeoIP) Reset() {\n\t*x = GeoIP{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_router_config_proto_msgTypes[2]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *GeoIP) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*GeoIP) ProtoMessage() {}\n\nfunc (x *GeoIP) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_router_config_proto_msgTypes[2]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use GeoIP.ProtoReflect.Descriptor instead.\nfunc (*GeoIP) Descriptor() ([]byte, []int) {\n\treturn file_app_router_config_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *GeoIP) GetCountryCode() string {\n\tif x != nil {\n\t\treturn x.CountryCode\n\t}\n\treturn \"\"\n}\n\nfunc (x *GeoIP) GetCidr() []*CIDR {\n\tif x != nil {\n\t\treturn x.Cidr\n\t}\n\treturn nil\n}\n\ntype GeoIPList struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tEntry []*GeoIP `protobuf:\"bytes,1,rep,name=entry,proto3\" json:\"entry,omitempty\"`\n}\n\nfunc (x *GeoIPList) Reset() {\n\t*x = GeoIPList{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_router_config_proto_msgTypes[3]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *GeoIPList) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*GeoIPList) ProtoMessage() {}\n\nfunc (x *GeoIPList) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_router_config_proto_msgTypes[3]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use GeoIPList.ProtoReflect.Descriptor instead.\nfunc (*GeoIPList) Descriptor() ([]byte, []int) {\n\treturn file_app_router_config_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *GeoIPList) GetEntry() []*GeoIP {\n\tif x != nil {\n\t\treturn x.Entry\n\t}\n\treturn nil\n}\n\ntype GeoSite struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tCountryCode string    `protobuf:\"bytes,1,opt,name=country_code,json=countryCode,proto3\" json:\"country_code,omitempty\"`\n\tDomain      []*Domain `protobuf:\"bytes,2,rep,name=domain,proto3\" json:\"domain,omitempty\"`\n}\n\nfunc (x *GeoSite) Reset() {\n\t*x = GeoSite{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_router_config_proto_msgTypes[4]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *GeoSite) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*GeoSite) ProtoMessage() {}\n\nfunc (x *GeoSite) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_router_config_proto_msgTypes[4]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use GeoSite.ProtoReflect.Descriptor instead.\nfunc (*GeoSite) Descriptor() ([]byte, []int) {\n\treturn file_app_router_config_proto_rawDescGZIP(), []int{4}\n}\n\nfunc (x *GeoSite) GetCountryCode() string {\n\tif x != nil {\n\t\treturn x.CountryCode\n\t}\n\treturn \"\"\n}\n\nfunc (x *GeoSite) GetDomain() []*Domain {\n\tif x != nil {\n\t\treturn x.Domain\n\t}\n\treturn nil\n}\n\ntype GeoSiteList struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tEntry []*GeoSite `protobuf:\"bytes,1,rep,name=entry,proto3\" json:\"entry,omitempty\"`\n}\n\nfunc (x *GeoSiteList) Reset() {\n\t*x = GeoSiteList{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_router_config_proto_msgTypes[5]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *GeoSiteList) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*GeoSiteList) ProtoMessage() {}\n\nfunc (x *GeoSiteList) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_router_config_proto_msgTypes[5]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use GeoSiteList.ProtoReflect.Descriptor instead.\nfunc (*GeoSiteList) Descriptor() ([]byte, []int) {\n\treturn file_app_router_config_proto_rawDescGZIP(), []int{5}\n}\n\nfunc (x *GeoSiteList) GetEntry() []*GeoSite {\n\tif x != nil {\n\t\treturn x.Entry\n\t}\n\treturn nil\n}\n\ntype RoutingRule struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Types that are assignable to TargetTag:\n\t//\t*RoutingRule_Tag\n\t//\t*RoutingRule_BalancingTag\n\tTargetTag isRoutingRule_TargetTag `protobuf_oneof:\"target_tag\"`\n\t// List of domains for target domain matching.\n\tDomain []*Domain `protobuf:\"bytes,2,rep,name=domain,proto3\" json:\"domain,omitempty\"`\n\t// List of CIDRs for target IP address matching.\n\t// Deprecated. Use geoip below.\n\t//\n\t// Deprecated: Do not use.\n\tCidr []*CIDR `protobuf:\"bytes,3,rep,name=cidr,proto3\" json:\"cidr,omitempty\"`\n\t// List of GeoIPs for target IP address matching. If this entry exists, the\n\t// cidr above will have no effect. GeoIP fields with the same country code are\n\t// supposed to contain exactly same content. They will be merged during\n\t// runtime. For customized GeoIPs, please leave country code empty.\n\tGeoip []*GeoIP `protobuf:\"bytes,10,rep,name=geoip,proto3\" json:\"geoip,omitempty\"`\n\t// A range of port [from, to]. If the destination port is in this range, this\n\t// rule takes effect. Deprecated. Use port_list.\n\t//\n\t// Deprecated: Do not use.\n\tPortRange *net.PortRange `protobuf:\"bytes,4,opt,name=port_range,json=portRange,proto3\" json:\"port_range,omitempty\"`\n\t// List of ports.\n\tPortList *net.PortList `protobuf:\"bytes,14,opt,name=port_list,json=portList,proto3\" json:\"port_list,omitempty\"`\n\t// List of networks. Deprecated. Use networks.\n\t//\n\t// Deprecated: Do not use.\n\tNetworkList *net.NetworkList `protobuf:\"bytes,5,opt,name=network_list,json=networkList,proto3\" json:\"network_list,omitempty\"`\n\t// List of networks for matching.\n\tNetworks []net.Network `protobuf:\"varint,13,rep,packed,name=networks,proto3,enum=v2ray.core.common.net.Network\" json:\"networks,omitempty\"`\n\t// List of CIDRs for source IP address matching.\n\t//\n\t// Deprecated: Do not use.\n\tSourceCidr []*CIDR `protobuf:\"bytes,6,rep,name=source_cidr,json=sourceCidr,proto3\" json:\"source_cidr,omitempty\"`\n\t// List of GeoIPs for source IP address matching. If this entry exists, the\n\t// source_cidr above will have no effect.\n\tSourceGeoip []*GeoIP `protobuf:\"bytes,11,rep,name=source_geoip,json=sourceGeoip,proto3\" json:\"source_geoip,omitempty\"`\n\t// List of ports for source port matching.\n\tSourcePortList *net.PortList `protobuf:\"bytes,16,opt,name=source_port_list,json=sourcePortList,proto3\" json:\"source_port_list,omitempty\"`\n\tUserEmail      []string      `protobuf:\"bytes,7,rep,name=user_email,json=userEmail,proto3\" json:\"user_email,omitempty\"`\n\tInboundTag     []string      `protobuf:\"bytes,8,rep,name=inbound_tag,json=inboundTag,proto3\" json:\"inbound_tag,omitempty\"`\n\tProtocol       []string      `protobuf:\"bytes,9,rep,name=protocol,proto3\" json:\"protocol,omitempty\"`\n\tAttributes     string        `protobuf:\"bytes,15,opt,name=attributes,proto3\" json:\"attributes,omitempty\"`\n}\n\nfunc (x *RoutingRule) Reset() {\n\t*x = RoutingRule{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_router_config_proto_msgTypes[6]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *RoutingRule) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RoutingRule) ProtoMessage() {}\n\nfunc (x *RoutingRule) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_router_config_proto_msgTypes[6]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RoutingRule.ProtoReflect.Descriptor instead.\nfunc (*RoutingRule) Descriptor() ([]byte, []int) {\n\treturn file_app_router_config_proto_rawDescGZIP(), []int{6}\n}\n\nfunc (m *RoutingRule) GetTargetTag() isRoutingRule_TargetTag {\n\tif m != nil {\n\t\treturn m.TargetTag\n\t}\n\treturn nil\n}\n\nfunc (x *RoutingRule) GetTag() string {\n\tif x, ok := x.GetTargetTag().(*RoutingRule_Tag); ok {\n\t\treturn x.Tag\n\t}\n\treturn \"\"\n}\n\nfunc (x *RoutingRule) GetBalancingTag() string {\n\tif x, ok := x.GetTargetTag().(*RoutingRule_BalancingTag); ok {\n\t\treturn x.BalancingTag\n\t}\n\treturn \"\"\n}\n\nfunc (x *RoutingRule) GetDomain() []*Domain {\n\tif x != nil {\n\t\treturn x.Domain\n\t}\n\treturn nil\n}\n\n// Deprecated: Do not use.\nfunc (x *RoutingRule) GetCidr() []*CIDR {\n\tif x != nil {\n\t\treturn x.Cidr\n\t}\n\treturn nil\n}\n\nfunc (x *RoutingRule) GetGeoip() []*GeoIP {\n\tif x != nil {\n\t\treturn x.Geoip\n\t}\n\treturn nil\n}\n\n// Deprecated: Do not use.\nfunc (x *RoutingRule) GetPortRange() *net.PortRange {\n\tif x != nil {\n\t\treturn x.PortRange\n\t}\n\treturn nil\n}\n\nfunc (x *RoutingRule) GetPortList() *net.PortList {\n\tif x != nil {\n\t\treturn x.PortList\n\t}\n\treturn nil\n}\n\n// Deprecated: Do not use.\nfunc (x *RoutingRule) GetNetworkList() *net.NetworkList {\n\tif x != nil {\n\t\treturn x.NetworkList\n\t}\n\treturn nil\n}\n\nfunc (x *RoutingRule) GetNetworks() []net.Network {\n\tif x != nil {\n\t\treturn x.Networks\n\t}\n\treturn nil\n}\n\n// Deprecated: Do not use.\nfunc (x *RoutingRule) GetSourceCidr() []*CIDR {\n\tif x != nil {\n\t\treturn x.SourceCidr\n\t}\n\treturn nil\n}\n\nfunc (x *RoutingRule) GetSourceGeoip() []*GeoIP {\n\tif x != nil {\n\t\treturn x.SourceGeoip\n\t}\n\treturn nil\n}\n\nfunc (x *RoutingRule) GetSourcePortList() *net.PortList {\n\tif x != nil {\n\t\treturn x.SourcePortList\n\t}\n\treturn nil\n}\n\nfunc (x *RoutingRule) GetUserEmail() []string {\n\tif x != nil {\n\t\treturn x.UserEmail\n\t}\n\treturn nil\n}\n\nfunc (x *RoutingRule) GetInboundTag() []string {\n\tif x != nil {\n\t\treturn x.InboundTag\n\t}\n\treturn nil\n}\n\nfunc (x *RoutingRule) GetProtocol() []string {\n\tif x != nil {\n\t\treturn x.Protocol\n\t}\n\treturn nil\n}\n\nfunc (x *RoutingRule) GetAttributes() string {\n\tif x != nil {\n\t\treturn x.Attributes\n\t}\n\treturn \"\"\n}\n\ntype isRoutingRule_TargetTag interface {\n\tisRoutingRule_TargetTag()\n}\n\ntype RoutingRule_Tag struct {\n\t// Tag of outbound that this rule is pointing to.\n\tTag string `protobuf:\"bytes,1,opt,name=tag,proto3,oneof\"`\n}\n\ntype RoutingRule_BalancingTag struct {\n\t// Tag of routing balancer.\n\tBalancingTag string `protobuf:\"bytes,12,opt,name=balancing_tag,json=balancingTag,proto3,oneof\"`\n}\n\nfunc (*RoutingRule_Tag) isRoutingRule_TargetTag() {}\n\nfunc (*RoutingRule_BalancingTag) isRoutingRule_TargetTag() {}\n\ntype BalancingRule struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tTag              string   `protobuf:\"bytes,1,opt,name=tag,proto3\" json:\"tag,omitempty\"`\n\tOutboundSelector []string `protobuf:\"bytes,2,rep,name=outbound_selector,json=outboundSelector,proto3\" json:\"outbound_selector,omitempty\"`\n}\n\nfunc (x *BalancingRule) Reset() {\n\t*x = BalancingRule{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_router_config_proto_msgTypes[7]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *BalancingRule) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*BalancingRule) ProtoMessage() {}\n\nfunc (x *BalancingRule) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_router_config_proto_msgTypes[7]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use BalancingRule.ProtoReflect.Descriptor instead.\nfunc (*BalancingRule) Descriptor() ([]byte, []int) {\n\treturn file_app_router_config_proto_rawDescGZIP(), []int{7}\n}\n\nfunc (x *BalancingRule) GetTag() string {\n\tif x != nil {\n\t\treturn x.Tag\n\t}\n\treturn \"\"\n}\n\nfunc (x *BalancingRule) GetOutboundSelector() []string {\n\tif x != nil {\n\t\treturn x.OutboundSelector\n\t}\n\treturn nil\n}\n\ntype Config struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tDomainStrategy Config_DomainStrategy `protobuf:\"varint,1,opt,name=domain_strategy,json=domainStrategy,proto3,enum=v2ray.core.app.router.Config_DomainStrategy\" json:\"domain_strategy,omitempty\"`\n\tRule           []*RoutingRule        `protobuf:\"bytes,2,rep,name=rule,proto3\" json:\"rule,omitempty\"`\n\tBalancingRule  []*BalancingRule      `protobuf:\"bytes,3,rep,name=balancing_rule,json=balancingRule,proto3\" json:\"balancing_rule,omitempty\"`\n}\n\nfunc (x *Config) Reset() {\n\t*x = Config{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_router_config_proto_msgTypes[8]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Config) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Config) ProtoMessage() {}\n\nfunc (x *Config) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_router_config_proto_msgTypes[8]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Config.ProtoReflect.Descriptor instead.\nfunc (*Config) Descriptor() ([]byte, []int) {\n\treturn file_app_router_config_proto_rawDescGZIP(), []int{8}\n}\n\nfunc (x *Config) GetDomainStrategy() Config_DomainStrategy {\n\tif x != nil {\n\t\treturn x.DomainStrategy\n\t}\n\treturn Config_AsIs\n}\n\nfunc (x *Config) GetRule() []*RoutingRule {\n\tif x != nil {\n\t\treturn x.Rule\n\t}\n\treturn nil\n}\n\nfunc (x *Config) GetBalancingRule() []*BalancingRule {\n\tif x != nil {\n\t\treturn x.BalancingRule\n\t}\n\treturn nil\n}\n\ntype Domain_Attribute struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tKey string `protobuf:\"bytes,1,opt,name=key,proto3\" json:\"key,omitempty\"`\n\t// Types that are assignable to TypedValue:\n\t//\t*Domain_Attribute_BoolValue\n\t//\t*Domain_Attribute_IntValue\n\tTypedValue isDomain_Attribute_TypedValue `protobuf_oneof:\"typed_value\"`\n}\n\nfunc (x *Domain_Attribute) Reset() {\n\t*x = Domain_Attribute{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_router_config_proto_msgTypes[9]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Domain_Attribute) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Domain_Attribute) ProtoMessage() {}\n\nfunc (x *Domain_Attribute) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_router_config_proto_msgTypes[9]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Domain_Attribute.ProtoReflect.Descriptor instead.\nfunc (*Domain_Attribute) Descriptor() ([]byte, []int) {\n\treturn file_app_router_config_proto_rawDescGZIP(), []int{0, 0}\n}\n\nfunc (x *Domain_Attribute) GetKey() string {\n\tif x != nil {\n\t\treturn x.Key\n\t}\n\treturn \"\"\n}\n\nfunc (m *Domain_Attribute) GetTypedValue() isDomain_Attribute_TypedValue {\n\tif m != nil {\n\t\treturn m.TypedValue\n\t}\n\treturn nil\n}\n\nfunc (x *Domain_Attribute) GetBoolValue() bool {\n\tif x, ok := x.GetTypedValue().(*Domain_Attribute_BoolValue); ok {\n\t\treturn x.BoolValue\n\t}\n\treturn false\n}\n\nfunc (x *Domain_Attribute) GetIntValue() int64 {\n\tif x, ok := x.GetTypedValue().(*Domain_Attribute_IntValue); ok {\n\t\treturn x.IntValue\n\t}\n\treturn 0\n}\n\ntype isDomain_Attribute_TypedValue interface {\n\tisDomain_Attribute_TypedValue()\n}\n\ntype Domain_Attribute_BoolValue struct {\n\tBoolValue bool `protobuf:\"varint,2,opt,name=bool_value,json=boolValue,proto3,oneof\"`\n}\n\ntype Domain_Attribute_IntValue struct {\n\tIntValue int64 `protobuf:\"varint,3,opt,name=int_value,json=intValue,proto3,oneof\"`\n}\n\nfunc (*Domain_Attribute_BoolValue) isDomain_Attribute_TypedValue() {}\n\nfunc (*Domain_Attribute_IntValue) isDomain_Attribute_TypedValue() {}\n\nvar File_app_router_config_proto protoreflect.FileDescriptor\n\nvar file_app_router_config_proto_rawDesc = []byte{\n\t0x0a, 0x17, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x6e,\n\t0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x15, 0x76, 0x32, 0x72, 0x61, 0x79,\n\t0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72,\n\t0x1a, 0x15, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x70, 0x6f, 0x72,\n\t0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f,\n\t0x6e, 0x65, 0x74, 0x2f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74,\n\t0x6f, 0x22, 0xbf, 0x02, 0x0a, 0x06, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x36, 0x0a, 0x04,\n\t0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x76, 0x32, 0x72,\n\t0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74,\n\t0x65, 0x72, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04,\n\t0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20,\n\t0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x45, 0x0a, 0x09, 0x61, 0x74,\n\t0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e,\n\t0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72,\n\t0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x41, 0x74, 0x74,\n\t0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x52, 0x09, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74,\n\t0x65, 0x1a, 0x6c, 0x0a, 0x09, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x12, 0x10,\n\t0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79,\n\t0x12, 0x1f, 0x0a, 0x0a, 0x62, 0x6f, 0x6f, 0x6c, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02,\n\t0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x09, 0x62, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75,\n\t0x65, 0x12, 0x1d, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03,\n\t0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x08, 0x69, 0x6e, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65,\n\t0x42, 0x0d, 0x0a, 0x0b, 0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22,\n\t0x32, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x09, 0x0a, 0x05, 0x50, 0x6c, 0x61, 0x69, 0x6e,\n\t0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x52, 0x65, 0x67, 0x65, 0x78, 0x10, 0x01, 0x12, 0x0a, 0x0a,\n\t0x06, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x46, 0x75, 0x6c,\n\t0x6c, 0x10, 0x03, 0x22, 0x2e, 0x0a, 0x04, 0x43, 0x49, 0x44, 0x52, 0x12, 0x0e, 0x0a, 0x02, 0x69,\n\t0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x70,\n\t0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x70, 0x72, 0x65,\n\t0x66, 0x69, 0x78, 0x22, 0x5b, 0x0a, 0x05, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x12, 0x21, 0x0a, 0x0c,\n\t0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01,\n\t0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x12,\n\t0x2f, 0x0a, 0x04, 0x63, 0x69, 0x64, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e,\n\t0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72,\n\t0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x43, 0x49, 0x44, 0x52, 0x52, 0x04, 0x63, 0x69, 0x64, 0x72,\n\t0x22, 0x3f, 0x0a, 0x09, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x32, 0x0a,\n\t0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x76,\n\t0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f,\n\t0x75, 0x74, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72,\n\t0x79, 0x22, 0x63, 0x0a, 0x07, 0x47, 0x65, 0x6f, 0x53, 0x69, 0x74, 0x65, 0x12, 0x21, 0x0a, 0x0c,\n\t0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01,\n\t0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x12,\n\t0x35, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32,\n\t0x1d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70,\n\t0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x06,\n\t0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x22, 0x43, 0x0a, 0x0b, 0x47, 0x65, 0x6f, 0x53, 0x69, 0x74,\n\t0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x34, 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01,\n\t0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72,\n\t0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f,\n\t0x53, 0x69, 0x74, 0x65, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x22, 0xca, 0x06, 0x0a, 0x0b,\n\t0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x03, 0x74,\n\t0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12,\n\t0x25, 0x0a, 0x0d, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x61, 0x67,\n\t0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0c, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63,\n\t0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, 0x12, 0x35, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e,\n\t0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,\n\t0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x44,\n\t0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x33, 0x0a,\n\t0x04, 0x63, 0x69, 0x64, 0x72, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x76, 0x32,\n\t0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75,\n\t0x74, 0x65, 0x72, 0x2e, 0x43, 0x49, 0x44, 0x52, 0x42, 0x02, 0x18, 0x01, 0x52, 0x04, 0x63, 0x69,\n\t0x64, 0x72, 0x12, 0x32, 0x0a, 0x05, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x18, 0x0a, 0x20, 0x03, 0x28,\n\t0x0b, 0x32, 0x1c, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61,\n\t0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52,\n\t0x05, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x12, 0x43, 0x0a, 0x0a, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x72,\n\t0x61, 0x6e, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x76, 0x32, 0x72,\n\t0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e,\n\t0x65, 0x74, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x42, 0x02, 0x18, 0x01,\n\t0x52, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x3c, 0x0a, 0x09, 0x70,\n\t0x6f, 0x72, 0x74, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f,\n\t0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,\n\t0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x52,\n\t0x08, 0x70, 0x6f, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x49, 0x0a, 0x0c, 0x6e, 0x65, 0x74,\n\t0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32,\n\t0x22, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d,\n\t0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4c,\n\t0x69, 0x73, 0x74, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0b, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b,\n\t0x4c, 0x69, 0x73, 0x74, 0x12, 0x3a, 0x0a, 0x08, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73,\n\t0x18, 0x0d, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,\n\t0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4e,\n\t0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x08, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73,\n\t0x12, 0x40, 0x0a, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x63, 0x69, 0x64, 0x72, 0x18,\n\t0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,\n\t0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x43, 0x49,\n\t0x44, 0x52, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0a, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x69,\n\t0x64, 0x72, 0x12, 0x3f, 0x0a, 0x0c, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x67, 0x65, 0x6f,\n\t0x69, 0x70, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,\n\t0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72,\n\t0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x65,\n\t0x6f, 0x69, 0x70, 0x12, 0x49, 0x0a, 0x10, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x70, 0x6f,\n\t0x72, 0x74, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e,\n\t0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,\n\t0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x0e,\n\t0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1d,\n\t0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x07, 0x20, 0x03,\n\t0x28, 0x09, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x1f, 0x0a,\n\t0x0b, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x74, 0x61, 0x67, 0x18, 0x08, 0x20, 0x03,\n\t0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x67, 0x12, 0x1a,\n\t0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09,\n\t0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x1e, 0x0a, 0x0a, 0x61, 0x74,\n\t0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a,\n\t0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x42, 0x0c, 0x0a, 0x0a, 0x74, 0x61,\n\t0x72, 0x67, 0x65, 0x74, 0x5f, 0x74, 0x61, 0x67, 0x22, 0x4e, 0x0a, 0x0d, 0x42, 0x61, 0x6c, 0x61,\n\t0x6e, 0x63, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67,\n\t0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x2b, 0x0a, 0x11, 0x6f,\n\t0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72,\n\t0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64,\n\t0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x22, 0xad, 0x02, 0x0a, 0x06, 0x43, 0x6f, 0x6e,\n\t0x66, 0x69, 0x67, 0x12, 0x55, 0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x73, 0x74,\n\t0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2c, 0x2e, 0x76,\n\t0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f,\n\t0x75, 0x74, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x44, 0x6f, 0x6d, 0x61,\n\t0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0e, 0x64, 0x6f, 0x6d, 0x61,\n\t0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x36, 0x0a, 0x04, 0x72, 0x75,\n\t0x6c, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,\n\t0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72,\n\t0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x04, 0x72, 0x75,\n\t0x6c, 0x65, 0x12, 0x4b, 0x0a, 0x0e, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x5f,\n\t0x72, 0x75, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x76, 0x32, 0x72,\n\t0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74,\n\t0x65, 0x72, 0x2e, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65,\n\t0x52, 0x0d, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x22,\n\t0x47, 0x0a, 0x0e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67,\n\t0x79, 0x12, 0x08, 0x0a, 0x04, 0x41, 0x73, 0x49, 0x73, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x55,\n\t0x73, 0x65, 0x49, 0x70, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x49, 0x70, 0x49, 0x66, 0x4e, 0x6f,\n\t0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x10, 0x02, 0x12, 0x0e, 0x0a, 0x0a, 0x49, 0x70, 0x4f, 0x6e,\n\t0x44, 0x65, 0x6d, 0x61, 0x6e, 0x64, 0x10, 0x03, 0x42, 0x50, 0x0a, 0x19, 0x63, 0x6f, 0x6d, 0x2e,\n\t0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72,\n\t0x6f, 0x75, 0x74, 0x65, 0x72, 0x50, 0x01, 0x5a, 0x19, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,\n\t0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74,\n\t0x65, 0x72, 0xaa, 0x02, 0x15, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e,\n\t0x41, 0x70, 0x70, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,\n\t0x6f, 0x33,\n}\n\nvar (\n\tfile_app_router_config_proto_rawDescOnce sync.Once\n\tfile_app_router_config_proto_rawDescData = file_app_router_config_proto_rawDesc\n)\n\nfunc file_app_router_config_proto_rawDescGZIP() []byte {\n\tfile_app_router_config_proto_rawDescOnce.Do(func() {\n\t\tfile_app_router_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_router_config_proto_rawDescData)\n\t})\n\treturn file_app_router_config_proto_rawDescData\n}\n\nvar file_app_router_config_proto_enumTypes = make([]protoimpl.EnumInfo, 2)\nvar file_app_router_config_proto_msgTypes = make([]protoimpl.MessageInfo, 10)\nvar file_app_router_config_proto_goTypes = []interface{}{\n\t(Domain_Type)(0),           // 0: v2ray.core.app.router.Domain.Type\n\t(Config_DomainStrategy)(0), // 1: v2ray.core.app.router.Config.DomainStrategy\n\t(*Domain)(nil),             // 2: v2ray.core.app.router.Domain\n\t(*CIDR)(nil),               // 3: v2ray.core.app.router.CIDR\n\t(*GeoIP)(nil),              // 4: v2ray.core.app.router.GeoIP\n\t(*GeoIPList)(nil),          // 5: v2ray.core.app.router.GeoIPList\n\t(*GeoSite)(nil),            // 6: v2ray.core.app.router.GeoSite\n\t(*GeoSiteList)(nil),        // 7: v2ray.core.app.router.GeoSiteList\n\t(*RoutingRule)(nil),        // 8: v2ray.core.app.router.RoutingRule\n\t(*BalancingRule)(nil),      // 9: v2ray.core.app.router.BalancingRule\n\t(*Config)(nil),             // 10: v2ray.core.app.router.Config\n\t(*Domain_Attribute)(nil),   // 11: v2ray.core.app.router.Domain.Attribute\n\t(*net.PortRange)(nil),      // 12: v2ray.core.common.net.PortRange\n\t(*net.PortList)(nil),       // 13: v2ray.core.common.net.PortList\n\t(*net.NetworkList)(nil),    // 14: v2ray.core.common.net.NetworkList\n\t(net.Network)(0),           // 15: v2ray.core.common.net.Network\n}\nvar file_app_router_config_proto_depIdxs = []int32{\n\t0,  // 0: v2ray.core.app.router.Domain.type:type_name -> v2ray.core.app.router.Domain.Type\n\t11, // 1: v2ray.core.app.router.Domain.attribute:type_name -> v2ray.core.app.router.Domain.Attribute\n\t3,  // 2: v2ray.core.app.router.GeoIP.cidr:type_name -> v2ray.core.app.router.CIDR\n\t4,  // 3: v2ray.core.app.router.GeoIPList.entry:type_name -> v2ray.core.app.router.GeoIP\n\t2,  // 4: v2ray.core.app.router.GeoSite.domain:type_name -> v2ray.core.app.router.Domain\n\t6,  // 5: v2ray.core.app.router.GeoSiteList.entry:type_name -> v2ray.core.app.router.GeoSite\n\t2,  // 6: v2ray.core.app.router.RoutingRule.domain:type_name -> v2ray.core.app.router.Domain\n\t3,  // 7: v2ray.core.app.router.RoutingRule.cidr:type_name -> v2ray.core.app.router.CIDR\n\t4,  // 8: v2ray.core.app.router.RoutingRule.geoip:type_name -> v2ray.core.app.router.GeoIP\n\t12, // 9: v2ray.core.app.router.RoutingRule.port_range:type_name -> v2ray.core.common.net.PortRange\n\t13, // 10: v2ray.core.app.router.RoutingRule.port_list:type_name -> v2ray.core.common.net.PortList\n\t14, // 11: v2ray.core.app.router.RoutingRule.network_list:type_name -> v2ray.core.common.net.NetworkList\n\t15, // 12: v2ray.core.app.router.RoutingRule.networks:type_name -> v2ray.core.common.net.Network\n\t3,  // 13: v2ray.core.app.router.RoutingRule.source_cidr:type_name -> v2ray.core.app.router.CIDR\n\t4,  // 14: v2ray.core.app.router.RoutingRule.source_geoip:type_name -> v2ray.core.app.router.GeoIP\n\t13, // 15: v2ray.core.app.router.RoutingRule.source_port_list:type_name -> v2ray.core.common.net.PortList\n\t1,  // 16: v2ray.core.app.router.Config.domain_strategy:type_name -> v2ray.core.app.router.Config.DomainStrategy\n\t8,  // 17: v2ray.core.app.router.Config.rule:type_name -> v2ray.core.app.router.RoutingRule\n\t9,  // 18: v2ray.core.app.router.Config.balancing_rule:type_name -> v2ray.core.app.router.BalancingRule\n\t19, // [19:19] is the sub-list for method output_type\n\t19, // [19:19] is the sub-list for method input_type\n\t19, // [19:19] is the sub-list for extension type_name\n\t19, // [19:19] is the sub-list for extension extendee\n\t0,  // [0:19] is the sub-list for field type_name\n}\n\nfunc init() { file_app_router_config_proto_init() }\nfunc file_app_router_config_proto_init() {\n\tif File_app_router_config_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_app_router_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Domain); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_router_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*CIDR); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_router_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*GeoIP); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_router_config_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*GeoIPList); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_router_config_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*GeoSite); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_router_config_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*GeoSiteList); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_router_config_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*RoutingRule); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_router_config_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*BalancingRule); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_router_config_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Config); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_router_config_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Domain_Attribute); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\tfile_app_router_config_proto_msgTypes[6].OneofWrappers = []interface{}{\n\t\t(*RoutingRule_Tag)(nil),\n\t\t(*RoutingRule_BalancingTag)(nil),\n\t}\n\tfile_app_router_config_proto_msgTypes[9].OneofWrappers = []interface{}{\n\t\t(*Domain_Attribute_BoolValue)(nil),\n\t\t(*Domain_Attribute_IntValue)(nil),\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_app_router_config_proto_rawDesc,\n\t\t\tNumEnums:      2,\n\t\t\tNumMessages:   10,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_app_router_config_proto_goTypes,\n\t\tDependencyIndexes: file_app_router_config_proto_depIdxs,\n\t\tEnumInfos:         file_app_router_config_proto_enumTypes,\n\t\tMessageInfos:      file_app_router_config_proto_msgTypes,\n\t}.Build()\n\tFile_app_router_config_proto = out.File\n\tfile_app_router_config_proto_rawDesc = nil\n\tfile_app_router_config_proto_goTypes = nil\n\tfile_app_router_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "app/router/config.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.app.router;\noption csharp_namespace = \"V2Ray.Core.App.Router\";\noption go_package = \"v2ray.com/core/app/router\";\noption java_package = \"com.v2ray.core.app.router\";\noption java_multiple_files = true;\n\nimport \"common/net/port.proto\";\nimport \"common/net/network.proto\";\n\n// Domain for routing decision.\nmessage Domain {\n  // Type of domain value.\n  enum Type {\n    // The value is used as is.\n    Plain = 0;\n    // The value is used as a regular expression.\n    Regex = 1;\n    // The value is a root domain.\n    Domain = 2;\n    // The value is a domain.\n    Full = 3;\n  }\n\n  // Domain matching type.\n  Type type = 1;\n\n  // Domain value.\n  string value = 2;\n\n  message Attribute {\n    string key = 1;\n\n    oneof typed_value {\n      bool bool_value = 2;\n      int64 int_value = 3;\n    }\n  }\n\n  // Attributes of this domain. May be used for filtering.\n  repeated Attribute attribute = 3;\n}\n\n// IP for routing decision, in CIDR form.\nmessage CIDR {\n  // IP address, should be either 4 or 16 bytes.\n  bytes ip = 1;\n\n  // Number of leading ones in the network mask.\n  uint32 prefix = 2;\n}\n\nmessage GeoIP {\n  string country_code = 1;\n  repeated CIDR cidr = 2;\n}\n\nmessage GeoIPList {\n  repeated GeoIP entry = 1;\n}\n\nmessage GeoSite {\n  string country_code = 1;\n  repeated Domain domain = 2;\n}\n\nmessage GeoSiteList {\n  repeated GeoSite entry = 1;\n}\n\nmessage RoutingRule {\n  oneof target_tag {\n    // Tag of outbound that this rule is pointing to.\n    string tag = 1;\n\n    // Tag of routing balancer.\n    string balancing_tag = 12;\n  }\n\n  // List of domains for target domain matching.\n  repeated Domain domain = 2;\n\n  // List of CIDRs for target IP address matching.\n  // Deprecated. Use geoip below.\n  repeated CIDR cidr = 3 [deprecated = true];\n\n  // List of GeoIPs for target IP address matching. If this entry exists, the\n  // cidr above will have no effect. GeoIP fields with the same country code are\n  // supposed to contain exactly same content. They will be merged during\n  // runtime. For customized GeoIPs, please leave country code empty.\n  repeated GeoIP geoip = 10;\n\n  // A range of port [from, to]. If the destination port is in this range, this\n  // rule takes effect. Deprecated. Use port_list.\n  v2ray.core.common.net.PortRange port_range = 4 [deprecated = true];\n\n  // List of ports.\n  v2ray.core.common.net.PortList port_list = 14;\n\n  // List of networks. Deprecated. Use networks.\n  v2ray.core.common.net.NetworkList network_list = 5 [deprecated = true];\n\n  // List of networks for matching.\n  repeated v2ray.core.common.net.Network networks = 13;\n\n  // List of CIDRs for source IP address matching.\n  repeated CIDR source_cidr = 6 [deprecated = true];\n\n  // List of GeoIPs for source IP address matching. If this entry exists, the\n  // source_cidr above will have no effect.\n  repeated GeoIP source_geoip = 11;\n\n  // List of ports for source port matching.\n  v2ray.core.common.net.PortList source_port_list = 16;\n\n  repeated string user_email = 7;\n  repeated string inbound_tag = 8;\n  repeated string protocol = 9;\n\n  string attributes = 15;\n}\n\nmessage BalancingRule {\n  string tag = 1;\n  repeated string outbound_selector = 2;\n}\n\nmessage Config {\n  enum DomainStrategy {\n    // Use domain as is.\n    AsIs = 0;\n\n    // Always resolve IP for domains.\n    UseIp = 1;\n\n    // Resolve to IP if the domain doesn't match any rules.\n    IpIfNonMatch = 2;\n\n    // Resolve to IP if any rule requires IP matching.\n    IpOnDemand = 3;\n  }\n  DomainStrategy domain_strategy = 1;\n  repeated RoutingRule rule = 2;\n  repeated BalancingRule balancing_rule = 3;\n}\n"
  },
  {
    "path": "app/router/errors.generated.go",
    "content": "package router\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "app/router/router.go",
    "content": "// +build !confonly\n\npackage router\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n\nimport (\n\t\"context\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/features/dns\"\n\t\"v2ray.com/core/features/outbound\"\n\t\"v2ray.com/core/features/routing\"\n\trouting_dns \"v2ray.com/core/features/routing/dns\"\n)\n\n// Router is an implementation of routing.Router.\ntype Router struct {\n\tdomainStrategy Config_DomainStrategy\n\trules          []*Rule\n\tbalancers      map[string]*Balancer\n\tdns            dns.Client\n}\n\n// Route is an implementation of routing.Route.\ntype Route struct {\n\trouting.Context\n\toutboundGroupTags []string\n\toutboundTag       string\n}\n\n// Init initializes the Router.\nfunc (r *Router) Init(config *Config, d dns.Client, ohm outbound.Manager) error {\n\tr.domainStrategy = config.DomainStrategy\n\tr.dns = d\n\n\tr.balancers = make(map[string]*Balancer, len(config.BalancingRule))\n\tfor _, rule := range config.BalancingRule {\n\t\tbalancer, err := rule.Build(ohm)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tr.balancers[rule.Tag] = balancer\n\t}\n\n\tr.rules = make([]*Rule, 0, len(config.Rule))\n\tfor _, rule := range config.Rule {\n\t\tcond, err := rule.BuildCondition()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\trr := &Rule{\n\t\t\tCondition: cond,\n\t\t\tTag:       rule.GetTag(),\n\t\t}\n\t\tbtag := rule.GetBalancingTag()\n\t\tif len(btag) > 0 {\n\t\t\tbrule, found := r.balancers[btag]\n\t\t\tif !found {\n\t\t\t\treturn newError(\"balancer \", btag, \" not found\")\n\t\t\t}\n\t\t\trr.Balancer = brule\n\t\t}\n\t\tr.rules = append(r.rules, rr)\n\t}\n\n\treturn nil\n}\n\n// PickRoute implements routing.Router.\nfunc (r *Router) PickRoute(ctx routing.Context) (routing.Route, error) {\n\trule, ctx, err := r.pickRouteInternal(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\ttag, err := rule.GetTag()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &Route{Context: ctx, outboundTag: tag}, nil\n}\n\nfunc (r *Router) pickRouteInternal(ctx routing.Context) (*Rule, routing.Context, error) {\n\tif r.domainStrategy == Config_IpOnDemand {\n\t\tctx = routing_dns.ContextWithDNSClient(ctx, r.dns)\n\t}\n\n\tfor _, rule := range r.rules {\n\t\tif rule.Apply(ctx) {\n\t\t\treturn rule, ctx, nil\n\t\t}\n\t}\n\n\tif r.domainStrategy != Config_IpIfNonMatch || len(ctx.GetTargetDomain()) == 0 {\n\t\treturn nil, ctx, common.ErrNoClue\n\t}\n\n\tctx = routing_dns.ContextWithDNSClient(ctx, r.dns)\n\n\t// Try applying rules again if we have IPs.\n\tfor _, rule := range r.rules {\n\t\tif rule.Apply(ctx) {\n\t\t\treturn rule, ctx, nil\n\t\t}\n\t}\n\n\treturn nil, ctx, common.ErrNoClue\n}\n\n// Start implements common.Runnable.\nfunc (*Router) Start() error {\n\treturn nil\n}\n\n// Close implements common.Closable.\nfunc (*Router) Close() error {\n\treturn nil\n}\n\n// Type implement common.HasType.\nfunc (*Router) Type() interface{} {\n\treturn routing.RouterType()\n}\n\n// GetOutboundGroupTags implements routing.Route.\nfunc (r *Route) GetOutboundGroupTags() []string {\n\treturn r.outboundGroupTags\n}\n\n// GetOutboundTag implements routing.Route.\nfunc (r *Route) GetOutboundTag() string {\n\treturn r.outboundTag\n}\n\nfunc init() {\n\tcommon.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {\n\t\tr := new(Router)\n\t\tif err := core.RequireFeatures(ctx, func(d dns.Client, ohm outbound.Manager) error {\n\t\t\treturn r.Init(config.(*Config), d, ohm)\n\t\t}); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn r, nil\n\t}))\n}\n"
  },
  {
    "path": "app/router/router_test.go",
    "content": "package router_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/golang/mock/gomock\"\n\t. \"v2ray.com/core/app/router\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/session\"\n\t\"v2ray.com/core/features/outbound\"\n\trouting_session \"v2ray.com/core/features/routing/session\"\n\t\"v2ray.com/core/testing/mocks\"\n)\n\ntype mockOutboundManager struct {\n\toutbound.Manager\n\toutbound.HandlerSelector\n}\n\nfunc TestSimpleRouter(t *testing.T) {\n\tconfig := &Config{\n\t\tRule: []*RoutingRule{\n\t\t\t{\n\t\t\t\tTargetTag: &RoutingRule_Tag{\n\t\t\t\t\tTag: \"test\",\n\t\t\t\t},\n\t\t\t\tNetworks: []net.Network{net.Network_TCP},\n\t\t\t},\n\t\t},\n\t}\n\n\tmockCtl := gomock.NewController(t)\n\tdefer mockCtl.Finish()\n\n\tmockDns := mocks.NewDNSClient(mockCtl)\n\tmockOhm := mocks.NewOutboundManager(mockCtl)\n\tmockHs := mocks.NewOutboundHandlerSelector(mockCtl)\n\n\tr := new(Router)\n\tcommon.Must(r.Init(config, mockDns, &mockOutboundManager{\n\t\tManager:         mockOhm,\n\t\tHandlerSelector: mockHs,\n\t}))\n\n\tctx := session.ContextWithOutbound(context.Background(), &session.Outbound{Target: net.TCPDestination(net.DomainAddress(\"v2ray.com\"), 80)})\n\troute, err := r.PickRoute(routing_session.AsRoutingContext(ctx))\n\tcommon.Must(err)\n\tif tag := route.GetOutboundTag(); tag != \"test\" {\n\t\tt.Error(\"expect tag 'test', bug actually \", tag)\n\t}\n}\n\nfunc TestSimpleBalancer(t *testing.T) {\n\tconfig := &Config{\n\t\tRule: []*RoutingRule{\n\t\t\t{\n\t\t\t\tTargetTag: &RoutingRule_BalancingTag{\n\t\t\t\t\tBalancingTag: \"balance\",\n\t\t\t\t},\n\t\t\t\tNetworks: []net.Network{net.Network_TCP},\n\t\t\t},\n\t\t},\n\t\tBalancingRule: []*BalancingRule{\n\t\t\t{\n\t\t\t\tTag:              \"balance\",\n\t\t\t\tOutboundSelector: []string{\"test-\"},\n\t\t\t},\n\t\t},\n\t}\n\n\tmockCtl := gomock.NewController(t)\n\tdefer mockCtl.Finish()\n\n\tmockDns := mocks.NewDNSClient(mockCtl)\n\tmockOhm := mocks.NewOutboundManager(mockCtl)\n\tmockHs := mocks.NewOutboundHandlerSelector(mockCtl)\n\n\tmockHs.EXPECT().Select(gomock.Eq([]string{\"test-\"})).Return([]string{\"test\"})\n\n\tr := new(Router)\n\tcommon.Must(r.Init(config, mockDns, &mockOutboundManager{\n\t\tManager:         mockOhm,\n\t\tHandlerSelector: mockHs,\n\t}))\n\n\tctx := session.ContextWithOutbound(context.Background(), &session.Outbound{Target: net.TCPDestination(net.DomainAddress(\"v2ray.com\"), 80)})\n\troute, err := r.PickRoute(routing_session.AsRoutingContext(ctx))\n\tcommon.Must(err)\n\tif tag := route.GetOutboundTag(); tag != \"test\" {\n\t\tt.Error(\"expect tag 'test', bug actually \", tag)\n\t}\n}\n\nfunc TestIPOnDemand(t *testing.T) {\n\tconfig := &Config{\n\t\tDomainStrategy: Config_IpOnDemand,\n\t\tRule: []*RoutingRule{\n\t\t\t{\n\t\t\t\tTargetTag: &RoutingRule_Tag{\n\t\t\t\t\tTag: \"test\",\n\t\t\t\t},\n\t\t\t\tCidr: []*CIDR{\n\t\t\t\t\t{\n\t\t\t\t\t\tIp:     []byte{192, 168, 0, 0},\n\t\t\t\t\t\tPrefix: 16,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tmockCtl := gomock.NewController(t)\n\tdefer mockCtl.Finish()\n\n\tmockDns := mocks.NewDNSClient(mockCtl)\n\tmockDns.EXPECT().LookupIP(gomock.Eq(\"v2ray.com\")).Return([]net.IP{{192, 168, 0, 1}}, nil).AnyTimes()\n\n\tr := new(Router)\n\tcommon.Must(r.Init(config, mockDns, nil))\n\n\tctx := session.ContextWithOutbound(context.Background(), &session.Outbound{Target: net.TCPDestination(net.DomainAddress(\"v2ray.com\"), 80)})\n\troute, err := r.PickRoute(routing_session.AsRoutingContext(ctx))\n\tcommon.Must(err)\n\tif tag := route.GetOutboundTag(); tag != \"test\" {\n\t\tt.Error(\"expect tag 'test', bug actually \", tag)\n\t}\n}\n\nfunc TestIPIfNonMatchDomain(t *testing.T) {\n\tconfig := &Config{\n\t\tDomainStrategy: Config_IpIfNonMatch,\n\t\tRule: []*RoutingRule{\n\t\t\t{\n\t\t\t\tTargetTag: &RoutingRule_Tag{\n\t\t\t\t\tTag: \"test\",\n\t\t\t\t},\n\t\t\t\tCidr: []*CIDR{\n\t\t\t\t\t{\n\t\t\t\t\t\tIp:     []byte{192, 168, 0, 0},\n\t\t\t\t\t\tPrefix: 16,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tmockCtl := gomock.NewController(t)\n\tdefer mockCtl.Finish()\n\n\tmockDns := mocks.NewDNSClient(mockCtl)\n\tmockDns.EXPECT().LookupIP(gomock.Eq(\"v2ray.com\")).Return([]net.IP{{192, 168, 0, 1}}, nil).AnyTimes()\n\n\tr := new(Router)\n\tcommon.Must(r.Init(config, mockDns, nil))\n\n\tctx := session.ContextWithOutbound(context.Background(), &session.Outbound{Target: net.TCPDestination(net.DomainAddress(\"v2ray.com\"), 80)})\n\troute, err := r.PickRoute(routing_session.AsRoutingContext(ctx))\n\tcommon.Must(err)\n\tif tag := route.GetOutboundTag(); tag != \"test\" {\n\t\tt.Error(\"expect tag 'test', bug actually \", tag)\n\t}\n}\n\nfunc TestIPIfNonMatchIP(t *testing.T) {\n\tconfig := &Config{\n\t\tDomainStrategy: Config_IpIfNonMatch,\n\t\tRule: []*RoutingRule{\n\t\t\t{\n\t\t\t\tTargetTag: &RoutingRule_Tag{\n\t\t\t\t\tTag: \"test\",\n\t\t\t\t},\n\t\t\t\tCidr: []*CIDR{\n\t\t\t\t\t{\n\t\t\t\t\t\tIp:     []byte{127, 0, 0, 0},\n\t\t\t\t\t\tPrefix: 8,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tmockCtl := gomock.NewController(t)\n\tdefer mockCtl.Finish()\n\n\tmockDns := mocks.NewDNSClient(mockCtl)\n\n\tr := new(Router)\n\tcommon.Must(r.Init(config, mockDns, nil))\n\n\tctx := session.ContextWithOutbound(context.Background(), &session.Outbound{Target: net.TCPDestination(net.LocalHostIP, 80)})\n\troute, err := r.PickRoute(routing_session.AsRoutingContext(ctx))\n\tcommon.Must(err)\n\tif tag := route.GetOutboundTag(); tag != \"test\" {\n\t\tt.Error(\"expect tag 'test', bug actually \", tag)\n\t}\n}\n"
  },
  {
    "path": "app/stats/channel.go",
    "content": "// +build !confonly\n\npackage stats\n\nimport (\n\t\"context\"\n\t\"sync\"\n\n\t\"v2ray.com/core/common\"\n)\n\n// Channel is an implementation of stats.Channel.\ntype Channel struct {\n\tchannel     chan channelMessage\n\tsubscribers []chan interface{}\n\n\t// Synchronization components\n\taccess sync.RWMutex\n\tclosed chan struct{}\n\n\t// Channel options\n\tblocking   bool // Set blocking state if channel buffer reaches limit\n\tbufferSize int  // Set to 0 as no buffering\n\tsubsLimit  int  // Set to 0 as no subscriber limit\n}\n\n// NewChannel creates an instance of Statistics Channel.\nfunc NewChannel(config *ChannelConfig) *Channel {\n\treturn &Channel{\n\t\tchannel:    make(chan channelMessage, config.BufferSize),\n\t\tsubsLimit:  int(config.SubscriberLimit),\n\t\tbufferSize: int(config.BufferSize),\n\t\tblocking:   config.Blocking,\n\t}\n}\n\n// Subscribers implements stats.Channel.\nfunc (c *Channel) Subscribers() []chan interface{} {\n\tc.access.RLock()\n\tdefer c.access.RUnlock()\n\treturn c.subscribers\n}\n\n// Subscribe implements stats.Channel.\nfunc (c *Channel) Subscribe() (chan interface{}, error) {\n\tc.access.Lock()\n\tdefer c.access.Unlock()\n\tif c.subsLimit > 0 && len(c.subscribers) >= c.subsLimit {\n\t\treturn nil, newError(\"Number of subscribers has reached limit\")\n\t}\n\tsubscriber := make(chan interface{}, c.bufferSize)\n\tc.subscribers = append(c.subscribers, subscriber)\n\treturn subscriber, nil\n}\n\n// Unsubscribe implements stats.Channel.\nfunc (c *Channel) Unsubscribe(subscriber chan interface{}) error {\n\tc.access.Lock()\n\tdefer c.access.Unlock()\n\tfor i, s := range c.subscribers {\n\t\tif s == subscriber {\n\t\t\t// Copy to new memory block to prevent modifying original data\n\t\t\tsubscribers := make([]chan interface{}, len(c.subscribers)-1)\n\t\t\tcopy(subscribers[:i], c.subscribers[:i])\n\t\t\tcopy(subscribers[i:], c.subscribers[i+1:])\n\t\t\tc.subscribers = subscribers\n\t\t}\n\t}\n\treturn nil\n}\n\n// Publish implements stats.Channel.\nfunc (c *Channel) Publish(ctx context.Context, msg interface{}) {\n\tselect { // Early exit if channel closed\n\tcase <-c.closed:\n\t\treturn\n\tdefault:\n\t\tpub := channelMessage{context: ctx, message: msg}\n\t\tif c.blocking {\n\t\t\tpub.publish(c.channel)\n\t\t} else {\n\t\t\tpub.publishNonBlocking(c.channel)\n\t\t}\n\t}\n}\n\n// Running returns whether the channel is running.\nfunc (c *Channel) Running() bool {\n\tselect {\n\tcase <-c.closed: // Channel closed\n\tdefault: // Channel running or not initialized\n\t\tif c.closed != nil { // Channel initialized\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// Start implements common.Runnable.\nfunc (c *Channel) Start() error {\n\tc.access.Lock()\n\tdefer c.access.Unlock()\n\tif !c.Running() {\n\t\tc.closed = make(chan struct{}) // Reset close signal\n\t\tgo func() {\n\t\t\tfor {\n\t\t\t\tselect {\n\t\t\t\tcase pub := <-c.channel: // Published message received\n\t\t\t\t\tfor _, sub := range c.Subscribers() { // Concurrency-safe subscribers retrievement\n\t\t\t\t\t\tif c.blocking {\n\t\t\t\t\t\t\tpub.broadcast(sub)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tpub.broadcastNonBlocking(sub)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\tcase <-c.closed: // Channel closed\n\t\t\t\t\tfor _, sub := range c.Subscribers() { // Remove all subscribers\n\t\t\t\t\t\tcommon.Must(c.Unsubscribe(sub))\n\t\t\t\t\t\tclose(sub)\n\t\t\t\t\t}\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t}()\n\t}\n\treturn nil\n}\n\n// Close implements common.Closable.\nfunc (c *Channel) Close() error {\n\tc.access.Lock()\n\tdefer c.access.Unlock()\n\tif c.Running() {\n\t\tclose(c.closed) // Send closed signal\n\t}\n\treturn nil\n}\n\n// channelMessage is the published message with guaranteed delivery.\n// message is discarded only when the context is early cancelled.\ntype channelMessage struct {\n\tcontext context.Context\n\tmessage interface{}\n}\n\nfunc (c channelMessage) publish(publisher chan channelMessage) {\n\tselect {\n\tcase publisher <- c:\n\tcase <-c.context.Done():\n\t}\n}\n\nfunc (c channelMessage) publishNonBlocking(publisher chan channelMessage) {\n\tselect {\n\tcase publisher <- c:\n\tdefault: // Create another goroutine to keep sending message\n\t\tgo c.publish(publisher)\n\t}\n}\n\nfunc (c channelMessage) broadcast(subscriber chan interface{}) {\n\tselect {\n\tcase subscriber <- c.message:\n\tcase <-c.context.Done():\n\t}\n}\n\nfunc (c channelMessage) broadcastNonBlocking(subscriber chan interface{}) {\n\tselect {\n\tcase subscriber <- c.message:\n\tdefault: // Create another goroutine to keep sending message\n\t\tgo c.broadcast(subscriber)\n\t}\n}\n"
  },
  {
    "path": "app/stats/channel_test.go",
    "content": "package stats_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t. \"v2ray.com/core/app/stats\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/features/stats\"\n)\n\nfunc TestStatsChannel(t *testing.T) {\n\t// At most 2 subscribers could be registered\n\tc := NewChannel(&ChannelConfig{SubscriberLimit: 2, Blocking: true})\n\n\ta, err := stats.SubscribeRunnableChannel(c)\n\tcommon.Must(err)\n\tif !c.Running() {\n\t\tt.Fatal(\"unexpected failure in running channel after first subscription\")\n\t}\n\n\tb, err := c.Subscribe()\n\tcommon.Must(err)\n\n\t// Test that third subscriber is forbidden\n\t_, err = c.Subscribe()\n\tif err == nil {\n\t\tt.Fatal(\"unexpected successful subscription\")\n\t}\n\tt.Log(\"expected error: \", err)\n\n\tstopCh := make(chan struct{})\n\terrCh := make(chan string)\n\n\tgo func() {\n\t\tc.Publish(context.Background(), 1)\n\t\tc.Publish(context.Background(), 2)\n\t\tc.Publish(context.Background(), \"3\")\n\t\tc.Publish(context.Background(), []int{4})\n\t\tstopCh <- struct{}{}\n\t}()\n\n\tgo func() {\n\t\tif v, ok := (<-a).(int); !ok || v != 1 {\n\t\t\terrCh <- fmt.Sprint(\"unexpected receiving: \", v, \", wanted \", 1)\n\t\t}\n\t\tif v, ok := (<-a).(int); !ok || v != 2 {\n\t\t\terrCh <- fmt.Sprint(\"unexpected receiving: \", v, \", wanted \", 2)\n\t\t}\n\t\tif v, ok := (<-a).(string); !ok || v != \"3\" {\n\t\t\terrCh <- fmt.Sprint(\"unexpected receiving: \", v, \", wanted \", \"3\")\n\t\t}\n\t\tif v, ok := (<-a).([]int); !ok || v[0] != 4 {\n\t\t\terrCh <- fmt.Sprint(\"unexpected receiving: \", v, \", wanted \", []int{4})\n\t\t}\n\t\tstopCh <- struct{}{}\n\t}()\n\n\tgo func() {\n\t\tif v, ok := (<-b).(int); !ok || v != 1 {\n\t\t\terrCh <- fmt.Sprint(\"unexpected receiving: \", v, \", wanted \", 1)\n\t\t}\n\t\tif v, ok := (<-b).(int); !ok || v != 2 {\n\t\t\terrCh <- fmt.Sprint(\"unexpected receiving: \", v, \", wanted \", 2)\n\t\t}\n\t\tif v, ok := (<-b).(string); !ok || v != \"3\" {\n\t\t\terrCh <- fmt.Sprint(\"unexpected receiving: \", v, \", wanted \", \"3\")\n\t\t}\n\t\tif v, ok := (<-b).([]int); !ok || v[0] != 4 {\n\t\t\terrCh <- fmt.Sprint(\"unexpected receiving: \", v, \", wanted \", []int{4})\n\t\t}\n\t\tstopCh <- struct{}{}\n\t}()\n\n\ttimeout := time.After(2 * time.Second)\n\tfor i := 0; i < 3; i++ {\n\t\tselect {\n\t\tcase <-timeout:\n\t\t\tt.Fatal(\"Test timeout after 2s\")\n\t\tcase e := <-errCh:\n\t\t\tt.Fatal(e)\n\t\tcase <-stopCh:\n\t\t}\n\t}\n\n\t// Test the unsubscription of channel\n\tcommon.Must(c.Unsubscribe(b))\n\n\t// Test the last subscriber will close channel with `UnsubscribeClosableChannel`\n\tcommon.Must(stats.UnsubscribeClosableChannel(c, a))\n\tif c.Running() {\n\t\tt.Fatal(\"unexpected running channel after unsubscribing the last subscriber\")\n\t}\n}\n\nfunc TestStatsChannelUnsubcribe(t *testing.T) {\n\tc := NewChannel(&ChannelConfig{Blocking: true})\n\tcommon.Must(c.Start())\n\tdefer c.Close()\n\n\ta, err := c.Subscribe()\n\tcommon.Must(err)\n\tdefer c.Unsubscribe(a)\n\n\tb, err := c.Subscribe()\n\tcommon.Must(err)\n\n\tpauseCh := make(chan struct{})\n\tstopCh := make(chan struct{})\n\terrCh := make(chan string)\n\n\t{\n\t\tvar aSet, bSet bool\n\t\tfor _, s := range c.Subscribers() {\n\t\t\tif s == a {\n\t\t\t\taSet = true\n\t\t\t}\n\t\t\tif s == b {\n\t\t\t\tbSet = true\n\t\t\t}\n\t\t}\n\t\tif !(aSet && bSet) {\n\t\t\tt.Fatal(\"unexpected subscribers: \", c.Subscribers())\n\t\t}\n\t}\n\n\tgo func() { // Blocking publish\n\t\tc.Publish(context.Background(), 1)\n\t\t<-pauseCh // Wait for `b` goroutine to resume sending message\n\t\tc.Publish(context.Background(), 2)\n\t}()\n\n\tgo func() {\n\t\tif v, ok := (<-a).(int); !ok || v != 1 {\n\t\t\terrCh <- fmt.Sprint(\"unexpected receiving: \", v, \", wanted \", 1)\n\t\t}\n\t\tif v, ok := (<-a).(int); !ok || v != 2 {\n\t\t\terrCh <- fmt.Sprint(\"unexpected receiving: \", v, \", wanted \", 2)\n\t\t}\n\t}()\n\n\tgo func() {\n\t\tif v, ok := (<-b).(int); !ok || v != 1 {\n\t\t\terrCh <- fmt.Sprint(\"unexpected receiving: \", v, \", wanted \", 1)\n\t\t}\n\t\t// Unsubscribe `b` while publishing is paused\n\t\tc.Unsubscribe(b)\n\t\t{ // Test `b` is not in subscribers\n\t\t\tvar aSet, bSet bool\n\t\t\tfor _, s := range c.Subscribers() {\n\t\t\t\tif s == a {\n\t\t\t\t\taSet = true\n\t\t\t\t}\n\t\t\t\tif s == b {\n\t\t\t\t\tbSet = true\n\t\t\t\t}\n\t\t\t}\n\t\t\tif !(aSet && !bSet) {\n\t\t\t\terrCh <- fmt.Sprint(\"unexpected subscribers: \", c.Subscribers())\n\t\t\t}\n\t\t}\n\t\t// Resume publishing progress\n\t\tclose(pauseCh)\n\t\t// Test `b` is neither closed nor able to receive any data\n\t\tselect {\n\t\tcase v, ok := <-b:\n\t\t\tif ok {\n\t\t\t\terrCh <- fmt.Sprint(\"unexpected data received: \", v)\n\t\t\t} else {\n\t\t\t\terrCh <- fmt.Sprint(\"unexpected closed channel: \", b)\n\t\t\t}\n\t\tdefault:\n\t\t}\n\t\tclose(stopCh)\n\t}()\n\n\tselect {\n\tcase <-time.After(2 * time.Second):\n\t\tt.Fatal(\"Test timeout after 2s\")\n\tcase e := <-errCh:\n\t\tt.Fatal(e)\n\tcase <-stopCh:\n\t}\n}\n\nfunc TestStatsChannelBlocking(t *testing.T) {\n\t// Do not use buffer so as to create blocking scenario\n\tc := NewChannel(&ChannelConfig{BufferSize: 0, Blocking: true})\n\tcommon.Must(c.Start())\n\tdefer c.Close()\n\n\ta, err := c.Subscribe()\n\tcommon.Must(err)\n\tdefer c.Unsubscribe(a)\n\n\tpauseCh := make(chan struct{})\n\tstopCh := make(chan struct{})\n\terrCh := make(chan string)\n\n\tctx, cancel := context.WithCancel(context.Background())\n\n\t// Test blocking channel publishing\n\tgo func() {\n\t\t// Dummy messsage with no subscriber receiving, will block broadcasting goroutine\n\t\tc.Publish(context.Background(), nil)\n\n\t\t<-pauseCh\n\n\t\t// Publishing should be blocked here, for last message was not cleared and buffer was full\n\t\tc.Publish(context.Background(), nil)\n\n\t\tpauseCh <- struct{}{}\n\n\t\t// Publishing should still be blocked here\n\t\tc.Publish(ctx, nil)\n\n\t\t// Check publishing is done because context is canceled\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\tif ctx.Err() != context.Canceled {\n\t\t\t\terrCh <- fmt.Sprint(\"unexpected error: \", ctx.Err())\n\t\t\t}\n\t\tdefault:\n\t\t\terrCh <- \"unexpected non-blocked publishing\"\n\t\t}\n\t\tclose(stopCh)\n\t}()\n\n\tgo func() {\n\t\tpauseCh <- struct{}{}\n\n\t\tselect {\n\t\tcase <-pauseCh:\n\t\t\terrCh <- \"unexpected non-blocked publishing\"\n\t\tcase <-time.After(100 * time.Millisecond):\n\t\t}\n\n\t\t// Receive first published message\n\t\t<-a\n\n\t\tselect {\n\t\tcase <-pauseCh:\n\t\tcase <-time.After(100 * time.Millisecond):\n\t\t\terrCh <- \"unexpected blocking publishing\"\n\t\t}\n\n\t\t// Manually cancel the context to end publishing\n\t\tcancel()\n\t}()\n\n\tselect {\n\tcase <-time.After(2 * time.Second):\n\t\tt.Fatal(\"Test timeout after 2s\")\n\tcase e := <-errCh:\n\t\tt.Fatal(e)\n\tcase <-stopCh:\n\t}\n}\n\nfunc TestStatsChannelNonBlocking(t *testing.T) {\n\t// Do not use buffer so as to create blocking scenario\n\tc := NewChannel(&ChannelConfig{BufferSize: 0, Blocking: false})\n\tcommon.Must(c.Start())\n\tdefer c.Close()\n\n\ta, err := c.Subscribe()\n\tcommon.Must(err)\n\tdefer c.Unsubscribe(a)\n\n\tpauseCh := make(chan struct{})\n\tstopCh := make(chan struct{})\n\terrCh := make(chan string)\n\n\tctx, cancel := context.WithCancel(context.Background())\n\n\t// Test blocking channel publishing\n\tgo func() {\n\t\tc.Publish(context.Background(), nil)\n\t\tc.Publish(context.Background(), nil)\n\t\tpauseCh <- struct{}{}\n\t\t<-pauseCh\n\t\tc.Publish(ctx, nil)\n\t\tc.Publish(ctx, nil)\n\t\t// Check publishing is done because context is canceled\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\tif ctx.Err() != context.Canceled {\n\t\t\t\terrCh <- fmt.Sprint(\"unexpected error: \", ctx.Err())\n\t\t\t}\n\t\tcase <-time.After(100 * time.Millisecond):\n\t\t\terrCh <- \"unexpected non-cancelled publishing\"\n\t\t}\n\t}()\n\n\tgo func() {\n\t\t// Check publishing won't block even if there is no subscriber receiving message\n\t\tselect {\n\t\tcase <-pauseCh:\n\t\tcase <-time.After(100 * time.Millisecond):\n\t\t\terrCh <- \"unexpected blocking publishing\"\n\t\t}\n\n\t\t// Receive first and second published message\n\t\t<-a\n\t\t<-a\n\n\t\tpauseCh <- struct{}{}\n\n\t\t// Manually cancel the context to end publishing\n\t\tcancel()\n\n\t\t// Check third and forth published message is cancelled and cannot receive\n\t\t<-time.After(100 * time.Millisecond)\n\t\tselect {\n\t\tcase <-a:\n\t\t\terrCh <- \"unexpected non-cancelled publishing\"\n\t\tdefault:\n\t\t}\n\t\tselect {\n\t\tcase <-a:\n\t\t\terrCh <- \"unexpected non-cancelled publishing\"\n\t\tdefault:\n\t\t}\n\t\tclose(stopCh)\n\t}()\n\n\tselect {\n\tcase <-time.After(2 * time.Second):\n\t\tt.Fatal(\"Test timeout after 2s\")\n\tcase e := <-errCh:\n\t\tt.Fatal(e)\n\tcase <-stopCh:\n\t}\n}\n\nfunc TestStatsChannelConcurrency(t *testing.T) {\n\t// Do not use buffer so as to create blocking scenario\n\tc := NewChannel(&ChannelConfig{BufferSize: 0, Blocking: true})\n\tcommon.Must(c.Start())\n\tdefer c.Close()\n\n\ta, err := c.Subscribe()\n\tcommon.Must(err)\n\tdefer c.Unsubscribe(a)\n\n\tb, err := c.Subscribe()\n\tcommon.Must(err)\n\tdefer c.Unsubscribe(b)\n\n\tstopCh := make(chan struct{})\n\terrCh := make(chan string)\n\n\tgo func() { // Blocking publish\n\t\tc.Publish(context.Background(), 1)\n\t\tc.Publish(context.Background(), 2)\n\t}()\n\n\tgo func() {\n\t\tif v, ok := (<-a).(int); !ok || v != 1 {\n\t\t\terrCh <- fmt.Sprint(\"unexpected receiving: \", v, \", wanted \", 1)\n\t\t}\n\t\tif v, ok := (<-a).(int); !ok || v != 2 {\n\t\t\terrCh <- fmt.Sprint(\"unexpected receiving: \", v, \", wanted \", 2)\n\t\t}\n\t}()\n\n\tgo func() {\n\t\t// Block `b` for a time so as to ensure source channel is trying to send message to `b`.\n\t\t<-time.After(25 * time.Millisecond)\n\t\t// This causes concurrency scenario: unsubscribe `b` while trying to send message to it\n\t\tc.Unsubscribe(b)\n\t\t// Test `b` is not closed and can still receive data 1:\n\t\t// Because unsubscribe won't affect the ongoing process of sending message.\n\t\tselect {\n\t\tcase v, ok := <-b:\n\t\t\tif v1, ok1 := v.(int); !(ok && ok1 && v1 == 1) {\n\t\t\t\terrCh <- fmt.Sprint(\"unexpected failure in receiving data: \", 1)\n\t\t\t}\n\t\tdefault:\n\t\t\terrCh <- fmt.Sprint(\"unexpected block from receiving data: \", 1)\n\t\t}\n\t\t// Test `b` is not closed but cannot receive data 2:\n\t\t// Because in a new round of messaging, `b` has been unsubscribed.\n\t\tselect {\n\t\tcase v, ok := <-b:\n\t\t\tif ok {\n\t\t\t\terrCh <- fmt.Sprint(\"unexpected receiving: \", v)\n\t\t\t} else {\n\t\t\t\terrCh <- fmt.Sprint(\"unexpected closing of channel\")\n\t\t\t}\n\t\tdefault:\n\t\t}\n\t\tclose(stopCh)\n\t}()\n\n\tselect {\n\tcase <-time.After(2 * time.Second):\n\t\tt.Fatal(\"Test timeout after 2s\")\n\tcase e := <-errCh:\n\t\tt.Fatal(e)\n\tcase <-stopCh:\n\t}\n}\n"
  },
  {
    "path": "app/stats/command/command.go",
    "content": "// +build !confonly\n\npackage command\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n\nimport (\n\t\"context\"\n\t\"runtime\"\n\t\"time\"\n\n\tgrpc \"google.golang.org/grpc\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/app/stats\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/strmatcher\"\n\tfeature_stats \"v2ray.com/core/features/stats\"\n)\n\n// statsServer is an implementation of StatsService.\ntype statsServer struct {\n\tstats     feature_stats.Manager\n\tstartTime time.Time\n}\n\nfunc NewStatsServer(manager feature_stats.Manager) StatsServiceServer {\n\treturn &statsServer{\n\t\tstats:     manager,\n\t\tstartTime: time.Now(),\n\t}\n}\n\nfunc (s *statsServer) GetStats(ctx context.Context, request *GetStatsRequest) (*GetStatsResponse, error) {\n\tc := s.stats.GetCounter(request.Name)\n\tif c == nil {\n\t\treturn nil, newError(request.Name, \" not found.\")\n\t}\n\tvar value int64\n\tif request.Reset_ {\n\t\tvalue = c.Set(0)\n\t} else {\n\t\tvalue = c.Value()\n\t}\n\treturn &GetStatsResponse{\n\t\tStat: &Stat{\n\t\t\tName:  request.Name,\n\t\t\tValue: value,\n\t\t},\n\t}, nil\n}\n\nfunc (s *statsServer) QueryStats(ctx context.Context, request *QueryStatsRequest) (*QueryStatsResponse, error) {\n\tmatcher, err := strmatcher.Substr.New(request.Pattern)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tresponse := &QueryStatsResponse{}\n\n\tmanager, ok := s.stats.(*stats.Manager)\n\tif !ok {\n\t\treturn nil, newError(\"QueryStats only works its own stats.Manager.\")\n\t}\n\n\tmanager.VisitCounters(func(name string, c feature_stats.Counter) bool {\n\t\tif matcher.Match(name) {\n\t\t\tvar value int64\n\t\t\tif request.Reset_ {\n\t\t\t\tvalue = c.Set(0)\n\t\t\t} else {\n\t\t\t\tvalue = c.Value()\n\t\t\t}\n\t\t\tresponse.Stat = append(response.Stat, &Stat{\n\t\t\t\tName:  name,\n\t\t\t\tValue: value,\n\t\t\t})\n\t\t}\n\t\treturn true\n\t})\n\n\treturn response, nil\n}\n\nfunc (s *statsServer) GetSysStats(ctx context.Context, request *SysStatsRequest) (*SysStatsResponse, error) {\n\tvar rtm runtime.MemStats\n\truntime.ReadMemStats(&rtm)\n\n\tuptime := time.Since(s.startTime)\n\n\tresponse := &SysStatsResponse{\n\t\tUptime:       uint32(uptime.Seconds()),\n\t\tNumGoroutine: uint32(runtime.NumGoroutine()),\n\t\tAlloc:        rtm.Alloc,\n\t\tTotalAlloc:   rtm.TotalAlloc,\n\t\tSys:          rtm.Sys,\n\t\tMallocs:      rtm.Mallocs,\n\t\tFrees:        rtm.Frees,\n\t\tLiveObjects:  rtm.Mallocs - rtm.Frees,\n\t\tNumGC:        rtm.NumGC,\n\t\tPauseTotalNs: rtm.PauseTotalNs,\n\t}\n\n\treturn response, nil\n}\n\nfunc (s *statsServer) mustEmbedUnimplementedStatsServiceServer() {}\n\ntype service struct {\n\tstatsManager feature_stats.Manager\n}\n\nfunc (s *service) Register(server *grpc.Server) {\n\tRegisterStatsServiceServer(server, NewStatsServer(s.statsManager))\n}\n\nfunc init() {\n\tcommon.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, cfg interface{}) (interface{}, error) {\n\t\ts := new(service)\n\n\t\tcore.RequireFeatures(ctx, func(sm feature_stats.Manager) {\n\t\t\ts.statsManager = sm\n\t\t})\n\n\t\treturn s, nil\n\t}))\n}\n"
  },
  {
    "path": "app/stats/command/command.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: app/stats/command/command.proto\n\npackage command\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype GetStatsRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Name of the stat counter.\n\tName string `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n\t// Whether or not to reset the counter to fetching its value.\n\tReset_ bool `protobuf:\"varint,2,opt,name=reset,proto3\" json:\"reset,omitempty\"`\n}\n\nfunc (x *GetStatsRequest) Reset() {\n\t*x = GetStatsRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_stats_command_command_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *GetStatsRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*GetStatsRequest) ProtoMessage() {}\n\nfunc (x *GetStatsRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_stats_command_command_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use GetStatsRequest.ProtoReflect.Descriptor instead.\nfunc (*GetStatsRequest) Descriptor() ([]byte, []int) {\n\treturn file_app_stats_command_command_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *GetStatsRequest) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *GetStatsRequest) GetReset_() bool {\n\tif x != nil {\n\t\treturn x.Reset_\n\t}\n\treturn false\n}\n\ntype Stat struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tName  string `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n\tValue int64  `protobuf:\"varint,2,opt,name=value,proto3\" json:\"value,omitempty\"`\n}\n\nfunc (x *Stat) Reset() {\n\t*x = Stat{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_stats_command_command_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Stat) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Stat) ProtoMessage() {}\n\nfunc (x *Stat) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_stats_command_command_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Stat.ProtoReflect.Descriptor instead.\nfunc (*Stat) Descriptor() ([]byte, []int) {\n\treturn file_app_stats_command_command_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *Stat) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *Stat) GetValue() int64 {\n\tif x != nil {\n\t\treturn x.Value\n\t}\n\treturn 0\n}\n\ntype GetStatsResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tStat *Stat `protobuf:\"bytes,1,opt,name=stat,proto3\" json:\"stat,omitempty\"`\n}\n\nfunc (x *GetStatsResponse) Reset() {\n\t*x = GetStatsResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_stats_command_command_proto_msgTypes[2]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *GetStatsResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*GetStatsResponse) ProtoMessage() {}\n\nfunc (x *GetStatsResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_stats_command_command_proto_msgTypes[2]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use GetStatsResponse.ProtoReflect.Descriptor instead.\nfunc (*GetStatsResponse) Descriptor() ([]byte, []int) {\n\treturn file_app_stats_command_command_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *GetStatsResponse) GetStat() *Stat {\n\tif x != nil {\n\t\treturn x.Stat\n\t}\n\treturn nil\n}\n\ntype QueryStatsRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tPattern string `protobuf:\"bytes,1,opt,name=pattern,proto3\" json:\"pattern,omitempty\"`\n\tReset_  bool   `protobuf:\"varint,2,opt,name=reset,proto3\" json:\"reset,omitempty\"`\n}\n\nfunc (x *QueryStatsRequest) Reset() {\n\t*x = QueryStatsRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_stats_command_command_proto_msgTypes[3]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *QueryStatsRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*QueryStatsRequest) ProtoMessage() {}\n\nfunc (x *QueryStatsRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_stats_command_command_proto_msgTypes[3]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use QueryStatsRequest.ProtoReflect.Descriptor instead.\nfunc (*QueryStatsRequest) Descriptor() ([]byte, []int) {\n\treturn file_app_stats_command_command_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *QueryStatsRequest) GetPattern() string {\n\tif x != nil {\n\t\treturn x.Pattern\n\t}\n\treturn \"\"\n}\n\nfunc (x *QueryStatsRequest) GetReset_() bool {\n\tif x != nil {\n\t\treturn x.Reset_\n\t}\n\treturn false\n}\n\ntype QueryStatsResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tStat []*Stat `protobuf:\"bytes,1,rep,name=stat,proto3\" json:\"stat,omitempty\"`\n}\n\nfunc (x *QueryStatsResponse) Reset() {\n\t*x = QueryStatsResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_stats_command_command_proto_msgTypes[4]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *QueryStatsResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*QueryStatsResponse) ProtoMessage() {}\n\nfunc (x *QueryStatsResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_stats_command_command_proto_msgTypes[4]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use QueryStatsResponse.ProtoReflect.Descriptor instead.\nfunc (*QueryStatsResponse) Descriptor() ([]byte, []int) {\n\treturn file_app_stats_command_command_proto_rawDescGZIP(), []int{4}\n}\n\nfunc (x *QueryStatsResponse) GetStat() []*Stat {\n\tif x != nil {\n\t\treturn x.Stat\n\t}\n\treturn nil\n}\n\ntype SysStatsRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *SysStatsRequest) Reset() {\n\t*x = SysStatsRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_stats_command_command_proto_msgTypes[5]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *SysStatsRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SysStatsRequest) ProtoMessage() {}\n\nfunc (x *SysStatsRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_stats_command_command_proto_msgTypes[5]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SysStatsRequest.ProtoReflect.Descriptor instead.\nfunc (*SysStatsRequest) Descriptor() ([]byte, []int) {\n\treturn file_app_stats_command_command_proto_rawDescGZIP(), []int{5}\n}\n\ntype SysStatsResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tNumGoroutine uint32 `protobuf:\"varint,1,opt,name=NumGoroutine,proto3\" json:\"NumGoroutine,omitempty\"`\n\tNumGC        uint32 `protobuf:\"varint,2,opt,name=NumGC,proto3\" json:\"NumGC,omitempty\"`\n\tAlloc        uint64 `protobuf:\"varint,3,opt,name=Alloc,proto3\" json:\"Alloc,omitempty\"`\n\tTotalAlloc   uint64 `protobuf:\"varint,4,opt,name=TotalAlloc,proto3\" json:\"TotalAlloc,omitempty\"`\n\tSys          uint64 `protobuf:\"varint,5,opt,name=Sys,proto3\" json:\"Sys,omitempty\"`\n\tMallocs      uint64 `protobuf:\"varint,6,opt,name=Mallocs,proto3\" json:\"Mallocs,omitempty\"`\n\tFrees        uint64 `protobuf:\"varint,7,opt,name=Frees,proto3\" json:\"Frees,omitempty\"`\n\tLiveObjects  uint64 `protobuf:\"varint,8,opt,name=LiveObjects,proto3\" json:\"LiveObjects,omitempty\"`\n\tPauseTotalNs uint64 `protobuf:\"varint,9,opt,name=PauseTotalNs,proto3\" json:\"PauseTotalNs,omitempty\"`\n\tUptime       uint32 `protobuf:\"varint,10,opt,name=Uptime,proto3\" json:\"Uptime,omitempty\"`\n}\n\nfunc (x *SysStatsResponse) Reset() {\n\t*x = SysStatsResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_stats_command_command_proto_msgTypes[6]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *SysStatsResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SysStatsResponse) ProtoMessage() {}\n\nfunc (x *SysStatsResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_stats_command_command_proto_msgTypes[6]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SysStatsResponse.ProtoReflect.Descriptor instead.\nfunc (*SysStatsResponse) Descriptor() ([]byte, []int) {\n\treturn file_app_stats_command_command_proto_rawDescGZIP(), []int{6}\n}\n\nfunc (x *SysStatsResponse) GetNumGoroutine() uint32 {\n\tif x != nil {\n\t\treturn x.NumGoroutine\n\t}\n\treturn 0\n}\n\nfunc (x *SysStatsResponse) GetNumGC() uint32 {\n\tif x != nil {\n\t\treturn x.NumGC\n\t}\n\treturn 0\n}\n\nfunc (x *SysStatsResponse) GetAlloc() uint64 {\n\tif x != nil {\n\t\treturn x.Alloc\n\t}\n\treturn 0\n}\n\nfunc (x *SysStatsResponse) GetTotalAlloc() uint64 {\n\tif x != nil {\n\t\treturn x.TotalAlloc\n\t}\n\treturn 0\n}\n\nfunc (x *SysStatsResponse) GetSys() uint64 {\n\tif x != nil {\n\t\treturn x.Sys\n\t}\n\treturn 0\n}\n\nfunc (x *SysStatsResponse) GetMallocs() uint64 {\n\tif x != nil {\n\t\treturn x.Mallocs\n\t}\n\treturn 0\n}\n\nfunc (x *SysStatsResponse) GetFrees() uint64 {\n\tif x != nil {\n\t\treturn x.Frees\n\t}\n\treturn 0\n}\n\nfunc (x *SysStatsResponse) GetLiveObjects() uint64 {\n\tif x != nil {\n\t\treturn x.LiveObjects\n\t}\n\treturn 0\n}\n\nfunc (x *SysStatsResponse) GetPauseTotalNs() uint64 {\n\tif x != nil {\n\t\treturn x.PauseTotalNs\n\t}\n\treturn 0\n}\n\nfunc (x *SysStatsResponse) GetUptime() uint32 {\n\tif x != nil {\n\t\treturn x.Uptime\n\t}\n\treturn 0\n}\n\ntype Config struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *Config) Reset() {\n\t*x = Config{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_stats_command_command_proto_msgTypes[7]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Config) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Config) ProtoMessage() {}\n\nfunc (x *Config) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_stats_command_command_proto_msgTypes[7]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Config.ProtoReflect.Descriptor instead.\nfunc (*Config) Descriptor() ([]byte, []int) {\n\treturn file_app_stats_command_command_proto_rawDescGZIP(), []int{7}\n}\n\nvar File_app_stats_command_command_proto protoreflect.FileDescriptor\n\nvar file_app_stats_command_command_proto_rawDesc = []byte{\n\t0x0a, 0x1f, 0x61, 0x70, 0x70, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2f, 0x63, 0x6f, 0x6d, 0x6d,\n\t0x61, 0x6e, 0x64, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74,\n\t0x6f, 0x12, 0x1c, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70,\n\t0x70, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x22,\n\t0x3b, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,\n\t0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,\n\t0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x65, 0x73, 0x65, 0x74, 0x18,\n\t0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x72, 0x65, 0x73, 0x65, 0x74, 0x22, 0x30, 0x0a, 0x04,\n\t0x53, 0x74, 0x61, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01,\n\t0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,\n\t0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x4a,\n\t0x0a, 0x10, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,\n\t0x73, 0x65, 0x12, 0x36, 0x0a, 0x04, 0x73, 0x74, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,\n\t0x32, 0x22, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70,\n\t0x70, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e,\n\t0x53, 0x74, 0x61, 0x74, 0x52, 0x04, 0x73, 0x74, 0x61, 0x74, 0x22, 0x43, 0x0a, 0x11, 0x51, 0x75,\n\t0x65, 0x72, 0x79, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,\n\t0x18, 0x0a, 0x07, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,\n\t0x52, 0x07, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x65, 0x73,\n\t0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x72, 0x65, 0x73, 0x65, 0x74, 0x22,\n\t0x4c, 0x0a, 0x12, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73,\n\t0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x04, 0x73, 0x74, 0x61, 0x74, 0x18, 0x01, 0x20,\n\t0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,\n\t0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61,\n\t0x6e, 0x64, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x52, 0x04, 0x73, 0x74, 0x61, 0x74, 0x22, 0x11, 0x0a,\n\t0x0f, 0x53, 0x79, 0x73, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,\n\t0x22, 0xa2, 0x02, 0x0a, 0x10, 0x53, 0x79, 0x73, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73,\n\t0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x4e, 0x75, 0x6d, 0x47, 0x6f, 0x72, 0x6f,\n\t0x75, 0x74, 0x69, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x4e, 0x75, 0x6d,\n\t0x47, 0x6f, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x4e, 0x75, 0x6d,\n\t0x47, 0x43, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x4e, 0x75, 0x6d, 0x47, 0x43, 0x12,\n\t0x14, 0x0a, 0x05, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05,\n\t0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x12, 0x1e, 0x0a, 0x0a, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x41, 0x6c,\n\t0x6c, 0x6f, 0x63, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x54, 0x6f, 0x74, 0x61, 0x6c,\n\t0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x12, 0x10, 0x0a, 0x03, 0x53, 0x79, 0x73, 0x18, 0x05, 0x20, 0x01,\n\t0x28, 0x04, 0x52, 0x03, 0x53, 0x79, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x4d, 0x61, 0x6c, 0x6c, 0x6f,\n\t0x63, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x4d, 0x61, 0x6c, 0x6c, 0x6f, 0x63,\n\t0x73, 0x12, 0x14, 0x0a, 0x05, 0x46, 0x72, 0x65, 0x65, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04,\n\t0x52, 0x05, 0x46, 0x72, 0x65, 0x65, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x4c, 0x69, 0x76, 0x65, 0x4f,\n\t0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x4c, 0x69,\n\t0x76, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x50, 0x61, 0x75,\n\t0x73, 0x65, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x4e, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52,\n\t0x0c, 0x50, 0x61, 0x75, 0x73, 0x65, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x4e, 0x73, 0x12, 0x16, 0x0a,\n\t0x06, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x55,\n\t0x70, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x08, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x32,\n\t0xde, 0x02, 0x0a, 0x0c, 0x53, 0x74, 0x61, 0x74, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,\n\t0x12, 0x6b, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x2d, 0x2e, 0x76,\n\t0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73, 0x74,\n\t0x61, 0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x53,\n\t0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x76, 0x32,\n\t0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73, 0x74, 0x61,\n\t0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74,\n\t0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x71, 0x0a,\n\t0x0a, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x2f, 0x2e, 0x76, 0x32,\n\t0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73, 0x74, 0x61,\n\t0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79,\n\t0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x76,\n\t0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73, 0x74,\n\t0x61, 0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x51, 0x75, 0x65, 0x72,\n\t0x79, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00,\n\t0x12, 0x6e, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x53, 0x79, 0x73, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12,\n\t0x2d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70,\n\t0x2e, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x53,\n\t0x79, 0x73, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e,\n\t0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e,\n\t0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x53, 0x79,\n\t0x73, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00,\n\t0x42, 0x65, 0x0a, 0x20, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,\n\t0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d,\n\t0x6d, 0x61, 0x6e, 0x64, 0x50, 0x01, 0x5a, 0x20, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,\n\t0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x73,\n\t0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0xaa, 0x02, 0x1c, 0x56, 0x32, 0x52, 0x61, 0x79,\n\t0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x2e,\n\t0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_app_stats_command_command_proto_rawDescOnce sync.Once\n\tfile_app_stats_command_command_proto_rawDescData = file_app_stats_command_command_proto_rawDesc\n)\n\nfunc file_app_stats_command_command_proto_rawDescGZIP() []byte {\n\tfile_app_stats_command_command_proto_rawDescOnce.Do(func() {\n\t\tfile_app_stats_command_command_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_stats_command_command_proto_rawDescData)\n\t})\n\treturn file_app_stats_command_command_proto_rawDescData\n}\n\nvar file_app_stats_command_command_proto_msgTypes = make([]protoimpl.MessageInfo, 8)\nvar file_app_stats_command_command_proto_goTypes = []interface{}{\n\t(*GetStatsRequest)(nil),    // 0: v2ray.core.app.stats.command.GetStatsRequest\n\t(*Stat)(nil),               // 1: v2ray.core.app.stats.command.Stat\n\t(*GetStatsResponse)(nil),   // 2: v2ray.core.app.stats.command.GetStatsResponse\n\t(*QueryStatsRequest)(nil),  // 3: v2ray.core.app.stats.command.QueryStatsRequest\n\t(*QueryStatsResponse)(nil), // 4: v2ray.core.app.stats.command.QueryStatsResponse\n\t(*SysStatsRequest)(nil),    // 5: v2ray.core.app.stats.command.SysStatsRequest\n\t(*SysStatsResponse)(nil),   // 6: v2ray.core.app.stats.command.SysStatsResponse\n\t(*Config)(nil),             // 7: v2ray.core.app.stats.command.Config\n}\nvar file_app_stats_command_command_proto_depIdxs = []int32{\n\t1, // 0: v2ray.core.app.stats.command.GetStatsResponse.stat:type_name -> v2ray.core.app.stats.command.Stat\n\t1, // 1: v2ray.core.app.stats.command.QueryStatsResponse.stat:type_name -> v2ray.core.app.stats.command.Stat\n\t0, // 2: v2ray.core.app.stats.command.StatsService.GetStats:input_type -> v2ray.core.app.stats.command.GetStatsRequest\n\t3, // 3: v2ray.core.app.stats.command.StatsService.QueryStats:input_type -> v2ray.core.app.stats.command.QueryStatsRequest\n\t5, // 4: v2ray.core.app.stats.command.StatsService.GetSysStats:input_type -> v2ray.core.app.stats.command.SysStatsRequest\n\t2, // 5: v2ray.core.app.stats.command.StatsService.GetStats:output_type -> v2ray.core.app.stats.command.GetStatsResponse\n\t4, // 6: v2ray.core.app.stats.command.StatsService.QueryStats:output_type -> v2ray.core.app.stats.command.QueryStatsResponse\n\t6, // 7: v2ray.core.app.stats.command.StatsService.GetSysStats:output_type -> v2ray.core.app.stats.command.SysStatsResponse\n\t5, // [5:8] is the sub-list for method output_type\n\t2, // [2:5] is the sub-list for method input_type\n\t2, // [2:2] is the sub-list for extension type_name\n\t2, // [2:2] is the sub-list for extension extendee\n\t0, // [0:2] is the sub-list for field type_name\n}\n\nfunc init() { file_app_stats_command_command_proto_init() }\nfunc file_app_stats_command_command_proto_init() {\n\tif File_app_stats_command_command_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_app_stats_command_command_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*GetStatsRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_stats_command_command_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Stat); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_stats_command_command_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*GetStatsResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_stats_command_command_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*QueryStatsRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_stats_command_command_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*QueryStatsResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_stats_command_command_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*SysStatsRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_stats_command_command_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*SysStatsResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_stats_command_command_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Config); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_app_stats_command_command_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   8,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   1,\n\t\t},\n\t\tGoTypes:           file_app_stats_command_command_proto_goTypes,\n\t\tDependencyIndexes: file_app_stats_command_command_proto_depIdxs,\n\t\tMessageInfos:      file_app_stats_command_command_proto_msgTypes,\n\t}.Build()\n\tFile_app_stats_command_command_proto = out.File\n\tfile_app_stats_command_command_proto_rawDesc = nil\n\tfile_app_stats_command_command_proto_goTypes = nil\n\tfile_app_stats_command_command_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "app/stats/command/command.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.app.stats.command;\noption csharp_namespace = \"V2Ray.Core.App.Stats.Command\";\noption go_package = \"v2ray.com/core/app/stats/command\";\noption java_package = \"com.v2ray.core.app.stats.command\";\noption java_multiple_files = true;\n\nmessage GetStatsRequest {\n  // Name of the stat counter.\n  string name = 1;\n  // Whether or not to reset the counter to fetching its value.\n  bool reset = 2;\n}\n\nmessage Stat {\n  string name = 1;\n  int64 value = 2;\n}\n\nmessage GetStatsResponse {\n  Stat stat = 1;\n}\n\nmessage QueryStatsRequest {\n  string pattern = 1;\n  bool reset = 2;\n}\n\nmessage QueryStatsResponse {\n  repeated Stat stat = 1;\n}\n\nmessage SysStatsRequest {}\n\nmessage SysStatsResponse {\n  uint32 NumGoroutine = 1;\n  uint32 NumGC = 2;\n  uint64 Alloc = 3;\n  uint64 TotalAlloc = 4;\n  uint64 Sys = 5;\n  uint64 Mallocs = 6;\n  uint64 Frees = 7;\n  uint64 LiveObjects = 8;\n  uint64 PauseTotalNs = 9;\n  uint32 Uptime = 10;\n}\n\nservice StatsService {\n  rpc GetStats(GetStatsRequest) returns (GetStatsResponse) {}\n  rpc QueryStats(QueryStatsRequest) returns (QueryStatsResponse) {}\n  rpc GetSysStats(SysStatsRequest) returns (SysStatsResponse) {}\n}\n\nmessage Config {}\n"
  },
  {
    "path": "app/stats/command/command_grpc.pb.go",
    "content": "// Code generated by protoc-gen-go-grpc. DO NOT EDIT.\n\npackage command\n\nimport (\n\tcontext \"context\"\n\tgrpc \"google.golang.org/grpc\"\n\tcodes \"google.golang.org/grpc/codes\"\n\tstatus \"google.golang.org/grpc/status\"\n)\n\n// This is a compile-time assertion to ensure that this generated file\n// is compatible with the grpc package it is being compiled against.\nconst _ = grpc.SupportPackageIsVersion7\n\n// StatsServiceClient is the client API for StatsService service.\n//\n// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.\ntype StatsServiceClient interface {\n\tGetStats(ctx context.Context, in *GetStatsRequest, opts ...grpc.CallOption) (*GetStatsResponse, error)\n\tQueryStats(ctx context.Context, in *QueryStatsRequest, opts ...grpc.CallOption) (*QueryStatsResponse, error)\n\tGetSysStats(ctx context.Context, in *SysStatsRequest, opts ...grpc.CallOption) (*SysStatsResponse, error)\n}\n\ntype statsServiceClient struct {\n\tcc grpc.ClientConnInterface\n}\n\nfunc NewStatsServiceClient(cc grpc.ClientConnInterface) StatsServiceClient {\n\treturn &statsServiceClient{cc}\n}\n\nfunc (c *statsServiceClient) GetStats(ctx context.Context, in *GetStatsRequest, opts ...grpc.CallOption) (*GetStatsResponse, error) {\n\tout := new(GetStatsResponse)\n\terr := c.cc.Invoke(ctx, \"/v2ray.core.app.stats.command.StatsService/GetStats\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *statsServiceClient) QueryStats(ctx context.Context, in *QueryStatsRequest, opts ...grpc.CallOption) (*QueryStatsResponse, error) {\n\tout := new(QueryStatsResponse)\n\terr := c.cc.Invoke(ctx, \"/v2ray.core.app.stats.command.StatsService/QueryStats\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *statsServiceClient) GetSysStats(ctx context.Context, in *SysStatsRequest, opts ...grpc.CallOption) (*SysStatsResponse, error) {\n\tout := new(SysStatsResponse)\n\terr := c.cc.Invoke(ctx, \"/v2ray.core.app.stats.command.StatsService/GetSysStats\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\n// StatsServiceServer is the server API for StatsService service.\n// All implementations must embed UnimplementedStatsServiceServer\n// for forward compatibility\ntype StatsServiceServer interface {\n\tGetStats(context.Context, *GetStatsRequest) (*GetStatsResponse, error)\n\tQueryStats(context.Context, *QueryStatsRequest) (*QueryStatsResponse, error)\n\tGetSysStats(context.Context, *SysStatsRequest) (*SysStatsResponse, error)\n\tmustEmbedUnimplementedStatsServiceServer()\n}\n\n// UnimplementedStatsServiceServer must be embedded to have forward compatible implementations.\ntype UnimplementedStatsServiceServer struct {\n}\n\nfunc (UnimplementedStatsServiceServer) GetStats(context.Context, *GetStatsRequest) (*GetStatsResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method GetStats not implemented\")\n}\nfunc (UnimplementedStatsServiceServer) QueryStats(context.Context, *QueryStatsRequest) (*QueryStatsResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method QueryStats not implemented\")\n}\nfunc (UnimplementedStatsServiceServer) GetSysStats(context.Context, *SysStatsRequest) (*SysStatsResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method GetSysStats not implemented\")\n}\nfunc (UnimplementedStatsServiceServer) mustEmbedUnimplementedStatsServiceServer() {}\n\n// UnsafeStatsServiceServer may be embedded to opt out of forward compatibility for this service.\n// Use of this interface is not recommended, as added methods to StatsServiceServer will\n// result in compilation errors.\ntype UnsafeStatsServiceServer interface {\n\tmustEmbedUnimplementedStatsServiceServer()\n}\n\nfunc RegisterStatsServiceServer(s *grpc.Server, srv StatsServiceServer) {\n\ts.RegisterService(&_StatsService_serviceDesc, srv)\n}\n\nfunc _StatsService_GetStats_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(GetStatsRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(StatsServiceServer).GetStats(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/v2ray.core.app.stats.command.StatsService/GetStats\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(StatsServiceServer).GetStats(ctx, req.(*GetStatsRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _StatsService_QueryStats_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(QueryStatsRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(StatsServiceServer).QueryStats(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/v2ray.core.app.stats.command.StatsService/QueryStats\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(StatsServiceServer).QueryStats(ctx, req.(*QueryStatsRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _StatsService_GetSysStats_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(SysStatsRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(StatsServiceServer).GetSysStats(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/v2ray.core.app.stats.command.StatsService/GetSysStats\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(StatsServiceServer).GetSysStats(ctx, req.(*SysStatsRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nvar _StatsService_serviceDesc = grpc.ServiceDesc{\n\tServiceName: \"v2ray.core.app.stats.command.StatsService\",\n\tHandlerType: (*StatsServiceServer)(nil),\n\tMethods: []grpc.MethodDesc{\n\t\t{\n\t\t\tMethodName: \"GetStats\",\n\t\t\tHandler:    _StatsService_GetStats_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"QueryStats\",\n\t\t\tHandler:    _StatsService_QueryStats_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"GetSysStats\",\n\t\t\tHandler:    _StatsService_GetSysStats_Handler,\n\t\t},\n\t},\n\tStreams:  []grpc.StreamDesc{},\n\tMetadata: \"app/stats/command/command.proto\",\n}\n"
  },
  {
    "path": "app/stats/command/command_test.go",
    "content": "package command_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/google/go-cmp/cmp/cmpopts\"\n\n\t\"v2ray.com/core/app/stats\"\n\t. \"v2ray.com/core/app/stats/command\"\n\t\"v2ray.com/core/common\"\n)\n\nfunc TestGetStats(t *testing.T) {\n\tm, err := stats.NewManager(context.Background(), &stats.Config{})\n\tcommon.Must(err)\n\n\tsc, err := m.RegisterCounter(\"test_counter\")\n\tcommon.Must(err)\n\n\tsc.Set(1)\n\n\ts := NewStatsServer(m)\n\n\ttestCases := []struct {\n\t\tname  string\n\t\treset bool\n\t\tvalue int64\n\t\terr   bool\n\t}{\n\t\t{\n\t\t\tname: \"counterNotExist\",\n\t\t\terr:  true,\n\t\t},\n\t\t{\n\t\t\tname:  \"test_counter\",\n\t\t\treset: true,\n\t\t\tvalue: 1,\n\t\t},\n\t\t{\n\t\t\tname:  \"test_counter\",\n\t\t\tvalue: 0,\n\t\t},\n\t}\n\tfor _, tc := range testCases {\n\t\tresp, err := s.GetStats(context.Background(), &GetStatsRequest{\n\t\t\tName:   tc.name,\n\t\t\tReset_: tc.reset,\n\t\t})\n\t\tif tc.err {\n\t\t\tif err == nil {\n\t\t\t\tt.Error(\"nil error: \", tc.name)\n\t\t\t}\n\t\t} else {\n\t\t\tcommon.Must(err)\n\t\t\tif r := cmp.Diff(resp.Stat, &Stat{Name: tc.name, Value: tc.value}, cmpopts.IgnoreUnexported(Stat{})); r != \"\" {\n\t\t\t\tt.Error(r)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc TestQueryStats(t *testing.T) {\n\tm, err := stats.NewManager(context.Background(), &stats.Config{})\n\tcommon.Must(err)\n\n\tsc1, err := m.RegisterCounter(\"test_counter\")\n\tcommon.Must(err)\n\tsc1.Set(1)\n\n\tsc2, err := m.RegisterCounter(\"test_counter_2\")\n\tcommon.Must(err)\n\tsc2.Set(2)\n\n\tsc3, err := m.RegisterCounter(\"test_counter_3\")\n\tcommon.Must(err)\n\tsc3.Set(3)\n\n\ts := NewStatsServer(m)\n\tresp, err := s.QueryStats(context.Background(), &QueryStatsRequest{\n\t\tPattern: \"counter_\",\n\t})\n\tcommon.Must(err)\n\tif r := cmp.Diff(resp.Stat, []*Stat{\n\t\t{Name: \"test_counter_2\", Value: 2},\n\t\t{Name: \"test_counter_3\", Value: 3},\n\t}, cmpopts.SortSlices(func(s1, s2 *Stat) bool { return s1.Name < s2.Name }),\n\t\tcmpopts.IgnoreUnexported(Stat{})); r != \"\" {\n\t\tt.Error(r)\n\t}\n}\n"
  },
  {
    "path": "app/stats/command/errors.generated.go",
    "content": "package command\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "app/stats/config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: app/stats/config.proto\n\npackage stats\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype Config struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *Config) Reset() {\n\t*x = Config{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_stats_config_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Config) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Config) ProtoMessage() {}\n\nfunc (x *Config) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_stats_config_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Config.ProtoReflect.Descriptor instead.\nfunc (*Config) Descriptor() ([]byte, []int) {\n\treturn file_app_stats_config_proto_rawDescGZIP(), []int{0}\n}\n\ntype ChannelConfig struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tBlocking        bool  `protobuf:\"varint,1,opt,name=Blocking,proto3\" json:\"Blocking,omitempty\"`\n\tSubscriberLimit int32 `protobuf:\"varint,2,opt,name=SubscriberLimit,proto3\" json:\"SubscriberLimit,omitempty\"`\n\tBufferSize      int32 `protobuf:\"varint,3,opt,name=BufferSize,proto3\" json:\"BufferSize,omitempty\"`\n}\n\nfunc (x *ChannelConfig) Reset() {\n\t*x = ChannelConfig{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_app_stats_config_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *ChannelConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ChannelConfig) ProtoMessage() {}\n\nfunc (x *ChannelConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_app_stats_config_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ChannelConfig.ProtoReflect.Descriptor instead.\nfunc (*ChannelConfig) Descriptor() ([]byte, []int) {\n\treturn file_app_stats_config_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *ChannelConfig) GetBlocking() bool {\n\tif x != nil {\n\t\treturn x.Blocking\n\t}\n\treturn false\n}\n\nfunc (x *ChannelConfig) GetSubscriberLimit() int32 {\n\tif x != nil {\n\t\treturn x.SubscriberLimit\n\t}\n\treturn 0\n}\n\nfunc (x *ChannelConfig) GetBufferSize() int32 {\n\tif x != nil {\n\t\treturn x.BufferSize\n\t}\n\treturn 0\n}\n\nvar File_app_stats_config_proto protoreflect.FileDescriptor\n\nvar file_app_stats_config_proto_rawDesc = []byte{\n\t0x0a, 0x16, 0x61, 0x70, 0x70, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x66,\n\t0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x14, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,\n\t0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x73, 0x22, 0x08,\n\t0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x75, 0x0a, 0x0d, 0x43, 0x68, 0x61, 0x6e,\n\t0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x42, 0x6c, 0x6f,\n\t0x63, 0x6b, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x42, 0x6c, 0x6f,\n\t0x63, 0x6b, 0x69, 0x6e, 0x67, 0x12, 0x28, 0x0a, 0x0f, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69,\n\t0x62, 0x65, 0x72, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f,\n\t0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x72, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12,\n\t0x1e, 0x0a, 0x0a, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20,\n\t0x01, 0x28, 0x05, 0x52, 0x0a, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x53, 0x69, 0x7a, 0x65, 0x42,\n\t0x4d, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72,\n\t0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x73, 0x50, 0x01, 0x5a, 0x18, 0x76,\n\t0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70,\n\t0x70, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x73, 0xaa, 0x02, 0x14, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e,\n\t0x43, 0x6f, 0x72, 0x65, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x62, 0x06,\n\t0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_app_stats_config_proto_rawDescOnce sync.Once\n\tfile_app_stats_config_proto_rawDescData = file_app_stats_config_proto_rawDesc\n)\n\nfunc file_app_stats_config_proto_rawDescGZIP() []byte {\n\tfile_app_stats_config_proto_rawDescOnce.Do(func() {\n\t\tfile_app_stats_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_stats_config_proto_rawDescData)\n\t})\n\treturn file_app_stats_config_proto_rawDescData\n}\n\nvar file_app_stats_config_proto_msgTypes = make([]protoimpl.MessageInfo, 2)\nvar file_app_stats_config_proto_goTypes = []interface{}{\n\t(*Config)(nil),        // 0: v2ray.core.app.stats.Config\n\t(*ChannelConfig)(nil), // 1: v2ray.core.app.stats.ChannelConfig\n}\nvar file_app_stats_config_proto_depIdxs = []int32{\n\t0, // [0:0] is the sub-list for method output_type\n\t0, // [0:0] is the sub-list for method input_type\n\t0, // [0:0] is the sub-list for extension type_name\n\t0, // [0:0] is the sub-list for extension extendee\n\t0, // [0:0] is the sub-list for field type_name\n}\n\nfunc init() { file_app_stats_config_proto_init() }\nfunc file_app_stats_config_proto_init() {\n\tif File_app_stats_config_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_app_stats_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Config); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_app_stats_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*ChannelConfig); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_app_stats_config_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   2,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_app_stats_config_proto_goTypes,\n\t\tDependencyIndexes: file_app_stats_config_proto_depIdxs,\n\t\tMessageInfos:      file_app_stats_config_proto_msgTypes,\n\t}.Build()\n\tFile_app_stats_config_proto = out.File\n\tfile_app_stats_config_proto_rawDesc = nil\n\tfile_app_stats_config_proto_goTypes = nil\n\tfile_app_stats_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "app/stats/config.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.app.stats;\noption csharp_namespace = \"V2Ray.Core.App.Stats\";\noption go_package = \"v2ray.com/core/app/stats\";\noption java_package = \"com.v2ray.core.app.stats\";\noption java_multiple_files = true;\n\nmessage Config {}\n\nmessage ChannelConfig {\n  bool Blocking = 1;\n  int32 SubscriberLimit = 2;\n  int32 BufferSize = 3;\n}\n"
  },
  {
    "path": "app/stats/counter.go",
    "content": "// +build !confonly\n\npackage stats\n\nimport \"sync/atomic\"\n\n// Counter is an implementation of stats.Counter.\ntype Counter struct {\n\tvalue int64\n}\n\n// Value implements stats.Counter.\nfunc (c *Counter) Value() int64 {\n\treturn atomic.LoadInt64(&c.value)\n}\n\n// Set implements stats.Counter.\nfunc (c *Counter) Set(newValue int64) int64 {\n\treturn atomic.SwapInt64(&c.value, newValue)\n}\n\n// Add implements stats.Counter.\nfunc (c *Counter) Add(delta int64) int64 {\n\treturn atomic.AddInt64(&c.value, delta)\n}\n"
  },
  {
    "path": "app/stats/counter_test.go",
    "content": "package stats_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t. \"v2ray.com/core/app/stats\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/features/stats\"\n)\n\nfunc TestStatsCounter(t *testing.T) {\n\traw, err := common.CreateObject(context.Background(), &Config{})\n\tcommon.Must(err)\n\n\tm := raw.(stats.Manager)\n\tc, err := m.RegisterCounter(\"test.counter\")\n\tcommon.Must(err)\n\n\tif v := c.Add(1); v != 1 {\n\t\tt.Fatal(\"unpexcted Add(1) return: \", v, \", wanted \", 1)\n\t}\n\n\tif v := c.Set(0); v != 1 {\n\t\tt.Fatal(\"unexpected Set(0) return: \", v, \", wanted \", 1)\n\t}\n\n\tif v := c.Value(); v != 0 {\n\t\tt.Fatal(\"unexpected Value() return: \", v, \", wanted \", 0)\n\t}\n}\n"
  },
  {
    "path": "app/stats/errors.generated.go",
    "content": "package stats\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "app/stats/stats.go",
    "content": "// +build !confonly\n\npackage stats\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n\nimport (\n\t\"context\"\n\t\"sync\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/errors\"\n\t\"v2ray.com/core/features/stats\"\n)\n\n// Manager is an implementation of stats.Manager.\ntype Manager struct {\n\taccess   sync.RWMutex\n\tcounters map[string]*Counter\n\tchannels map[string]*Channel\n\trunning  bool\n}\n\n// NewManager creates an instance of Statistics Manager.\nfunc NewManager(ctx context.Context, config *Config) (*Manager, error) {\n\tm := &Manager{\n\t\tcounters: make(map[string]*Counter),\n\t\tchannels: make(map[string]*Channel),\n\t}\n\n\treturn m, nil\n}\n\n// Type implements common.HasType.\nfunc (*Manager) Type() interface{} {\n\treturn stats.ManagerType()\n}\n\n// RegisterCounter implements stats.Manager.\nfunc (m *Manager) RegisterCounter(name string) (stats.Counter, error) {\n\tm.access.Lock()\n\tdefer m.access.Unlock()\n\n\tif _, found := m.counters[name]; found {\n\t\treturn nil, newError(\"Counter \", name, \" already registered.\")\n\t}\n\tnewError(\"create new counter \", name).AtDebug().WriteToLog()\n\tc := new(Counter)\n\tm.counters[name] = c\n\treturn c, nil\n}\n\n// UnregisterCounter implements stats.Manager.\nfunc (m *Manager) UnregisterCounter(name string) error {\n\tm.access.Lock()\n\tdefer m.access.Unlock()\n\n\tif _, found := m.counters[name]; found {\n\t\tnewError(\"remove counter \", name).AtDebug().WriteToLog()\n\t\tdelete(m.counters, name)\n\t}\n\treturn nil\n}\n\n// GetCounter implements stats.Manager.\nfunc (m *Manager) GetCounter(name string) stats.Counter {\n\tm.access.RLock()\n\tdefer m.access.RUnlock()\n\n\tif c, found := m.counters[name]; found {\n\t\treturn c\n\t}\n\treturn nil\n}\n\n// VisitCounters calls visitor function on all managed counters.\nfunc (m *Manager) VisitCounters(visitor func(string, stats.Counter) bool) {\n\tm.access.RLock()\n\tdefer m.access.RUnlock()\n\n\tfor name, c := range m.counters {\n\t\tif !visitor(name, c) {\n\t\t\tbreak\n\t\t}\n\t}\n}\n\n// RegisterChannel implements stats.Manager.\nfunc (m *Manager) RegisterChannel(name string) (stats.Channel, error) {\n\tm.access.Lock()\n\tdefer m.access.Unlock()\n\n\tif _, found := m.channels[name]; found {\n\t\treturn nil, newError(\"Channel \", name, \" already registered.\")\n\t}\n\tnewError(\"create new channel \", name).AtDebug().WriteToLog()\n\tc := NewChannel(&ChannelConfig{BufferSize: 64, Blocking: false})\n\tm.channels[name] = c\n\tif m.running {\n\t\treturn c, c.Start()\n\t}\n\treturn c, nil\n}\n\n// UnregisterChannel implements stats.Manager.\nfunc (m *Manager) UnregisterChannel(name string) error {\n\tm.access.Lock()\n\tdefer m.access.Unlock()\n\n\tif c, found := m.channels[name]; found {\n\t\tnewError(\"remove channel \", name).AtDebug().WriteToLog()\n\t\tdelete(m.channels, name)\n\t\treturn c.Close()\n\t}\n\treturn nil\n}\n\n// GetChannel implements stats.Manager.\nfunc (m *Manager) GetChannel(name string) stats.Channel {\n\tm.access.RLock()\n\tdefer m.access.RUnlock()\n\n\tif c, found := m.channels[name]; found {\n\t\treturn c\n\t}\n\treturn nil\n}\n\n// Start implements common.Runnable.\nfunc (m *Manager) Start() error {\n\tm.access.Lock()\n\tdefer m.access.Unlock()\n\tm.running = true\n\terrs := []error{}\n\tfor _, channel := range m.channels {\n\t\tif err := channel.Start(); err != nil {\n\t\t\terrs = append(errs, err)\n\t\t}\n\t}\n\tif len(errs) != 0 {\n\t\treturn errors.Combine(errs...)\n\t}\n\treturn nil\n}\n\n// Close implement common.Closable.\nfunc (m *Manager) Close() error {\n\tm.access.Lock()\n\tdefer m.access.Unlock()\n\tm.running = false\n\terrs := []error{}\n\tfor name, channel := range m.channels {\n\t\tnewError(\"remove channel \", name).AtDebug().WriteToLog()\n\t\tdelete(m.channels, name)\n\t\tif err := channel.Close(); err != nil {\n\t\t\terrs = append(errs, err)\n\t\t}\n\t}\n\tif len(errs) != 0 {\n\t\treturn errors.Combine(errs...)\n\t}\n\treturn nil\n}\n\nfunc init() {\n\tcommon.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {\n\t\treturn NewManager(ctx, config.(*Config))\n\t}))\n}"
  },
  {
    "path": "app/stats/stats_test.go",
    "content": "package stats_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t. \"v2ray.com/core/app/stats\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/features/stats\"\n)\n\nfunc TestInterface(t *testing.T) {\n\t_ = (stats.Manager)(new(Manager))\n}\n\nfunc TestStatsChannelRunnable(t *testing.T) {\n\traw, err := common.CreateObject(context.Background(), &Config{})\n\tcommon.Must(err)\n\n\tm := raw.(stats.Manager)\n\n\tch1, err := m.RegisterChannel(\"test.channel.1\")\n\tc1 := ch1.(*Channel)\n\tcommon.Must(err)\n\n\tif c1.Running() {\n\t\tt.Fatalf(\"unexpected running channel: test.channel.%d\", 1)\n\t}\n\n\tcommon.Must(m.Start())\n\n\tif !c1.Running() {\n\t\tt.Fatalf(\"unexpected non-running channel: test.channel.%d\", 1)\n\t}\n\n\tch2, err := m.RegisterChannel(\"test.channel.2\")\n\tc2 := ch2.(*Channel)\n\tcommon.Must(err)\n\n\tif !c2.Running() {\n\t\tt.Fatalf(\"unexpected non-running channel: test.channel.%d\", 2)\n\t}\n\n\ts1, err := c1.Subscribe()\n\tcommon.Must(err)\n\tcommon.Must(c1.Close())\n\n\tif c1.Running() {\n\t\tt.Fatalf(\"unexpected running channel: test.channel.%d\", 1)\n\t}\n\n\tselect { // Check all subscribers in closed channel are closed\n\tcase _, ok := <-s1:\n\t\tif ok {\n\t\t\tt.Fatalf(\"unexpected non-closed subscriber in channel: test.channel.%d\", 1)\n\t\t}\n\tcase <-time.After(500 * time.Millisecond):\n\t\tt.Fatalf(\"unexpected non-closed subscriber in channel: test.channel.%d\", 1)\n\t}\n\n\tif len(c1.Subscribers()) != 0 { // Check subscribers in closed channel are emptied\n\t\tt.Fatalf(\"unexpected non-empty subscribers in channel: test.channel.%d\", 1)\n\t}\n\n\tcommon.Must(m.Close())\n\n\tif c2.Running() {\n\t\tt.Fatalf(\"unexpected running channel: test.channel.%d\", 2)\n\t}\n\n\tch3, err := m.RegisterChannel(\"test.channel.3\")\n\tc3 := ch3.(*Channel)\n\tcommon.Must(err)\n\n\tif c3.Running() {\n\t\tt.Fatalf(\"unexpected running channel: test.channel.%d\", 3)\n\t}\n\n\tcommon.Must(c3.Start())\n\tcommon.Must(m.UnregisterChannel(\"test.channel.3\"))\n\n\tif c3.Running() { // Test that unregistering will close the channel.\n\t\tt.Fatalf(\"unexpected running channel: test.channel.%d\", 3)\n\t}\n}\n"
  },
  {
    "path": "azure-pipelines.yml",
    "content": "trigger:\n  batch: true\n  branches:\n    include:\n      - master\n      - dev*\n      - refs/tags/*\n\npool:\n  vmImage: \"ubuntu-latest\"\n\nvariables:\n  - group: GithubToken\n\nsteps:\n  - checkout: self\n  - task: GoTool@0\n    inputs:\n      version: \"1.15.2\"\n  - script: |\n      go version\n      go mod download\n    workingDirectory: $(system.defaultWorkingDirectory)\n    displayName: \"Fetch sources\"\n  - script: |\n      bazel build --action_env=PATH=$PATH --action_env=GOPATH=$(go env GOPATH) --action_env=GOCACHE=$(go env GOCACHE) --action_env=SPWD=$(pwd) --spawn_strategy local //release:all\n    workingDirectory: $(system.defaultWorkingDirectory)\n    displayName: \"Build Binaries\"\n  - script: |\n      echo $RELEASE_TAG\n      ./release/bleedingrelease.sh\n    workingDirectory: $(system.defaultWorkingDirectory)\n    displayName: \"Generate Bleeding Edge Release\"\n    env:\n      WORKDIR: $(system.defaultWorkingDirectory)\n      GITHUB_TOKEN: $(GITHUB_TOKEN)\n      PRERELEASE: true\n      RELEASE_TAG: unstable-$(Build.SourceVersion)\n      RELEASE_SHA: $(Build.SourceVersion)\n      TRIGGER_REASON: $(Build.SourceBranch)\n      GITHUB_REPO_OWNER: v2fly\n      GITHUB_REPO_NAME: v2ray-core\n  - script: |\n      echo $RELEASE_TAG\n      ./release/tagrelease.sh\n    workingDirectory: $(system.defaultWorkingDirectory)\n    displayName: \"Generate Tag Release\"\n    env:\n      WORKDIR: $(system.defaultWorkingDirectory)\n      GITHUB_TOKEN: $(GITHUB_TOKEN)\n      PRERELEASE: true\n      RELEASE_TAG: unstable-$(Build.SourceVersion)\n      RELEASE_SHA: $(Build.SourceVersion)\n      TRIGGER_REASON: $(Build.SourceBranch)\n"
  },
  {
    "path": "common/antireplay/antireplay.go",
    "content": "package antireplay\n\nimport (\n\tcuckoo \"github.com/seiflotfy/cuckoofilter\"\n\t\"sync\"\n\t\"time\"\n)\n\nfunc NewAntiReplayWindow(AntiReplayTime int64) *AntiReplayWindow {\n\tarw := &AntiReplayWindow{}\n\tarw.AntiReplayTime = AntiReplayTime\n\treturn arw\n}\n\ntype AntiReplayWindow struct {\n\tlock           sync.Mutex\n\tpoolA          *cuckoo.Filter\n\tpoolB          *cuckoo.Filter\n\tlastSwapTime   int64\n\tPoolSwap       bool\n\tAntiReplayTime int64\n}\n\nfunc (aw *AntiReplayWindow) Check(sum []byte) bool {\n\taw.lock.Lock()\n\n\tif aw.lastSwapTime == 0 {\n\t\taw.lastSwapTime = time.Now().Unix()\n\t\taw.poolA = cuckoo.NewFilter(100000)\n\t\taw.poolB = cuckoo.NewFilter(100000)\n\t}\n\n\ttnow := time.Now().Unix()\n\ttimediff := tnow - aw.lastSwapTime\n\n\tif timediff >= aw.AntiReplayTime {\n\t\tif aw.PoolSwap {\n\t\t\taw.PoolSwap = false\n\t\t\taw.poolA.Reset()\n\t\t} else {\n\t\t\taw.PoolSwap = true\n\t\t\taw.poolB.Reset()\n\t\t}\n\t\taw.lastSwapTime = tnow\n\t}\n\n\tret := aw.poolA.InsertUnique(sum) && aw.poolB.InsertUnique(sum)\n\taw.lock.Unlock()\n\treturn ret\n}\n"
  },
  {
    "path": "common/bitmask/byte.go",
    "content": "package bitmask\n\n// Byte is a bitmask in byte.\ntype Byte byte\n\n// Has returns true if this bitmask contains another bitmask.\nfunc (b Byte) Has(bb Byte) bool {\n\treturn (b & bb) != 0\n}\n\nfunc (b *Byte) Set(bb Byte) {\n\t*b |= bb\n}\n\nfunc (b *Byte) Clear(bb Byte) {\n\t*b &= ^bb\n}\n\nfunc (b *Byte) Toggle(bb Byte) {\n\t*b ^= bb\n}\n"
  },
  {
    "path": "common/bitmask/byte_test.go",
    "content": "package bitmask_test\n\nimport (\n\t\"testing\"\n\n\t. \"v2ray.com/core/common/bitmask\"\n)\n\nfunc TestBitmaskByte(t *testing.T) {\n\tb := Byte(0)\n\tb.Set(Byte(1))\n\tif !b.Has(1) {\n\t\tt.Fatal(\"expected \", b, \" to contain 1, but actually not\")\n\t}\n\n\tb.Set(Byte(2))\n\tif !b.Has(2) {\n\t\tt.Fatal(\"expected \", b, \" to contain 2, but actually not\")\n\t}\n\tif !b.Has(1) {\n\t\tt.Fatal(\"expected \", b, \" to contain 1, but actually not\")\n\t}\n\n\tb.Clear(Byte(1))\n\tif !b.Has(2) {\n\t\tt.Fatal(\"expected \", b, \" to contain 2, but actually not\")\n\t}\n\tif b.Has(1) {\n\t\tt.Fatal(\"expected \", b, \" to not contain 1, but actually did\")\n\t}\n\n\tb.Toggle(Byte(2))\n\tif b.Has(2) {\n\t\tt.Fatal(\"expected \", b, \" to not contain 2, but actually did\")\n\t}\n}\n"
  },
  {
    "path": "common/buf/buf.go",
    "content": "// Package buf provides a light-weight memory allocation mechanism.\npackage buf // import \"v2ray.com/core/common/buf\"\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n"
  },
  {
    "path": "common/buf/buffer.go",
    "content": "package buf\n\nimport (\n\t\"io\"\n\n\t\"v2ray.com/core/common/bytespool\"\n)\n\nconst (\n\t// Size of a regular buffer.\n\tSize = 2048\n)\n\n// Buffer is a recyclable allocation of a byte array. Buffer.Release() recycles\n// the buffer into an internal buffer pool, in order to recreate a buffer more\n// quickly.\ntype Buffer struct {\n\tv     []byte\n\tstart int32\n\tend   int32\n}\n\n// Release recycles the buffer into an internal buffer pool.\nfunc (b *Buffer) Release() {\n\tif b == nil || b.v == nil {\n\t\treturn\n\t}\n\n\tp := b.v\n\tb.v = nil\n\tb.Clear()\n\tpool.Put(p)\n}\n\n// Clear clears the content of the buffer, results an empty buffer with\n// Len() = 0.\nfunc (b *Buffer) Clear() {\n\tb.start = 0\n\tb.end = 0\n}\n\n// Byte returns the bytes at index.\nfunc (b *Buffer) Byte(index int32) byte {\n\treturn b.v[b.start+index]\n}\n\n// SetByte sets the byte value at index.\nfunc (b *Buffer) SetByte(index int32, value byte) {\n\tb.v[b.start+index] = value\n}\n\n// Bytes returns the content bytes of this Buffer.\nfunc (b *Buffer) Bytes() []byte {\n\treturn b.v[b.start:b.end]\n}\n\n// Extend increases the buffer size by n bytes, and returns the extended part.\n// It panics if result size is larger than buf.Size.\nfunc (b *Buffer) Extend(n int32) []byte {\n\tend := b.end + n\n\tif end > int32(len(b.v)) {\n\t\tpanic(\"extending out of bound\")\n\t}\n\text := b.v[b.end:end]\n\tb.end = end\n\treturn ext\n}\n\n// BytesRange returns a slice of this buffer with given from and to boundary.\nfunc (b *Buffer) BytesRange(from, to int32) []byte {\n\tif from < 0 {\n\t\tfrom += b.Len()\n\t}\n\tif to < 0 {\n\t\tto += b.Len()\n\t}\n\treturn b.v[b.start+from : b.start+to]\n}\n\n// BytesFrom returns a slice of this Buffer starting from the given position.\nfunc (b *Buffer) BytesFrom(from int32) []byte {\n\tif from < 0 {\n\t\tfrom += b.Len()\n\t}\n\treturn b.v[b.start+from : b.end]\n}\n\n// BytesTo returns a slice of this Buffer from start to the given position.\nfunc (b *Buffer) BytesTo(to int32) []byte {\n\tif to < 0 {\n\t\tto += b.Len()\n\t}\n\treturn b.v[b.start : b.start+to]\n}\n\n// Resize cuts the buffer at the given position.\nfunc (b *Buffer) Resize(from, to int32) {\n\tif from < 0 {\n\t\tfrom += b.Len()\n\t}\n\tif to < 0 {\n\t\tto += b.Len()\n\t}\n\tif to < from {\n\t\tpanic(\"Invalid slice\")\n\t}\n\tb.end = b.start + to\n\tb.start += from\n}\n\n// Advance cuts the buffer at the given position.\nfunc (b *Buffer) Advance(from int32) {\n\tif from < 0 {\n\t\tfrom += b.Len()\n\t}\n\tb.start += from\n}\n\n// Len returns the length of the buffer content.\nfunc (b *Buffer) Len() int32 {\n\tif b == nil {\n\t\treturn 0\n\t}\n\treturn b.end - b.start\n}\n\n// IsEmpty returns true if the buffer is empty.\nfunc (b *Buffer) IsEmpty() bool {\n\treturn b.Len() == 0\n}\n\n// IsFull returns true if the buffer has no more room to grow.\nfunc (b *Buffer) IsFull() bool {\n\treturn b != nil && b.end == int32(len(b.v))\n}\n\n// Write implements Write method in io.Writer.\nfunc (b *Buffer) Write(data []byte) (int, error) {\n\tnBytes := copy(b.v[b.end:], data)\n\tb.end += int32(nBytes)\n\treturn nBytes, nil\n}\n\n// WriteByte writes a single byte into the buffer.\nfunc (b *Buffer) WriteByte(v byte) error {\n\tif b.IsFull() {\n\t\treturn newError(\"buffer full\")\n\t}\n\tb.v[b.end] = v\n\tb.end++\n\treturn nil\n}\n\n// WriteString implements io.StringWriter.\nfunc (b *Buffer) WriteString(s string) (int, error) {\n\treturn b.Write([]byte(s))\n}\n\n// Read implements io.Reader.Read().\nfunc (b *Buffer) Read(data []byte) (int, error) {\n\tif b.Len() == 0 {\n\t\treturn 0, io.EOF\n\t}\n\tnBytes := copy(data, b.v[b.start:b.end])\n\tif int32(nBytes) == b.Len() {\n\t\tb.Clear()\n\t} else {\n\t\tb.start += int32(nBytes)\n\t}\n\treturn nBytes, nil\n}\n\n// ReadFrom implements io.ReaderFrom.\nfunc (b *Buffer) ReadFrom(reader io.Reader) (int64, error) {\n\tn, err := reader.Read(b.v[b.end:])\n\tb.end += int32(n)\n\treturn int64(n), err\n}\n\n// ReadFullFrom reads exact size of bytes from given reader, or until error occurs.\nfunc (b *Buffer) ReadFullFrom(reader io.Reader, size int32) (int64, error) {\n\tend := b.end + size\n\tif end > int32(len(b.v)) {\n\t\tv := end\n\t\treturn 0, newError(\"out of bound: \", v)\n\t}\n\tn, err := io.ReadFull(reader, b.v[b.end:end])\n\tb.end += int32(n)\n\treturn int64(n), err\n}\n\n// String returns the string form of this Buffer.\nfunc (b *Buffer) String() string {\n\treturn string(b.Bytes())\n}\n\nvar pool = bytespool.GetPool(Size)\n\n// New creates a Buffer with 0 length and 2K capacity.\nfunc New() *Buffer {\n\treturn &Buffer{\n\t\tv: pool.Get().([]byte),\n\t}\n}\n\n// StackNew creates a new Buffer object on stack.\n// This method is for buffers that is released in the same function.\nfunc StackNew() Buffer {\n\treturn Buffer{\n\t\tv: pool.Get().([]byte),\n\t}\n}\n"
  },
  {
    "path": "common/buf/buffer_test.go",
    "content": "package buf_test\n\nimport (\n\t\"bytes\"\n\t\"crypto/rand\"\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"v2ray.com/core/common\"\n\t. \"v2ray.com/core/common/buf\"\n)\n\nfunc TestBufferClear(t *testing.T) {\n\tbuffer := New()\n\tdefer buffer.Release()\n\n\tpayload := \"Bytes\"\n\tbuffer.Write([]byte(payload))\n\tif diff := cmp.Diff(buffer.Bytes(), []byte(payload)); diff != \"\" {\n\t\tt.Error(diff)\n\t}\n\n\tbuffer.Clear()\n\tif buffer.Len() != 0 {\n\t\tt.Error(\"expect 0 length, but got \", buffer.Len())\n\t}\n}\n\nfunc TestBufferIsEmpty(t *testing.T) {\n\tbuffer := New()\n\tdefer buffer.Release()\n\n\tif buffer.IsEmpty() != true {\n\t\tt.Error(\"expect empty buffer, but not\")\n\t}\n}\n\nfunc TestBufferString(t *testing.T) {\n\tbuffer := New()\n\tdefer buffer.Release()\n\n\tconst payload = \"Test String\"\n\tcommon.Must2(buffer.WriteString(payload))\n\tif buffer.String() != payload {\n\t\tt.Error(\"expect buffer content as \", payload, \" but actually \", buffer.String())\n\t}\n}\n\nfunc TestBufferByte(t *testing.T) {\n\t{\n\t\tbuffer := New()\n\t\tcommon.Must(buffer.WriteByte('m'))\n\t\tif buffer.String() != \"m\" {\n\t\t\tt.Error(\"expect buffer content as \", \"m\", \" but actually \", buffer.String())\n\t\t}\n\t\tbuffer.Release()\n\t}\n\t{\n\t\tbuffer := StackNew()\n\t\tcommon.Must(buffer.WriteByte('n'))\n\t\tif buffer.String() != \"n\" {\n\t\t\tt.Error(\"expect buffer content as \", \"n\", \" but actually \", buffer.String())\n\t\t}\n\t\tbuffer.Release()\n\t}\n\t{\n\t\tbuffer := StackNew()\n\t\tcommon.Must2(buffer.WriteString(\"HELLOWORLD\"))\n\t\tif b := buffer.Byte(5); b != 'W' {\n\t\t\tt.Error(\"unexpected byte \", b)\n\t\t}\n\n\t\tbuffer.SetByte(5, 'M')\n\t\tif buffer.String() != \"HELLOMORLD\" {\n\t\t\tt.Error(\"expect buffer content as \", \"n\", \" but actually \", buffer.String())\n\t\t}\n\t\tbuffer.Release()\n\t}\n}\nfunc TestBufferResize(t *testing.T) {\n\tbuffer := New()\n\tdefer buffer.Release()\n\n\tconst payload = \"Test String\"\n\tcommon.Must2(buffer.WriteString(payload))\n\tif buffer.String() != payload {\n\t\tt.Error(\"expect buffer content as \", payload, \" but actually \", buffer.String())\n\t}\n\n\tbuffer.Resize(-6, -3)\n\tif l := buffer.Len(); int(l) != 3 {\n\t\tt.Error(\"len error \", l)\n\t}\n\n\tif s := buffer.String(); s != \"Str\" {\n\t\tt.Error(\"unexpect buffer \", s)\n\t}\n\n\tbuffer.Resize(int32(len(payload)), 200)\n\tif l := buffer.Len(); int(l) != 200-len(payload) {\n\t\tt.Error(\"len error \", l)\n\t}\n}\n\nfunc TestBufferSlice(t *testing.T) {\n\t{\n\t\tb := New()\n\t\tcommon.Must2(b.Write([]byte(\"abcd\")))\n\t\tbytes := b.BytesFrom(-2)\n\t\tif diff := cmp.Diff(bytes, []byte{'c', 'd'}); diff != \"\" {\n\t\t\tt.Error(diff)\n\t\t}\n\t}\n\n\t{\n\t\tb := New()\n\t\tcommon.Must2(b.Write([]byte(\"abcd\")))\n\t\tbytes := b.BytesTo(-2)\n\t\tif diff := cmp.Diff(bytes, []byte{'a', 'b'}); diff != \"\" {\n\t\t\tt.Error(diff)\n\t\t}\n\t}\n\n\t{\n\t\tb := New()\n\t\tcommon.Must2(b.Write([]byte(\"abcd\")))\n\t\tbytes := b.BytesRange(-3, -1)\n\t\tif diff := cmp.Diff(bytes, []byte{'b', 'c'}); diff != \"\" {\n\t\t\tt.Error(diff)\n\t\t}\n\t}\n}\n\nfunc TestBufferReadFullFrom(t *testing.T) {\n\tpayload := make([]byte, 1024)\n\tcommon.Must2(rand.Read(payload))\n\n\treader := bytes.NewReader(payload)\n\tb := New()\n\tn, err := b.ReadFullFrom(reader, 1024)\n\tcommon.Must(err)\n\tif n != 1024 {\n\t\tt.Error(\"expect reading 1024 bytes, but actually \", n)\n\t}\n\n\tif diff := cmp.Diff(payload, b.Bytes()); diff != \"\" {\n\t\tt.Error(diff)\n\t}\n}\n\nfunc BenchmarkNewBuffer(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tbuffer := New()\n\t\tbuffer.Release()\n\t}\n}\n\nfunc BenchmarkNewBufferStack(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tbuffer := StackNew()\n\t\tbuffer.Release()\n\t}\n}\n\nfunc BenchmarkWrite2(b *testing.B) {\n\tbuffer := New()\n\n\tb.ResetTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\t_, _ = buffer.Write([]byte{'a', 'b'})\n\t\tbuffer.Clear()\n\t}\n}\n\nfunc BenchmarkWrite8(b *testing.B) {\n\tbuffer := New()\n\n\tb.ResetTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\t_, _ = buffer.Write([]byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'})\n\t\tbuffer.Clear()\n\t}\n}\n\nfunc BenchmarkWrite32(b *testing.B) {\n\tbuffer := New()\n\tpayload := make([]byte, 32)\n\trand.Read(payload)\n\n\tb.ResetTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\t_, _ = buffer.Write(payload)\n\t\tbuffer.Clear()\n\t}\n}\n\nfunc BenchmarkWriteByte2(b *testing.B) {\n\tbuffer := New()\n\n\tb.ResetTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\t_ = buffer.WriteByte('a')\n\t\t_ = buffer.WriteByte('b')\n\t\tbuffer.Clear()\n\t}\n}\n\nfunc BenchmarkWriteByte8(b *testing.B) {\n\tbuffer := New()\n\n\tb.ResetTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\t_ = buffer.WriteByte('a')\n\t\t_ = buffer.WriteByte('b')\n\t\t_ = buffer.WriteByte('c')\n\t\t_ = buffer.WriteByte('d')\n\t\t_ = buffer.WriteByte('e')\n\t\t_ = buffer.WriteByte('f')\n\t\t_ = buffer.WriteByte('g')\n\t\t_ = buffer.WriteByte('h')\n\t\tbuffer.Clear()\n\t}\n}\n"
  },
  {
    "path": "common/buf/copy.go",
    "content": "package buf\n\nimport (\n\t\"io\"\n\t\"time\"\n\n\t\"v2ray.com/core/common/errors\"\n\t\"v2ray.com/core/common/signal\"\n)\n\ntype dataHandler func(MultiBuffer)\n\ntype copyHandler struct {\n\tonData []dataHandler\n}\n\n// SizeCounter is for counting bytes copied by Copy().\ntype SizeCounter struct {\n\tSize int64\n}\n\n// CopyOption is an option for copying data.\ntype CopyOption func(*copyHandler)\n\n// UpdateActivity is a CopyOption to update activity on each data copy operation.\nfunc UpdateActivity(timer signal.ActivityUpdater) CopyOption {\n\treturn func(handler *copyHandler) {\n\t\thandler.onData = append(handler.onData, func(MultiBuffer) {\n\t\t\ttimer.Update()\n\t\t})\n\t}\n}\n\n// CountSize is a CopyOption that sums the total size of data copied into the given SizeCounter.\nfunc CountSize(sc *SizeCounter) CopyOption {\n\treturn func(handler *copyHandler) {\n\t\thandler.onData = append(handler.onData, func(b MultiBuffer) {\n\t\t\tsc.Size += int64(b.Len())\n\t\t})\n\t}\n}\n\ntype readError struct {\n\terror\n}\n\nfunc (e readError) Error() string {\n\treturn e.error.Error()\n}\n\nfunc (e readError) Inner() error {\n\treturn e.error\n}\n\n// IsReadError returns true if the error in Copy() comes from reading.\nfunc IsReadError(err error) bool {\n\t_, ok := err.(readError)\n\treturn ok\n}\n\ntype writeError struct {\n\terror\n}\n\nfunc (e writeError) Error() string {\n\treturn e.error.Error()\n}\n\nfunc (e writeError) Inner() error {\n\treturn e.error\n}\n\n// IsWriteError returns true if the error in Copy() comes from writing.\nfunc IsWriteError(err error) bool {\n\t_, ok := err.(writeError)\n\treturn ok\n}\n\nfunc copyInternal(reader Reader, writer Writer, handler *copyHandler) error {\n\tfor {\n\t\tbuffer, err := reader.ReadMultiBuffer()\n\t\tif !buffer.IsEmpty() {\n\t\t\tfor _, handler := range handler.onData {\n\t\t\t\thandler(buffer)\n\t\t\t}\n\n\t\t\tif werr := writer.WriteMultiBuffer(buffer); werr != nil {\n\t\t\t\treturn writeError{werr}\n\t\t\t}\n\t\t}\n\n\t\tif err != nil {\n\t\t\treturn readError{err}\n\t\t}\n\t}\n}\n\n// Copy dumps all payload from reader to writer or stops when an error occurs. It returns nil when EOF.\nfunc Copy(reader Reader, writer Writer, options ...CopyOption) error {\n\tvar handler copyHandler\n\tfor _, option := range options {\n\t\toption(&handler)\n\t}\n\terr := copyInternal(reader, writer, &handler)\n\tif err != nil && errors.Cause(err) != io.EOF {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nvar ErrNotTimeoutReader = newError(\"not a TimeoutReader\")\n\nfunc CopyOnceTimeout(reader Reader, writer Writer, timeout time.Duration) error {\n\ttimeoutReader, ok := reader.(TimeoutReader)\n\tif !ok {\n\t\treturn ErrNotTimeoutReader\n\t}\n\tmb, err := timeoutReader.ReadMultiBufferTimeout(timeout)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn writer.WriteMultiBuffer(mb)\n}\n"
  },
  {
    "path": "common/buf/copy_test.go",
    "content": "package buf_test\n\nimport (\n\t\"crypto/rand\"\n\t\"io\"\n\t\"testing\"\n\n\t\"github.com/golang/mock/gomock\"\n\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/errors\"\n\t\"v2ray.com/core/testing/mocks\"\n)\n\nfunc TestReadError(t *testing.T) {\n\tmockCtl := gomock.NewController(t)\n\tdefer mockCtl.Finish()\n\n\tmockReader := mocks.NewReader(mockCtl)\n\tmockReader.EXPECT().Read(gomock.Any()).Return(0, errors.New(\"error\"))\n\n\terr := buf.Copy(buf.NewReader(mockReader), buf.Discard)\n\tif err == nil {\n\t\tt.Fatal(\"expected error, but nil\")\n\t}\n\n\tif !buf.IsReadError(err) {\n\t\tt.Error(\"expected to be ReadError, but not\")\n\t}\n\n\tif err.Error() != \"error\" {\n\t\tt.Fatal(\"unexpected error message: \", err.Error())\n\t}\n}\n\nfunc TestWriteError(t *testing.T) {\n\tmockCtl := gomock.NewController(t)\n\tdefer mockCtl.Finish()\n\n\tmockWriter := mocks.NewWriter(mockCtl)\n\tmockWriter.EXPECT().Write(gomock.Any()).Return(0, errors.New(\"error\"))\n\n\terr := buf.Copy(buf.NewReader(rand.Reader), buf.NewWriter(mockWriter))\n\tif err == nil {\n\t\tt.Fatal(\"expected error, but nil\")\n\t}\n\n\tif !buf.IsWriteError(err) {\n\t\tt.Error(\"expected to be WriteError, but not\")\n\t}\n\n\tif err.Error() != \"error\" {\n\t\tt.Fatal(\"unexpected error message: \", err.Error())\n\t}\n}\n\ntype TestReader struct{}\n\nfunc (TestReader) Read(b []byte) (int, error) {\n\treturn len(b), nil\n}\n\nfunc BenchmarkCopy(b *testing.B) {\n\treader := buf.NewReader(io.LimitReader(TestReader{}, 10240))\n\twriter := buf.Discard\n\n\tb.ResetTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\t_ = buf.Copy(reader, writer)\n\t}\n}\n"
  },
  {
    "path": "common/buf/errors.generated.go",
    "content": "package buf\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "common/buf/io.go",
    "content": "package buf\n\nimport (\n\t\"io\"\n\t\"net\"\n\t\"os\"\n\t\"syscall\"\n\t\"time\"\n)\n\n// Reader extends io.Reader with MultiBuffer.\ntype Reader interface {\n\t// ReadMultiBuffer reads content from underlying reader, and put it into a MultiBuffer.\n\tReadMultiBuffer() (MultiBuffer, error)\n}\n\n// ErrReadTimeout is an error that happens with IO timeout.\nvar ErrReadTimeout = newError(\"IO timeout\")\n\n// TimeoutReader is a reader that returns error if Read() operation takes longer than the given timeout.\ntype TimeoutReader interface {\n\tReadMultiBufferTimeout(time.Duration) (MultiBuffer, error)\n}\n\n// Writer extends io.Writer with MultiBuffer.\ntype Writer interface {\n\t// WriteMultiBuffer writes a MultiBuffer into underlying writer.\n\tWriteMultiBuffer(MultiBuffer) error\n}\n\n// WriteAllBytes ensures all bytes are written into the given writer.\nfunc WriteAllBytes(writer io.Writer, payload []byte) error {\n\tfor len(payload) > 0 {\n\t\tn, err := writer.Write(payload)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tpayload = payload[n:]\n\t}\n\treturn nil\n}\n\nfunc isPacketReader(reader io.Reader) bool {\n\t_, ok := reader.(net.PacketConn)\n\treturn ok\n}\n\n// NewReader creates a new Reader.\n// The Reader instance doesn't take the ownership of reader.\nfunc NewReader(reader io.Reader) Reader {\n\tif mr, ok := reader.(Reader); ok {\n\t\treturn mr\n\t}\n\n\tif isPacketReader(reader) {\n\t\treturn &PacketReader{\n\t\t\tReader: reader,\n\t\t}\n\t}\n\n\t_, isFile := reader.(*os.File)\n\tif !isFile && useReadv {\n\t\tif sc, ok := reader.(syscall.Conn); ok {\n\t\t\trawConn, err := sc.SyscallConn()\n\t\t\tif err != nil {\n\t\t\t\tnewError(\"failed to get sysconn\").Base(err).WriteToLog()\n\t\t\t} else {\n\t\t\t\treturn NewReadVReader(reader, rawConn)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn &SingleReader{\n\t\tReader: reader,\n\t}\n}\n\n// NewPacketReader creates a new PacketReader based on the given reader.\nfunc NewPacketReader(reader io.Reader) Reader {\n\tif mr, ok := reader.(Reader); ok {\n\t\treturn mr\n\t}\n\n\treturn &PacketReader{\n\t\tReader: reader,\n\t}\n}\n\nfunc isPacketWriter(writer io.Writer) bool {\n\tif _, ok := writer.(net.PacketConn); ok {\n\t\treturn true\n\t}\n\n\t// If the writer doesn't implement syscall.Conn, it is probably not a TCP connection.\n\tif _, ok := writer.(syscall.Conn); !ok {\n\t\treturn true\n\t}\n\treturn false\n}\n\n// NewWriter creates a new Writer.\nfunc NewWriter(writer io.Writer) Writer {\n\tif mw, ok := writer.(Writer); ok {\n\t\treturn mw\n\t}\n\n\tif isPacketWriter(writer) {\n\t\treturn &SequentialWriter{\n\t\t\tWriter: writer,\n\t\t}\n\t}\n\n\treturn &BufferToBytesWriter{\n\t\tWriter: writer,\n\t}\n}\n"
  },
  {
    "path": "common/buf/io_test.go",
    "content": "package buf_test\n\nimport (\n\t\"crypto/tls\"\n\t\"io\"\n\t\"testing\"\n\n\t. \"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/testing/servers/tcp\"\n)\n\nfunc TestWriterCreation(t *testing.T) {\n\ttcpServer := tcp.Server{}\n\tdest, err := tcpServer.Start()\n\tif err != nil {\n\t\tt.Fatal(\"failed to start tcp server: \", err)\n\t}\n\tdefer tcpServer.Close()\n\n\tconn, err := net.Dial(\"tcp\", dest.NetAddr())\n\tif err != nil {\n\t\tt.Fatal(\"failed to dial a TCP connection: \", err)\n\t}\n\tdefer conn.Close()\n\n\t{\n\t\twriter := NewWriter(conn)\n\t\tif _, ok := writer.(*BufferToBytesWriter); !ok {\n\t\t\tt.Fatal(\"writer is not a BufferToBytesWriter\")\n\t\t}\n\n\t\twriter2 := NewWriter(writer.(io.Writer))\n\t\tif writer2 != writer {\n\t\t\tt.Fatal(\"writer is not reused\")\n\t\t}\n\t}\n\n\ttlsConn := tls.Client(conn, &tls.Config{\n\t\tInsecureSkipVerify: true,\n\t})\n\tdefer tlsConn.Close()\n\n\t{\n\t\twriter := NewWriter(tlsConn)\n\t\tif _, ok := writer.(*SequentialWriter); !ok {\n\t\t\tt.Fatal(\"writer is not a SequentialWriter\")\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "common/buf/multi_buffer.go",
    "content": "package buf\n\nimport (\n\t\"io\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/errors\"\n\t\"v2ray.com/core/common/serial\"\n)\n\n// ReadAllToBytes reads all content from the reader into a byte array, until EOF.\nfunc ReadAllToBytes(reader io.Reader) ([]byte, error) {\n\tmb, err := ReadFrom(reader)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif mb.Len() == 0 {\n\t\treturn nil, nil\n\t}\n\tb := make([]byte, mb.Len())\n\tmb, _ = SplitBytes(mb, b)\n\tReleaseMulti(mb)\n\treturn b, nil\n}\n\n// MultiBuffer is a list of Buffers. The order of Buffer matters.\ntype MultiBuffer []*Buffer\n\n// MergeMulti merges content from src to dest, and returns the new address of dest and src\nfunc MergeMulti(dest MultiBuffer, src MultiBuffer) (MultiBuffer, MultiBuffer) {\n\tdest = append(dest, src...)\n\tfor idx := range src {\n\t\tsrc[idx] = nil\n\t}\n\treturn dest, src[:0]\n}\n\n// MergeBytes merges the given bytes into MultiBuffer and return the new address of the merged MultiBuffer.\nfunc MergeBytes(dest MultiBuffer, src []byte) MultiBuffer {\n\tn := len(dest)\n\tif n > 0 && !(dest)[n-1].IsFull() {\n\t\tnBytes, _ := (dest)[n-1].Write(src)\n\t\tsrc = src[nBytes:]\n\t}\n\n\tfor len(src) > 0 {\n\t\tb := New()\n\t\tnBytes, _ := b.Write(src)\n\t\tsrc = src[nBytes:]\n\t\tdest = append(dest, b)\n\t}\n\n\treturn dest\n}\n\n// ReleaseMulti release all content of the MultiBuffer, and returns an empty MultiBuffer.\nfunc ReleaseMulti(mb MultiBuffer) MultiBuffer {\n\tfor i := range mb {\n\t\tmb[i].Release()\n\t\tmb[i] = nil\n\t}\n\treturn mb[:0]\n}\n\n// Copy copied the beginning part of the MultiBuffer into the given byte array.\nfunc (mb MultiBuffer) Copy(b []byte) int {\n\ttotal := 0\n\tfor _, bb := range mb {\n\t\tnBytes := copy(b[total:], bb.Bytes())\n\t\ttotal += nBytes\n\t\tif int32(nBytes) < bb.Len() {\n\t\t\tbreak\n\t\t}\n\t}\n\treturn total\n}\n\n// ReadFrom reads all content from reader until EOF.\nfunc ReadFrom(reader io.Reader) (MultiBuffer, error) {\n\tmb := make(MultiBuffer, 0, 16)\n\tfor {\n\t\tb := New()\n\t\t_, err := b.ReadFullFrom(reader, Size)\n\t\tif b.IsEmpty() {\n\t\t\tb.Release()\n\t\t} else {\n\t\t\tmb = append(mb, b)\n\t\t}\n\t\tif err != nil {\n\t\t\tif errors.Cause(err) == io.EOF || errors.Cause(err) == io.ErrUnexpectedEOF {\n\t\t\t\treturn mb, nil\n\t\t\t}\n\t\t\treturn mb, err\n\t\t}\n\t}\n}\n\n// SplitBytes splits the given amount of bytes from the beginning of the MultiBuffer.\n// It returns the new address of MultiBuffer leftover, and number of bytes written into the input byte slice.\nfunc SplitBytes(mb MultiBuffer, b []byte) (MultiBuffer, int) {\n\ttotalBytes := 0\n\tendIndex := -1\n\tfor i := range mb {\n\t\tpBuffer := mb[i]\n\t\tnBytes, _ := pBuffer.Read(b)\n\t\ttotalBytes += nBytes\n\t\tb = b[nBytes:]\n\t\tif !pBuffer.IsEmpty() {\n\t\t\tendIndex = i\n\t\t\tbreak\n\t\t}\n\t\tpBuffer.Release()\n\t\tmb[i] = nil\n\t}\n\n\tif endIndex == -1 {\n\t\tmb = mb[:0]\n\t} else {\n\t\tmb = mb[endIndex:]\n\t}\n\n\treturn mb, totalBytes\n}\n\n// SplitFirstBytes splits the first buffer from MultiBuffer, and then copy its content into the given slice.\nfunc SplitFirstBytes(mb MultiBuffer, p []byte) (MultiBuffer, int) {\n\tmb, b := SplitFirst(mb)\n\tif b == nil {\n\t\treturn mb, 0\n\t}\n\tn := copy(p, b.Bytes())\n\tb.Release()\n\treturn mb, n\n}\n\n// Compact returns another MultiBuffer by merging all content of the given one together.\nfunc Compact(mb MultiBuffer) MultiBuffer {\n\tif len(mb) == 0 {\n\t\treturn mb\n\t}\n\n\tmb2 := make(MultiBuffer, 0, len(mb))\n\tlast := mb[0]\n\n\tfor i := 1; i < len(mb); i++ {\n\t\tcurr := mb[i]\n\t\tif last.Len()+curr.Len() > Size {\n\t\t\tmb2 = append(mb2, last)\n\t\t\tlast = curr\n\t\t} else {\n\t\t\tcommon.Must2(last.ReadFrom(curr))\n\t\t\tcurr.Release()\n\t\t}\n\t}\n\n\tmb2 = append(mb2, last)\n\treturn mb2\n}\n\n// SplitFirst splits the first Buffer from the beginning of the MultiBuffer.\nfunc SplitFirst(mb MultiBuffer) (MultiBuffer, *Buffer) {\n\tif len(mb) == 0 {\n\t\treturn mb, nil\n\t}\n\n\tb := mb[0]\n\tmb[0] = nil\n\tmb = mb[1:]\n\treturn mb, b\n}\n\n// SplitSize splits the beginning of the MultiBuffer into another one, for at most size bytes.\nfunc SplitSize(mb MultiBuffer, size int32) (MultiBuffer, MultiBuffer) {\n\tif len(mb) == 0 {\n\t\treturn mb, nil\n\t}\n\n\tif mb[0].Len() > size {\n\t\tb := New()\n\t\tcopy(b.Extend(size), mb[0].BytesTo(size))\n\t\tmb[0].Advance(size)\n\t\treturn mb, MultiBuffer{b}\n\t}\n\n\ttotalBytes := int32(0)\n\tvar r MultiBuffer\n\tendIndex := -1\n\tfor i := range mb {\n\t\tif totalBytes+mb[i].Len() > size {\n\t\t\tendIndex = i\n\t\t\tbreak\n\t\t}\n\t\ttotalBytes += mb[i].Len()\n\t\tr = append(r, mb[i])\n\t\tmb[i] = nil\n\t}\n\tif endIndex == -1 {\n\t\t// To reuse mb array\n\t\tmb = mb[:0]\n\t} else {\n\t\tmb = mb[endIndex:]\n\t}\n\treturn mb, r\n}\n\n// WriteMultiBuffer writes all buffers from the MultiBuffer to the Writer one by one, and return error if any, with leftover MultiBuffer.\nfunc WriteMultiBuffer(writer io.Writer, mb MultiBuffer) (MultiBuffer, error) {\n\tfor {\n\t\tmb2, b := SplitFirst(mb)\n\t\tmb = mb2\n\t\tif b == nil {\n\t\t\tbreak\n\t\t}\n\n\t\t_, err := writer.Write(b.Bytes())\n\t\tb.Release()\n\t\tif err != nil {\n\t\t\treturn mb, err\n\t\t}\n\t}\n\n\treturn nil, nil\n}\n\n// Len returns the total number of bytes in the MultiBuffer.\nfunc (mb MultiBuffer) Len() int32 {\n\tif mb == nil {\n\t\treturn 0\n\t}\n\n\tsize := int32(0)\n\tfor _, b := range mb {\n\t\tsize += b.Len()\n\t}\n\treturn size\n}\n\n// IsEmpty return true if the MultiBuffer has no content.\nfunc (mb MultiBuffer) IsEmpty() bool {\n\tfor _, b := range mb {\n\t\tif !b.IsEmpty() {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n// String returns the content of the MultiBuffer in string.\nfunc (mb MultiBuffer) String() string {\n\tv := make([]interface{}, len(mb))\n\tfor i, b := range mb {\n\t\tv[i] = b\n\t}\n\treturn serial.Concat(v...)\n}\n\n// MultiBufferContainer is a ReadWriteCloser wrapper over MultiBuffer.\ntype MultiBufferContainer struct {\n\tMultiBuffer\n}\n\n// Read implements io.Reader.\nfunc (c *MultiBufferContainer) Read(b []byte) (int, error) {\n\tif c.MultiBuffer.IsEmpty() {\n\t\treturn 0, io.EOF\n\t}\n\n\tmb, nBytes := SplitBytes(c.MultiBuffer, b)\n\tc.MultiBuffer = mb\n\treturn nBytes, nil\n}\n\n// ReadMultiBuffer implements Reader.\nfunc (c *MultiBufferContainer) ReadMultiBuffer() (MultiBuffer, error) {\n\tmb := c.MultiBuffer\n\tc.MultiBuffer = nil\n\treturn mb, nil\n}\n\n// Write implements io.Writer.\nfunc (c *MultiBufferContainer) Write(b []byte) (int, error) {\n\tc.MultiBuffer = MergeBytes(c.MultiBuffer, b)\n\treturn len(b), nil\n}\n\n// WriteMultiBuffer implement Writer.\nfunc (c *MultiBufferContainer) WriteMultiBuffer(b MultiBuffer) error {\n\tmb, _ := MergeMulti(c.MultiBuffer, b)\n\tc.MultiBuffer = mb\n\treturn nil\n}\n\n// Close implement io.Closer.\nfunc (c *MultiBufferContainer) Close() error {\n\tc.MultiBuffer = ReleaseMulti(c.MultiBuffer)\n\treturn nil\n}\n"
  },
  {
    "path": "common/buf/multi_buffer_test.go",
    "content": "package buf_test\n\nimport (\n\t\"bytes\"\n\t\"crypto/rand\"\n\t\"io\"\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"io/ioutil\"\n\t\"os\"\n\n\t\"v2ray.com/core/common\"\n\t. \"v2ray.com/core/common/buf\"\n)\n\nfunc TestMultiBufferRead(t *testing.T) {\n\tb1 := New()\n\tcommon.Must2(b1.WriteString(\"ab\"))\n\n\tb2 := New()\n\tcommon.Must2(b2.WriteString(\"cd\"))\n\tmb := MultiBuffer{b1, b2}\n\n\tbs := make([]byte, 32)\n\t_, nBytes := SplitBytes(mb, bs)\n\tif nBytes != 4 {\n\t\tt.Error(\"expect 4 bytes split, but got \", nBytes)\n\t}\n\tif r := cmp.Diff(bs[:nBytes], []byte(\"abcd\")); r != \"\" {\n\t\tt.Error(r)\n\t}\n}\n\nfunc TestMultiBufferAppend(t *testing.T) {\n\tvar mb MultiBuffer\n\tb := New()\n\tcommon.Must2(b.WriteString(\"ab\"))\n\tmb = append(mb, b)\n\tif mb.Len() != 2 {\n\t\tt.Error(\"expected length 2, but got \", mb.Len())\n\t}\n}\n\nfunc TestMultiBufferSliceBySizeLarge(t *testing.T) {\n\tlb := make([]byte, 8*1024)\n\tcommon.Must2(io.ReadFull(rand.Reader, lb))\n\n\tmb := MergeBytes(nil, lb)\n\n\tmb, mb2 := SplitSize(mb, 1024)\n\tif mb2.Len() != 1024 {\n\t\tt.Error(\"expect length 1024, but got \", mb2.Len())\n\t}\n\tif mb.Len() != 7*1024 {\n\t\tt.Error(\"expect length 7*1024, but got \", mb.Len())\n\t}\n\n\tmb, mb3 := SplitSize(mb, 7*1024)\n\tif mb3.Len() != 7*1024 {\n\t\tt.Error(\"expect length 7*1024, but got\", mb.Len())\n\t}\n\n\tif !mb.IsEmpty() {\n\t\tt.Error(\"expect empty buffer, but got \", mb.Len())\n\t}\n}\n\nfunc TestMultiBufferSplitFirst(t *testing.T) {\n\tb1 := New()\n\tb1.WriteString(\"b1\")\n\n\tb2 := New()\n\tb2.WriteString(\"b2\")\n\n\tb3 := New()\n\tb3.WriteString(\"b3\")\n\n\tvar mb MultiBuffer\n\tmb = append(mb, b1, b2, b3)\n\n\tmb, c1 := SplitFirst(mb)\n\tif diff := cmp.Diff(b1.String(), c1.String()); diff != \"\" {\n\t\tt.Error(diff)\n\t}\n\n\tmb, c2 := SplitFirst(mb)\n\tif diff := cmp.Diff(b2.String(), c2.String()); diff != \"\" {\n\t\tt.Error(diff)\n\t}\n\n\tmb, c3 := SplitFirst(mb)\n\tif diff := cmp.Diff(b3.String(), c3.String()); diff != \"\" {\n\t\tt.Error(diff)\n\t}\n\n\tif !mb.IsEmpty() {\n\t\tt.Error(\"expect empty buffer, but got \", mb.String())\n\t}\n}\n\nfunc TestMultiBufferReadAllToByte(t *testing.T) {\n\t{\n\t\tlb := make([]byte, 8*1024)\n\t\tcommon.Must2(io.ReadFull(rand.Reader, lb))\n\t\trd := bytes.NewBuffer(lb)\n\t\tb, err := ReadAllToBytes(rd)\n\t\tcommon.Must(err)\n\n\t\tif l := len(b); l != 8*1024 {\n\t\t\tt.Error(\"unexpceted length from ReadAllToBytes\", l)\n\t\t}\n\n\t}\n\t{\n\t\tconst dat = \"data/test_MultiBufferReadAllToByte.dat\"\n\t\tf, err := os.Open(dat)\n\t\tcommon.Must(err)\n\n\t\tbuf2, err := ReadAllToBytes(f)\n\t\tcommon.Must(err)\n\t\tf.Close()\n\n\t\tcnt, err := ioutil.ReadFile(dat)\n\t\tcommon.Must(err)\n\n\t\tif d := cmp.Diff(buf2, cnt); d != \"\" {\n\t\t\tt.Error(\"fail to read from file: \", d)\n\t\t}\n\t}\n}\n\nfunc TestMultiBufferCopy(t *testing.T) {\n\tlb := make([]byte, 8*1024)\n\tcommon.Must2(io.ReadFull(rand.Reader, lb))\n\treader := bytes.NewBuffer(lb)\n\n\tmb, err := ReadFrom(reader)\n\tcommon.Must(err)\n\n\tlbdst := make([]byte, 8*1024)\n\tmb.Copy(lbdst)\n\n\tif d := cmp.Diff(lb, lbdst); d != \"\" {\n\t\tt.Error(\"unexpceted different from MultiBufferCopy \", d)\n\t}\n}\n\nfunc TestSplitFirstBytes(t *testing.T) {\n\ta := New()\n\tcommon.Must2(a.WriteString(\"ab\"))\n\tb := New()\n\tcommon.Must2(b.WriteString(\"bc\"))\n\n\tmb := MultiBuffer{a, b}\n\n\to := make([]byte, 2)\n\t_, cnt := SplitFirstBytes(mb, o)\n\tif cnt != 2 {\n\t\tt.Error(\"unexpected cnt from SplitFirstBytes \", cnt)\n\t}\n\tif d := cmp.Diff(string(o), \"ab\"); d != \"\" {\n\t\tt.Error(\"unexpected splited result from SplitFirstBytes \", d)\n\t}\n}\n\nfunc TestCompact(t *testing.T) {\n\ta := New()\n\tcommon.Must2(a.WriteString(\"ab\"))\n\tb := New()\n\tcommon.Must2(b.WriteString(\"bc\"))\n\n\tmb := MultiBuffer{a, b}\n\tcmb := Compact(mb)\n\n\tif w := cmb.String(); w != \"abbc\" {\n\t\tt.Error(\"unexpected Compact result \", w)\n\t}\n}\n\nfunc BenchmarkSplitBytes(b *testing.B) {\n\tvar mb MultiBuffer\n\traw := make([]byte, Size)\n\n\tb.ResetTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\tbuffer := StackNew()\n\t\tbuffer.Extend(Size)\n\t\tmb = append(mb, &buffer)\n\t\tmb, _ = SplitBytes(mb, raw)\n\t}\n}\n"
  },
  {
    "path": "common/buf/reader.go",
    "content": "package buf\n\nimport (\n\t\"io\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/errors\"\n)\n\nfunc readOneUDP(r io.Reader) (*Buffer, error) {\n\tb := New()\n\tfor i := 0; i < 64; i++ {\n\t\t_, err := b.ReadFrom(r)\n\t\tif !b.IsEmpty() {\n\t\t\treturn b, nil\n\t\t}\n\t\tif err != nil {\n\t\t\tb.Release()\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tb.Release()\n\treturn nil, newError(\"Reader returns too many empty payloads.\")\n}\n\n// ReadBuffer reads a Buffer from the given reader.\nfunc ReadBuffer(r io.Reader) (*Buffer, error) {\n\tb := New()\n\tn, err := b.ReadFrom(r)\n\tif n > 0 {\n\t\treturn b, err\n\t}\n\tb.Release()\n\treturn nil, err\n}\n\n// BufferedReader is a Reader that keeps its internal buffer.\ntype BufferedReader struct {\n\t// Reader is the underlying reader to be read from\n\tReader Reader\n\t// Buffer is the internal buffer to be read from first\n\tBuffer MultiBuffer\n\t// Spliter is a function to read bytes from MultiBuffer\n\tSpliter func(MultiBuffer, []byte) (MultiBuffer, int)\n}\n\n// BufferedBytes returns the number of bytes that is cached in this reader.\nfunc (r *BufferedReader) BufferedBytes() int32 {\n\treturn r.Buffer.Len()\n}\n\n// ReadByte implements io.ByteReader.\nfunc (r *BufferedReader) ReadByte() (byte, error) {\n\tvar b [1]byte\n\t_, err := r.Read(b[:])\n\treturn b[0], err\n}\n\n// Read implements io.Reader. It reads from internal buffer first (if available) and then reads from the underlying reader.\nfunc (r *BufferedReader) Read(b []byte) (int, error) {\n\tspliter := r.Spliter\n\tif spliter == nil {\n\t\tspliter = SplitBytes\n\t}\n\n\tif !r.Buffer.IsEmpty() {\n\t\tbuffer, nBytes := spliter(r.Buffer, b)\n\t\tr.Buffer = buffer\n\t\tif r.Buffer.IsEmpty() {\n\t\t\tr.Buffer = nil\n\t\t}\n\t\treturn nBytes, nil\n\t}\n\n\tmb, err := r.Reader.ReadMultiBuffer()\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\tmb, nBytes := spliter(mb, b)\n\tif !mb.IsEmpty() {\n\t\tr.Buffer = mb\n\t}\n\treturn nBytes, nil\n}\n\n// ReadMultiBuffer implements Reader.\nfunc (r *BufferedReader) ReadMultiBuffer() (MultiBuffer, error) {\n\tif !r.Buffer.IsEmpty() {\n\t\tmb := r.Buffer\n\t\tr.Buffer = nil\n\t\treturn mb, nil\n\t}\n\n\treturn r.Reader.ReadMultiBuffer()\n}\n\n// ReadAtMost returns a MultiBuffer with at most size.\nfunc (r *BufferedReader) ReadAtMost(size int32) (MultiBuffer, error) {\n\tif r.Buffer.IsEmpty() {\n\t\tmb, err := r.Reader.ReadMultiBuffer()\n\t\tif mb.IsEmpty() && err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tr.Buffer = mb\n\t}\n\n\trb, mb := SplitSize(r.Buffer, size)\n\tr.Buffer = rb\n\tif r.Buffer.IsEmpty() {\n\t\tr.Buffer = nil\n\t}\n\treturn mb, nil\n}\n\nfunc (r *BufferedReader) writeToInternal(writer io.Writer) (int64, error) {\n\tmbWriter := NewWriter(writer)\n\tvar sc SizeCounter\n\tif r.Buffer != nil {\n\t\tsc.Size = int64(r.Buffer.Len())\n\t\tif err := mbWriter.WriteMultiBuffer(r.Buffer); err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\tr.Buffer = nil\n\t}\n\n\terr := Copy(r.Reader, mbWriter, CountSize(&sc))\n\treturn sc.Size, err\n}\n\n// WriteTo implements io.WriterTo.\nfunc (r *BufferedReader) WriteTo(writer io.Writer) (int64, error) {\n\tnBytes, err := r.writeToInternal(writer)\n\tif errors.Cause(err) == io.EOF {\n\t\treturn nBytes, nil\n\t}\n\treturn nBytes, err\n}\n\n// Interrupt implements common.Interruptible.\nfunc (r *BufferedReader) Interrupt() {\n\tcommon.Interrupt(r.Reader)\n}\n\n// Close implements io.Closer.\nfunc (r *BufferedReader) Close() error {\n\treturn common.Close(r.Reader)\n}\n\n// SingleReader is a Reader that read one Buffer every time.\ntype SingleReader struct {\n\tio.Reader\n}\n\n// ReadMultiBuffer implements Reader.\nfunc (r *SingleReader) ReadMultiBuffer() (MultiBuffer, error) {\n\tb, err := ReadBuffer(r.Reader)\n\treturn MultiBuffer{b}, err\n}\n\n// PacketReader is a Reader that read one Buffer every time.\ntype PacketReader struct {\n\tio.Reader\n}\n\n// ReadMultiBuffer implements Reader.\nfunc (r *PacketReader) ReadMultiBuffer() (MultiBuffer, error) {\n\tb, err := readOneUDP(r.Reader)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn MultiBuffer{b}, nil\n}\n"
  },
  {
    "path": "common/buf/reader_test.go",
    "content": "package buf_test\n\nimport (\n\t\"bytes\"\n\t\"io\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"v2ray.com/core/common\"\n\t. \"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/transport/pipe\"\n)\n\nfunc TestBytesReaderWriteTo(t *testing.T) {\n\tpReader, pWriter := pipe.New(pipe.WithSizeLimit(1024))\n\treader := &BufferedReader{Reader: pReader}\n\tb1 := New()\n\tb1.WriteString(\"abc\")\n\tb2 := New()\n\tb2.WriteString(\"efg\")\n\tcommon.Must(pWriter.WriteMultiBuffer(MultiBuffer{b1, b2}))\n\tpWriter.Close()\n\n\tpReader2, pWriter2 := pipe.New(pipe.WithSizeLimit(1024))\n\twriter := NewBufferedWriter(pWriter2)\n\twriter.SetBuffered(false)\n\n\tnBytes, err := io.Copy(writer, reader)\n\tcommon.Must(err)\n\tif nBytes != 6 {\n\t\tt.Error(\"copy: \", nBytes)\n\t}\n\n\tmb, err := pReader2.ReadMultiBuffer()\n\tcommon.Must(err)\n\tif s := mb.String(); s != \"abcefg\" {\n\t\tt.Error(\"content: \", s)\n\t}\n}\n\nfunc TestBytesReaderMultiBuffer(t *testing.T) {\n\tpReader, pWriter := pipe.New(pipe.WithSizeLimit(1024))\n\treader := &BufferedReader{Reader: pReader}\n\tb1 := New()\n\tb1.WriteString(\"abc\")\n\tb2 := New()\n\tb2.WriteString(\"efg\")\n\tcommon.Must(pWriter.WriteMultiBuffer(MultiBuffer{b1, b2}))\n\tpWriter.Close()\n\n\tmbReader := NewReader(reader)\n\tmb, err := mbReader.ReadMultiBuffer()\n\tcommon.Must(err)\n\tif s := mb.String(); s != \"abcefg\" {\n\t\tt.Error(\"content: \", s)\n\t}\n}\n\nfunc TestReadByte(t *testing.T) {\n\tsr := strings.NewReader(\"abcd\")\n\treader := &BufferedReader{\n\t\tReader: NewReader(sr),\n\t}\n\tb, err := reader.ReadByte()\n\tcommon.Must(err)\n\tif b != 'a' {\n\t\tt.Error(\"unexpected byte: \", b, \" want a\")\n\t}\n\tif reader.BufferedBytes() != 3 { // 3 bytes left in buffer\n\t\tt.Error(\"unexpected buffered Bytes: \", reader.BufferedBytes())\n\t}\n\n\tnBytes, err := reader.WriteTo(DiscardBytes)\n\tcommon.Must(err)\n\tif nBytes != 3 {\n\t\tt.Error(\"unexpect bytes written: \", nBytes)\n\t}\n}\n\nfunc TestReadBuffer(t *testing.T) {\n\t{\n\t\tsr := strings.NewReader(\"abcd\")\n\t\tbuf, err := ReadBuffer(sr)\n\t\tcommon.Must(err)\n\n\t\tif s := buf.String(); s != \"abcd\" {\n\t\t\tt.Error(\"unexpected str: \", s, \" want abcd\")\n\t\t}\n\t\tbuf.Release()\n\t}\n\n}\n\nfunc TestReadAtMost(t *testing.T) {\n\tsr := strings.NewReader(\"abcd\")\n\treader := &BufferedReader{\n\t\tReader: NewReader(sr),\n\t}\n\n\tmb, err := reader.ReadAtMost(3)\n\tcommon.Must(err)\n\tif s := mb.String(); s != \"abc\" {\n\t\tt.Error(\"unexpected read result: \", s)\n\t}\n\n\tnBytes, err := reader.WriteTo(DiscardBytes)\n\tcommon.Must(err)\n\tif nBytes != 1 {\n\t\tt.Error(\"unexpect bytes written: \", nBytes)\n\t}\n}\n\nfunc TestPacketReader_ReadMultiBuffer(t *testing.T) {\n\tconst alpha = \"abcefg\"\n\tbuf := bytes.NewBufferString(alpha)\n\treader := &PacketReader{buf}\n\tmb, err := reader.ReadMultiBuffer()\n\tcommon.Must(err)\n\tif s := mb.String(); s != alpha {\n\t\tt.Error(\"content: \", s)\n\t}\n}\n\nfunc TestReaderInterface(t *testing.T) {\n\t_ = (io.Reader)(new(ReadVReader))\n\t_ = (Reader)(new(ReadVReader))\n\n\t_ = (Reader)(new(BufferedReader))\n\t_ = (io.Reader)(new(BufferedReader))\n\t_ = (io.ByteReader)(new(BufferedReader))\n\t_ = (io.WriterTo)(new(BufferedReader))\n}\n"
  },
  {
    "path": "common/buf/readv_posix.go",
    "content": "// +build !windows\n// +build !wasm\n// +build !illumos\n\npackage buf\n\nimport (\n\t\"syscall\"\n\t\"unsafe\"\n)\n\ntype posixReader struct {\n\tiovecs []syscall.Iovec\n}\n\nfunc (r *posixReader) Init(bs []*Buffer) {\n\tiovecs := r.iovecs\n\tif iovecs == nil {\n\t\tiovecs = make([]syscall.Iovec, 0, len(bs))\n\t}\n\tfor idx, b := range bs {\n\t\tiovecs = append(iovecs, syscall.Iovec{\n\t\t\tBase: &(b.v[0]),\n\t\t})\n\t\tiovecs[idx].SetLen(int(Size))\n\t}\n\tr.iovecs = iovecs\n}\n\nfunc (r *posixReader) Read(fd uintptr) int32 {\n\tn, _, e := syscall.Syscall(syscall.SYS_READV, fd, uintptr(unsafe.Pointer(&r.iovecs[0])), uintptr(len(r.iovecs)))\n\tif e != 0 {\n\t\treturn -1\n\t}\n\treturn int32(n)\n}\n\nfunc (r *posixReader) Clear() {\n\tfor idx := range r.iovecs {\n\t\tr.iovecs[idx].Base = nil\n\t}\n\tr.iovecs = r.iovecs[:0]\n}\n\nfunc newMultiReader() multiReader {\n\treturn &posixReader{}\n}\n"
  },
  {
    "path": "common/buf/readv_reader.go",
    "content": "// +build !wasm\n\npackage buf\n\nimport (\n\t\"io\"\n\t\"runtime\"\n\t\"syscall\"\n\n\t\"v2ray.com/core/common/platform\"\n)\n\ntype allocStrategy struct {\n\tcurrent uint32\n}\n\nfunc (s *allocStrategy) Current() uint32 {\n\treturn s.current\n}\n\nfunc (s *allocStrategy) Adjust(n uint32) {\n\tif n >= s.current {\n\t\ts.current *= 4\n\t} else {\n\t\ts.current = n\n\t}\n\n\tif s.current > 32 {\n\t\ts.current = 32\n\t}\n\n\tif s.current == 0 {\n\t\ts.current = 1\n\t}\n}\n\nfunc (s *allocStrategy) Alloc() []*Buffer {\n\tbs := make([]*Buffer, s.current)\n\tfor i := range bs {\n\t\tbs[i] = New()\n\t}\n\treturn bs\n}\n\ntype multiReader interface {\n\tInit([]*Buffer)\n\tRead(fd uintptr) int32\n\tClear()\n}\n\n// ReadVReader is a Reader that uses readv(2) syscall to read data.\ntype ReadVReader struct {\n\tio.Reader\n\trawConn syscall.RawConn\n\tmr      multiReader\n\talloc   allocStrategy\n}\n\n// NewReadVReader creates a new ReadVReader.\nfunc NewReadVReader(reader io.Reader, rawConn syscall.RawConn) *ReadVReader {\n\treturn &ReadVReader{\n\t\tReader:  reader,\n\t\trawConn: rawConn,\n\t\talloc: allocStrategy{\n\t\t\tcurrent: 1,\n\t\t},\n\t\tmr: newMultiReader(),\n\t}\n}\n\nfunc (r *ReadVReader) readMulti() (MultiBuffer, error) {\n\tbs := r.alloc.Alloc()\n\n\tr.mr.Init(bs)\n\tvar nBytes int32\n\terr := r.rawConn.Read(func(fd uintptr) bool {\n\t\tn := r.mr.Read(fd)\n\t\tif n < 0 {\n\t\t\treturn false\n\t\t}\n\n\t\tnBytes = n\n\t\treturn true\n\t})\n\tr.mr.Clear()\n\n\tif err != nil {\n\t\tReleaseMulti(MultiBuffer(bs))\n\t\treturn nil, err\n\t}\n\n\tif nBytes == 0 {\n\t\tReleaseMulti(MultiBuffer(bs))\n\t\treturn nil, io.EOF\n\t}\n\n\tnBuf := 0\n\tfor nBuf < len(bs) {\n\t\tif nBytes <= 0 {\n\t\t\tbreak\n\t\t}\n\t\tend := nBytes\n\t\tif end > Size {\n\t\t\tend = Size\n\t\t}\n\t\tbs[nBuf].end = end\n\t\tnBytes -= end\n\t\tnBuf++\n\t}\n\n\tfor i := nBuf; i < len(bs); i++ {\n\t\tbs[i].Release()\n\t\tbs[i] = nil\n\t}\n\n\treturn MultiBuffer(bs[:nBuf]), nil\n}\n\n// ReadMultiBuffer implements Reader.\nfunc (r *ReadVReader) ReadMultiBuffer() (MultiBuffer, error) {\n\tif r.alloc.Current() == 1 {\n\t\tb, err := ReadBuffer(r.Reader)\n\t\tif b.IsFull() {\n\t\t\tr.alloc.Adjust(1)\n\t\t}\n\t\treturn MultiBuffer{b}, err\n\t}\n\n\tmb, err := r.readMulti()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tr.alloc.Adjust(uint32(len(mb)))\n\treturn mb, nil\n}\n\nvar useReadv = false\n\nfunc init() {\n\tconst defaultFlagValue = \"NOT_DEFINED_AT_ALL\"\n\tvalue := platform.NewEnvFlag(\"v2ray.buf.readv\").GetValue(func() string { return defaultFlagValue })\n\tswitch value {\n\tcase defaultFlagValue, \"auto\":\n\t\tif (runtime.GOARCH == \"386\" || runtime.GOARCH == \"amd64\" || runtime.GOARCH == \"s390x\") && (runtime.GOOS == \"linux\" || runtime.GOOS == \"darwin\" || runtime.GOOS == \"windows\") {\n\t\t\tuseReadv = true\n\t\t}\n\tcase \"enable\":\n\t\tuseReadv = true\n\t}\n}\n"
  },
  {
    "path": "common/buf/readv_reader_wasm.go",
    "content": "// +build wasm\n\npackage buf\n\nimport (\n\t\"io\"\n\t\"syscall\"\n)\n\nconst useReadv = false\n\nfunc NewReadVReader(reader io.Reader, rawConn syscall.RawConn) Reader {\n\tpanic(\"not implemented\")\n}\n"
  },
  {
    "path": "common/buf/readv_test.go",
    "content": "// +build !wasm\n\npackage buf_test\n\nimport (\n\t\"crypto/rand\"\n\t\"net\"\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\n\t\"golang.org/x/sync/errgroup\"\n\t\"v2ray.com/core/common\"\n\t. \"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/testing/servers/tcp\"\n)\n\nfunc TestReadvReader(t *testing.T) {\n\ttcpServer := &tcp.Server{\n\t\tMsgProcessor: func(b []byte) []byte {\n\t\t\treturn b\n\t\t},\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\tdefer tcpServer.Close() // nolint: errcheck\n\n\tconn, err := net.Dial(\"tcp\", dest.NetAddr())\n\tcommon.Must(err)\n\tdefer conn.Close() // nolint: errcheck\n\n\tconst size = 8192\n\tdata := make([]byte, 8192)\n\tcommon.Must2(rand.Read(data))\n\n\tvar errg errgroup.Group\n\terrg.Go(func() error {\n\t\twriter := NewWriter(conn)\n\t\tmb := MergeBytes(nil, data)\n\n\t\treturn writer.WriteMultiBuffer(mb)\n\t})\n\n\tdefer func() {\n\t\tif err := errg.Wait(); err != nil {\n\t\t\tt.Error(err)\n\t\t}\n\t}()\n\n\trawConn, err := conn.(*net.TCPConn).SyscallConn()\n\tcommon.Must(err)\n\n\treader := NewReadVReader(conn, rawConn)\n\tvar rmb MultiBuffer\n\tfor {\n\t\tmb, err := reader.ReadMultiBuffer()\n\t\tif err != nil {\n\t\t\tt.Fatal(\"unexpected error: \", err)\n\t\t}\n\t\trmb, _ = MergeMulti(rmb, mb)\n\t\tif rmb.Len() == size {\n\t\t\tbreak\n\t\t}\n\t}\n\n\trdata := make([]byte, size)\n\tSplitBytes(rmb, rdata)\n\n\tif r := cmp.Diff(data, rdata); r != \"\" {\n\t\tt.Fatal(r)\n\t}\n}\n"
  },
  {
    "path": "common/buf/readv_unix.go",
    "content": "// +build illumos\n\npackage buf\n\nimport \"golang.org/x/sys/unix\"\n\ntype unixReader struct {\n\tiovs [][]byte\n}\n\nfunc (r *unixReader) Init(bs []*Buffer) {\n\tiovs := r.iovs\n\tif iovs == nil {\n\t\tiovs = make([][]byte, 0, len(bs))\n\t}\n\tfor _, b := range bs {\n\t\tiovs = append(iovs, b.v)\n\t}\n\tr.iovs = iovs\n}\n\nfunc (r *unixReader) Read(fd uintptr) int32 {\n\tn, e := unix.Readv(int(fd), r.iovs)\n\tif e != nil {\n\t\treturn -1\n\t}\n\treturn int32(n)\n}\n\nfunc (r *unixReader) Clear() {\n\tr.iovs = r.iovs[:0]\n}\n\nfunc newMultiReader() multiReader {\n\treturn &unixReader{}\n}\n"
  },
  {
    "path": "common/buf/readv_windows.go",
    "content": "package buf\n\nimport (\n\t\"syscall\"\n)\n\ntype windowsReader struct {\n\tbufs []syscall.WSABuf\n}\n\nfunc (r *windowsReader) Init(bs []*Buffer) {\n\tif r.bufs == nil {\n\t\tr.bufs = make([]syscall.WSABuf, 0, len(bs))\n\t}\n\tfor _, b := range bs {\n\t\tr.bufs = append(r.bufs, syscall.WSABuf{Len: uint32(Size), Buf: &b.v[0]})\n\t}\n}\n\nfunc (r *windowsReader) Clear() {\n\tfor idx := range r.bufs {\n\t\tr.bufs[idx].Buf = nil\n\t}\n\tr.bufs = r.bufs[:0]\n}\n\nfunc (r *windowsReader) Read(fd uintptr) int32 {\n\tvar nBytes uint32\n\tvar flags uint32\n\terr := syscall.WSARecv(syscall.Handle(fd), &r.bufs[0], uint32(len(r.bufs)), &nBytes, &flags, nil, nil)\n\tif err != nil {\n\t\treturn -1\n\t}\n\treturn int32(nBytes)\n}\n\nfunc newMultiReader() multiReader {\n\treturn new(windowsReader)\n}\n"
  },
  {
    "path": "common/buf/writer.go",
    "content": "package buf\n\nimport (\n\t\"io\"\n\t\"net\"\n\t\"sync\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/errors\"\n)\n\n// BufferToBytesWriter is a Writer that writes alloc.Buffer into underlying writer.\ntype BufferToBytesWriter struct {\n\tio.Writer\n\n\tcache [][]byte\n}\n\n// WriteMultiBuffer implements Writer. This method takes ownership of the given buffer.\nfunc (w *BufferToBytesWriter) WriteMultiBuffer(mb MultiBuffer) error {\n\tdefer ReleaseMulti(mb)\n\n\tsize := mb.Len()\n\tif size == 0 {\n\t\treturn nil\n\t}\n\n\tif len(mb) == 1 {\n\t\treturn WriteAllBytes(w.Writer, mb[0].Bytes())\n\t}\n\n\tif cap(w.cache) < len(mb) {\n\t\tw.cache = make([][]byte, 0, len(mb))\n\t}\n\n\tbs := w.cache\n\tfor _, b := range mb {\n\t\tbs = append(bs, b.Bytes())\n\t}\n\n\tdefer func() {\n\t\tfor idx := range bs {\n\t\t\tbs[idx] = nil\n\t\t}\n\t}()\n\n\tnb := net.Buffers(bs)\n\n\tfor size > 0 {\n\t\tn, err := nb.WriteTo(w.Writer)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tsize -= int32(n)\n\t}\n\n\treturn nil\n}\n\n// ReadFrom implements io.ReaderFrom.\nfunc (w *BufferToBytesWriter) ReadFrom(reader io.Reader) (int64, error) {\n\tvar sc SizeCounter\n\terr := Copy(NewReader(reader), w, CountSize(&sc))\n\treturn sc.Size, err\n}\n\n// BufferedWriter is a Writer with internal buffer.\ntype BufferedWriter struct {\n\tsync.Mutex\n\twriter   Writer\n\tbuffer   *Buffer\n\tbuffered bool\n}\n\n// NewBufferedWriter creates a new BufferedWriter.\nfunc NewBufferedWriter(writer Writer) *BufferedWriter {\n\treturn &BufferedWriter{\n\t\twriter:   writer,\n\t\tbuffer:   New(),\n\t\tbuffered: true,\n\t}\n}\n\n// WriteByte implements io.ByteWriter.\nfunc (w *BufferedWriter) WriteByte(c byte) error {\n\treturn common.Error2(w.Write([]byte{c}))\n}\n\n// Write implements io.Writer.\nfunc (w *BufferedWriter) Write(b []byte) (int, error) {\n\tif len(b) == 0 {\n\t\treturn 0, nil\n\t}\n\n\tw.Lock()\n\tdefer w.Unlock()\n\n\tif !w.buffered {\n\t\tif writer, ok := w.writer.(io.Writer); ok {\n\t\t\treturn writer.Write(b)\n\t\t}\n\t}\n\n\ttotalBytes := 0\n\tfor len(b) > 0 {\n\t\tif w.buffer == nil {\n\t\t\tw.buffer = New()\n\t\t}\n\n\t\tnBytes, err := w.buffer.Write(b)\n\t\ttotalBytes += nBytes\n\t\tif err != nil {\n\t\t\treturn totalBytes, err\n\t\t}\n\t\tif !w.buffered || w.buffer.IsFull() {\n\t\t\tif err := w.flushInternal(); err != nil {\n\t\t\t\treturn totalBytes, err\n\t\t\t}\n\t\t}\n\t\tb = b[nBytes:]\n\t}\n\n\treturn totalBytes, nil\n}\n\n// WriteMultiBuffer implements Writer. It takes ownership of the given MultiBuffer.\nfunc (w *BufferedWriter) WriteMultiBuffer(b MultiBuffer) error {\n\tif b.IsEmpty() {\n\t\treturn nil\n\t}\n\n\tw.Lock()\n\tdefer w.Unlock()\n\n\tif !w.buffered {\n\t\treturn w.writer.WriteMultiBuffer(b)\n\t}\n\n\treader := MultiBufferContainer{\n\t\tMultiBuffer: b,\n\t}\n\tdefer reader.Close()\n\n\tfor !reader.MultiBuffer.IsEmpty() {\n\t\tif w.buffer == nil {\n\t\t\tw.buffer = New()\n\t\t}\n\t\tcommon.Must2(w.buffer.ReadFrom(&reader))\n\t\tif w.buffer.IsFull() {\n\t\t\tif err := w.flushInternal(); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Flush flushes buffered content into underlying writer.\nfunc (w *BufferedWriter) Flush() error {\n\tw.Lock()\n\tdefer w.Unlock()\n\n\treturn w.flushInternal()\n}\n\nfunc (w *BufferedWriter) flushInternal() error {\n\tif w.buffer.IsEmpty() {\n\t\treturn nil\n\t}\n\n\tb := w.buffer\n\tw.buffer = nil\n\n\tif writer, ok := w.writer.(io.Writer); ok {\n\t\terr := WriteAllBytes(writer, b.Bytes())\n\t\tb.Release()\n\t\treturn err\n\t}\n\n\treturn w.writer.WriteMultiBuffer(MultiBuffer{b})\n}\n\n// SetBuffered sets whether the internal buffer is used. If set to false, Flush() will be called to clear the buffer.\nfunc (w *BufferedWriter) SetBuffered(f bool) error {\n\tw.Lock()\n\tdefer w.Unlock()\n\n\tw.buffered = f\n\tif !f {\n\t\treturn w.flushInternal()\n\t}\n\treturn nil\n}\n\n// ReadFrom implements io.ReaderFrom.\nfunc (w *BufferedWriter) ReadFrom(reader io.Reader) (int64, error) {\n\tif err := w.SetBuffered(false); err != nil {\n\t\treturn 0, err\n\t}\n\n\tvar sc SizeCounter\n\terr := Copy(NewReader(reader), w, CountSize(&sc))\n\treturn sc.Size, err\n}\n\n// Close implements io.Closable.\nfunc (w *BufferedWriter) Close() error {\n\tif err := w.Flush(); err != nil {\n\t\treturn err\n\t}\n\treturn common.Close(w.writer)\n}\n\n// SequentialWriter is a Writer that writes MultiBuffer sequentially into the underlying io.Writer.\ntype SequentialWriter struct {\n\tio.Writer\n}\n\n// WriteMultiBuffer implements Writer.\nfunc (w *SequentialWriter) WriteMultiBuffer(mb MultiBuffer) error {\n\tmb, err := WriteMultiBuffer(w.Writer, mb)\n\tReleaseMulti(mb)\n\treturn err\n}\n\ntype noOpWriter byte\n\nfunc (noOpWriter) WriteMultiBuffer(b MultiBuffer) error {\n\tReleaseMulti(b)\n\treturn nil\n}\n\nfunc (noOpWriter) Write(b []byte) (int, error) {\n\treturn len(b), nil\n}\n\nfunc (noOpWriter) ReadFrom(reader io.Reader) (int64, error) {\n\tb := New()\n\tdefer b.Release()\n\n\ttotalBytes := int64(0)\n\tfor {\n\t\tb.Clear()\n\t\t_, err := b.ReadFrom(reader)\n\t\ttotalBytes += int64(b.Len())\n\t\tif err != nil {\n\t\t\tif errors.Cause(err) == io.EOF {\n\t\t\t\treturn totalBytes, nil\n\t\t\t}\n\t\t\treturn totalBytes, err\n\t\t}\n\t}\n}\n\nvar (\n\t// Discard is a Writer that swallows all contents written in.\n\tDiscard Writer = noOpWriter(0)\n\n\t// DiscardBytes is an io.Writer that swallows all contents written in.\n\tDiscardBytes io.Writer = noOpWriter(0)\n)\n"
  },
  {
    "path": "common/buf/writer_test.go",
    "content": "package buf_test\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"crypto/rand\"\n\t\"io\"\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\n\t\"v2ray.com/core/common\"\n\t. \"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/transport/pipe\"\n)\n\nfunc TestWriter(t *testing.T) {\n\tlb := New()\n\tcommon.Must2(lb.ReadFrom(rand.Reader))\n\n\texpectedBytes := append([]byte(nil), lb.Bytes()...)\n\n\twriteBuffer := bytes.NewBuffer(make([]byte, 0, 1024*1024))\n\n\twriter := NewBufferedWriter(NewWriter(writeBuffer))\n\twriter.SetBuffered(false)\n\tcommon.Must(writer.WriteMultiBuffer(MultiBuffer{lb}))\n\tcommon.Must(writer.Flush())\n\n\tif r := cmp.Diff(expectedBytes, writeBuffer.Bytes()); r != \"\" {\n\t\tt.Error(r)\n\t}\n}\n\nfunc TestBytesWriterReadFrom(t *testing.T) {\n\tconst size = 50000\n\tpReader, pWriter := pipe.New(pipe.WithSizeLimit(size))\n\treader := bufio.NewReader(io.LimitReader(rand.Reader, size))\n\twriter := NewBufferedWriter(pWriter)\n\twriter.SetBuffered(false)\n\tnBytes, err := reader.WriteTo(writer)\n\tif nBytes != size {\n\t\tt.Fatal(\"unexpected size of bytes written: \", nBytes)\n\t}\n\tif err != nil {\n\t\tt.Fatal(\"expect success, but actually error: \", err.Error())\n\t}\n\n\tmb, err := pReader.ReadMultiBuffer()\n\tcommon.Must(err)\n\tif mb.Len() != size {\n\t\tt.Fatal(\"unexpected size read: \", mb.Len())\n\t}\n}\n\nfunc TestDiscardBytes(t *testing.T) {\n\tb := New()\n\tcommon.Must2(b.ReadFullFrom(rand.Reader, Size))\n\n\tnBytes, err := io.Copy(DiscardBytes, b)\n\tcommon.Must(err)\n\tif nBytes != Size {\n\t\tt.Error(\"copy size: \", nBytes)\n\t}\n}\n\nfunc TestDiscardBytesMultiBuffer(t *testing.T) {\n\tconst size = 10240*1024 + 1\n\tbuffer := bytes.NewBuffer(make([]byte, 0, size))\n\tcommon.Must2(buffer.ReadFrom(io.LimitReader(rand.Reader, size)))\n\n\tr := NewReader(buffer)\n\tnBytes, err := io.Copy(DiscardBytes, &BufferedReader{Reader: r})\n\tcommon.Must(err)\n\tif nBytes != size {\n\t\tt.Error(\"copy size: \", nBytes)\n\t}\n}\n\nfunc TestWriterInterface(t *testing.T) {\n\t{\n\t\tvar writer interface{} = (*BufferToBytesWriter)(nil)\n\t\tswitch writer.(type) {\n\t\tcase Writer, io.Writer, io.ReaderFrom:\n\t\tdefault:\n\t\t\tt.Error(\"BufferToBytesWriter is not Writer, io.Writer or io.ReaderFrom\")\n\t\t}\n\t}\n\n\t{\n\t\tvar writer interface{} = (*BufferedWriter)(nil)\n\t\tswitch writer.(type) {\n\t\tcase Writer, io.Writer, io.ReaderFrom, io.ByteWriter:\n\t\tdefault:\n\t\t\tt.Error(\"BufferedWriter is not Writer, io.Writer, io.ReaderFrom or io.ByteWriter\")\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "common/bytespool/pool.go",
    "content": "package bytespool\n\nimport \"sync\"\n\nfunc createAllocFunc(size int32) func() interface{} {\n\treturn func() interface{} {\n\t\treturn make([]byte, size)\n\t}\n}\n\n// The following parameters controls the size of buffer pools.\n// There are numPools pools. Starting from 2k size, the size of each pool is sizeMulti of the previous one.\n// Package buf is guaranteed to not use buffers larger than the largest pool.\n// Other packets may use larger buffers.\nconst (\n\tnumPools  = 4\n\tsizeMulti = 4\n)\n\nvar (\n\tpool     [numPools]sync.Pool\n\tpoolSize [numPools]int32\n)\n\nfunc init() {\n\tsize := int32(2048)\n\tfor i := 0; i < numPools; i++ {\n\t\tpool[i] = sync.Pool{\n\t\t\tNew: createAllocFunc(size),\n\t\t}\n\t\tpoolSize[i] = size\n\t\tsize *= sizeMulti\n\t}\n}\n\n// GetPool returns a sync.Pool that generates bytes array with at least the given size.\n// It may return nil if no such pool exists.\n//\n// v2ray:api:stable\nfunc GetPool(size int32) *sync.Pool {\n\tfor idx, ps := range poolSize {\n\t\tif size <= ps {\n\t\t\treturn &pool[idx]\n\t\t}\n\t}\n\treturn nil\n}\n\n// Alloc returns a byte slice with at least the given size. Minimum size of returned slice is 2048.\n//\n// v2ray:api:stable\nfunc Alloc(size int32) []byte {\n\tpool := GetPool(size)\n\tif pool != nil {\n\t\treturn pool.Get().([]byte)\n\t}\n\treturn make([]byte, size)\n}\n\n// Free puts a byte slice into the internal pool.\n//\n// v2ray:api:stable\nfunc Free(b []byte) {\n\tsize := int32(cap(b))\n\tb = b[0:cap(b)]\n\tfor i := numPools - 1; i >= 0; i-- {\n\t\tif size >= poolSize[i] {\n\t\t\tpool[i].Put(b) // nolint: megacheck\n\t\t\treturn\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "common/cmdarg/cmdarg.go",
    "content": "package cmdarg\n\nimport \"strings\"\n\n// Arg is used by flag to accept multiple argument.\ntype Arg []string\n\nfunc (c *Arg) String() string {\n\treturn strings.Join([]string(*c), \" \")\n}\n\n// Set is the method flag package calls\nfunc (c *Arg) Set(value string) error {\n\t*c = append(*c, value)\n\treturn nil\n}\n"
  },
  {
    "path": "common/common.go",
    "content": "// Package common contains common utilities that are shared among other packages.\n// See each sub-package for detail.\npackage common\n\nimport (\n\t\"fmt\"\n\t\"go/build\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"v2ray.com/core/common/errors\"\n)\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n\nvar (\n\t// ErrNoClue is for the situation that existing information is not enough to make a decision. For example, Router may return this error when there is no suitable route.\n\tErrNoClue = errors.New(\"not enough information for making a decision\")\n)\n\n// Must panics if err is not nil.\nfunc Must(err error) {\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// Must2 panics if the second parameter is not nil, otherwise returns the first parameter.\nfunc Must2(v interface{}, err error) interface{} {\n\tMust(err)\n\treturn v\n}\n\n// Error2 returns the err from the 2nd parameter.\nfunc Error2(v interface{}, err error) error {\n\treturn err\n}\n\n// envFile returns the name of the Go environment configuration file.\n// Copy from https://github.com/golang/go/blob/c4f2a9788a7be04daf931ac54382fbe2cb754938/src/cmd/go/internal/cfg/cfg.go#L150-L166\nfunc envFile() (string, error) {\n\tif file := os.Getenv(\"GOENV\"); file != \"\" {\n\t\tif file == \"off\" {\n\t\t\treturn \"\", fmt.Errorf(\"GOENV=off\")\n\t\t}\n\t\treturn file, nil\n\t}\n\tdir, err := os.UserConfigDir()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tif dir == \"\" {\n\t\treturn \"\", fmt.Errorf(\"missing user-config dir\")\n\t}\n\treturn filepath.Join(dir, \"go\", \"env\"), nil\n}\n\n// GetRuntimeEnv returns the value of runtime environment variable,\n// that is set by running following command: `go env -w key=value`.\nfunc GetRuntimeEnv(key string) (string, error) {\n\tfile, err := envFile()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tif file == \"\" {\n\t\treturn \"\", fmt.Errorf(\"missing runtime env file\")\n\t}\n\tvar data []byte\n\tvar runtimeEnv string\n\tdata, readErr := ioutil.ReadFile(file)\n\tif readErr != nil {\n\t\treturn \"\", readErr\n\t}\n\tenvStrings := strings.Split(string(data), \"\\n\")\n\tfor _, envItem := range envStrings {\n\t\tenvItem = strings.TrimSuffix(envItem, \"\\r\")\n\t\tenvKeyValue := strings.Split(envItem, \"=\")\n\t\tif strings.EqualFold(strings.TrimSpace(envKeyValue[0]), key) {\n\t\t\truntimeEnv = strings.TrimSpace(envKeyValue[1])\n\t\t}\n\t}\n\treturn runtimeEnv, nil\n}\n\n// GetGOBIN returns GOBIN environment variable as a string. It will NOT be empty.\nfunc GetGOBIN() string {\n\t// The one set by user explicitly by `export GOBIN=/path` or `env GOBIN=/path command`\n\tGOBIN := os.Getenv(\"GOBIN\")\n\tif GOBIN == \"\" {\n\t\tvar err error\n\t\t// The one set by user by running `go env -w GOBIN=/path`\n\t\tGOBIN, err = GetRuntimeEnv(\"GOBIN\")\n\t\tif err != nil {\n\t\t\t// The default one that Golang uses\n\t\t\treturn filepath.Join(build.Default.GOPATH, \"bin\")\n\t\t}\n\t\tif GOBIN == \"\" {\n\t\t\treturn filepath.Join(build.Default.GOPATH, \"bin\")\n\t\t}\n\t\treturn GOBIN\n\t}\n\treturn GOBIN\n}\n\n// GetGOPATH returns GOPATH environment variable as a string. It will NOT be empty.\nfunc GetGOPATH() string {\n\t// The one set by user explicitly by `export GOPATH=/path` or `env GOPATH=/path command`\n\tGOPATH := os.Getenv(\"GOPATH\")\n\tif GOPATH == \"\" {\n\t\tvar err error\n\t\t// The one set by user by running `go env -w GOPATH=/path`\n\t\tGOPATH, err = GetRuntimeEnv(\"GOPATH\")\n\t\tif err != nil {\n\t\t\t// The default one that Golang uses\n\t\t\treturn build.Default.GOPATH\n\t\t}\n\t\tif GOPATH == \"\" {\n\t\t\treturn build.Default.GOPATH\n\t\t}\n\t\treturn GOPATH\n\t}\n\treturn GOPATH\n}\n\n// GetModuleName returns the value of module in `go.mod` file.\nfunc GetModuleName(pathToProjectRoot string) (string, error) {\n\tvar moduleName string\n\tloopPath := pathToProjectRoot\n\tfor {\n\t\tif idx := strings.LastIndex(loopPath, string(filepath.Separator)); idx >= 0 {\n\t\t\tgomodPath := filepath.Join(loopPath, \"go.mod\")\n\t\t\tgomodBytes, err := ioutil.ReadFile(gomodPath)\n\t\t\tif err != nil {\n\t\t\t\tloopPath = loopPath[:idx]\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tgomodContent := string(gomodBytes)\n\t\t\tmoduleIdx := strings.Index(gomodContent, \"module \")\n\t\t\tnewLineIdx := strings.Index(gomodContent, \"\\n\")\n\n\t\t\tif moduleIdx >= 0 {\n\t\t\t\tif newLineIdx >= 0 {\n\t\t\t\t\tmoduleName = strings.TrimSpace(gomodContent[moduleIdx+6 : newLineIdx])\n\t\t\t\t\tmoduleName = strings.TrimSuffix(moduleName, \"\\r\")\n\t\t\t\t} else {\n\t\t\t\t\tmoduleName = strings.TrimSpace(gomodContent[moduleIdx+6:])\n\t\t\t\t}\n\t\t\t\treturn moduleName, nil\n\t\t\t}\n\t\t\treturn \"\", fmt.Errorf(\"can not get module path in `%s`\", gomodPath)\n\t\t}\n\t\tbreak\n\t}\n\treturn moduleName, fmt.Errorf(\"no `go.mod` file in every parent directory of `%s`\", pathToProjectRoot)\n}\n"
  },
  {
    "path": "common/common_test.go",
    "content": "package common_test\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t. \"v2ray.com/core/common\"\n)\n\nfunc TestMust(t *testing.T) {\n\thasPanic := func(f func()) (ret bool) {\n\t\tdefer func() {\n\t\t\tif r := recover(); r != nil {\n\t\t\t\tret = true\n\t\t\t}\n\t\t}()\n\t\tf()\n\t\treturn false\n\t}\n\n\ttestCases := []struct {\n\t\tInput func()\n\t\tPanic bool\n\t}{\n\t\t{\n\t\t\tPanic: true,\n\t\t\tInput: func() { Must(func() error { return errors.New(\"test error\") }()) },\n\t\t},\n\t\t{\n\t\t\tPanic: true,\n\t\t\tInput: func() { Must2(func() (int, error) { return 0, errors.New(\"test error\") }()) },\n\t\t},\n\t\t{\n\t\t\tPanic: false,\n\t\t\tInput: func() { Must(func() error { return nil }()) },\n\t\t},\n\t}\n\n\tfor idx, test := range testCases {\n\t\tif hasPanic(test.Input) != test.Panic {\n\t\t\tt.Error(\"test case #\", idx, \" expect panic \", test.Panic, \" but actually not\")\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "common/crypto/aes.go",
    "content": "package crypto\n\nimport (\n\t\"crypto/aes\"\n\t\"crypto/cipher\"\n\n\t\"v2ray.com/core/common\"\n)\n\n// NewAesDecryptionStream creates a new AES encryption stream based on given key and IV.\n// Caller must ensure the length of key and IV is either 16, 24 or 32 bytes.\nfunc NewAesDecryptionStream(key []byte, iv []byte) cipher.Stream {\n\treturn NewAesStreamMethod(key, iv, cipher.NewCFBDecrypter)\n}\n\n// NewAesEncryptionStream creates a new AES description stream based on given key and IV.\n// Caller must ensure the length of key and IV is either 16, 24 or 32 bytes.\nfunc NewAesEncryptionStream(key []byte, iv []byte) cipher.Stream {\n\treturn NewAesStreamMethod(key, iv, cipher.NewCFBEncrypter)\n}\n\nfunc NewAesStreamMethod(key []byte, iv []byte, f func(cipher.Block, []byte) cipher.Stream) cipher.Stream {\n\taesBlock, err := aes.NewCipher(key)\n\tcommon.Must(err)\n\treturn f(aesBlock, iv)\n}\n\n// NewAesCTRStream creates a stream cipher based on AES-CTR.\nfunc NewAesCTRStream(key []byte, iv []byte) cipher.Stream {\n\treturn NewAesStreamMethod(key, iv, cipher.NewCTR)\n}\n\n// NewAesGcm creates a AEAD cipher based on AES-GCM.\nfunc NewAesGcm(key []byte) cipher.AEAD {\n\tblock, err := aes.NewCipher(key)\n\tcommon.Must(err)\n\taead, err := cipher.NewGCM(block)\n\tcommon.Must(err)\n\treturn aead\n}\n"
  },
  {
    "path": "common/crypto/auth.go",
    "content": "package crypto\n\nimport (\n\t\"crypto/cipher\"\n\t\"io\"\n\t\"math/rand\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/bytespool\"\n\t\"v2ray.com/core/common/protocol\"\n)\n\ntype BytesGenerator func() []byte\n\nfunc GenerateEmptyBytes() BytesGenerator {\n\tvar b [1]byte\n\treturn func() []byte {\n\t\treturn b[:0]\n\t}\n}\n\nfunc GenerateStaticBytes(content []byte) BytesGenerator {\n\treturn func() []byte {\n\t\treturn content\n\t}\n}\n\nfunc GenerateIncreasingNonce(nonce []byte) BytesGenerator {\n\tc := append([]byte(nil), nonce...)\n\treturn func() []byte {\n\t\tfor i := range c {\n\t\t\tc[i]++\n\t\t\tif c[i] != 0 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\treturn c\n\t}\n}\n\nfunc GenerateInitialAEADNonce() BytesGenerator {\n\treturn GenerateIncreasingNonce([]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF})\n}\n\ntype Authenticator interface {\n\tNonceSize() int\n\tOverhead() int\n\tOpen(dst, cipherText []byte) ([]byte, error)\n\tSeal(dst, plainText []byte) ([]byte, error)\n}\n\ntype AEADAuthenticator struct {\n\tcipher.AEAD\n\tNonceGenerator          BytesGenerator\n\tAdditionalDataGenerator BytesGenerator\n}\n\nfunc (v *AEADAuthenticator) Open(dst, cipherText []byte) ([]byte, error) {\n\tiv := v.NonceGenerator()\n\tif len(iv) != v.AEAD.NonceSize() {\n\t\treturn nil, newError(\"invalid AEAD nonce size: \", len(iv))\n\t}\n\n\tvar additionalData []byte\n\tif v.AdditionalDataGenerator != nil {\n\t\tadditionalData = v.AdditionalDataGenerator()\n\t}\n\treturn v.AEAD.Open(dst, iv, cipherText, additionalData)\n}\n\nfunc (v *AEADAuthenticator) Seal(dst, plainText []byte) ([]byte, error) {\n\tiv := v.NonceGenerator()\n\tif len(iv) != v.AEAD.NonceSize() {\n\t\treturn nil, newError(\"invalid AEAD nonce size: \", len(iv))\n\t}\n\n\tvar additionalData []byte\n\tif v.AdditionalDataGenerator != nil {\n\t\tadditionalData = v.AdditionalDataGenerator()\n\t}\n\treturn v.AEAD.Seal(dst, iv, plainText, additionalData), nil\n}\n\ntype AuthenticationReader struct {\n\tauth         Authenticator\n\treader       *buf.BufferedReader\n\tsizeParser   ChunkSizeDecoder\n\tsizeBytes    []byte\n\ttransferType protocol.TransferType\n\tpadding      PaddingLengthGenerator\n\tsize         uint16\n\tpaddingLen   uint16\n\thasSize      bool\n\tdone         bool\n}\n\nfunc NewAuthenticationReader(auth Authenticator, sizeParser ChunkSizeDecoder, reader io.Reader, transferType protocol.TransferType, paddingLen PaddingLengthGenerator) *AuthenticationReader {\n\tr := &AuthenticationReader{\n\t\tauth:         auth,\n\t\tsizeParser:   sizeParser,\n\t\ttransferType: transferType,\n\t\tpadding:      paddingLen,\n\t\tsizeBytes:    make([]byte, sizeParser.SizeBytes()),\n\t}\n\tif breader, ok := reader.(*buf.BufferedReader); ok {\n\t\tr.reader = breader\n\t} else {\n\t\tr.reader = &buf.BufferedReader{Reader: buf.NewReader(reader)}\n\t}\n\treturn r\n}\n\nfunc (r *AuthenticationReader) readSize() (uint16, uint16, error) {\n\tif r.hasSize {\n\t\tr.hasSize = false\n\t\treturn r.size, r.paddingLen, nil\n\t}\n\tif _, err := io.ReadFull(r.reader, r.sizeBytes); err != nil {\n\t\treturn 0, 0, err\n\t}\n\tvar padding uint16\n\tif r.padding != nil {\n\t\tpadding = r.padding.NextPaddingLen()\n\t}\n\tsize, err := r.sizeParser.Decode(r.sizeBytes)\n\treturn size, padding, err\n}\n\nvar errSoft = newError(\"waiting for more data\")\n\nfunc (r *AuthenticationReader) readBuffer(size int32, padding int32) (*buf.Buffer, error) {\n\tb := buf.New()\n\tif _, err := b.ReadFullFrom(r.reader, size); err != nil {\n\t\tb.Release()\n\t\treturn nil, err\n\t}\n\tsize -= padding\n\trb, err := r.auth.Open(b.BytesTo(0), b.BytesTo(size))\n\tif err != nil {\n\t\tb.Release()\n\t\treturn nil, err\n\t}\n\tb.Resize(0, int32(len(rb)))\n\treturn b, nil\n}\n\nfunc (r *AuthenticationReader) readInternal(soft bool, mb *buf.MultiBuffer) error {\n\tif soft && r.reader.BufferedBytes() < r.sizeParser.SizeBytes() {\n\t\treturn errSoft\n\t}\n\n\tif r.done {\n\t\treturn io.EOF\n\t}\n\n\tsize, padding, err := r.readSize()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif size == uint16(r.auth.Overhead())+padding {\n\t\tr.done = true\n\t\treturn io.EOF\n\t}\n\n\tif soft && int32(size) > r.reader.BufferedBytes() {\n\t\tr.size = size\n\t\tr.paddingLen = padding\n\t\tr.hasSize = true\n\t\treturn errSoft\n\t}\n\n\tif size <= buf.Size {\n\t\tb, err := r.readBuffer(int32(size), int32(padding))\n\t\tif err != nil {\n\t\t\treturn nil\n\t\t}\n\t\t*mb = append(*mb, b)\n\t\treturn nil\n\t}\n\n\tpayload := bytespool.Alloc(int32(size))\n\tdefer bytespool.Free(payload)\n\n\tif _, err := io.ReadFull(r.reader, payload[:size]); err != nil {\n\t\treturn err\n\t}\n\n\tsize -= padding\n\n\trb, err := r.auth.Open(payload[:0], payload[:size])\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t*mb = buf.MergeBytes(*mb, rb)\n\treturn nil\n}\n\nfunc (r *AuthenticationReader) ReadMultiBuffer() (buf.MultiBuffer, error) {\n\tconst readSize = 16\n\tmb := make(buf.MultiBuffer, 0, readSize)\n\tif err := r.readInternal(false, &mb); err != nil {\n\t\tbuf.ReleaseMulti(mb)\n\t\treturn nil, err\n\t}\n\n\tfor i := 1; i < readSize; i++ {\n\t\terr := r.readInternal(true, &mb)\n\t\tif err == errSoft || err == io.EOF {\n\t\t\tbreak\n\t\t}\n\t\tif err != nil {\n\t\t\tbuf.ReleaseMulti(mb)\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn mb, nil\n}\n\ntype AuthenticationWriter struct {\n\tauth         Authenticator\n\twriter       buf.Writer\n\tsizeParser   ChunkSizeEncoder\n\ttransferType protocol.TransferType\n\tpadding      PaddingLengthGenerator\n}\n\nfunc NewAuthenticationWriter(auth Authenticator, sizeParser ChunkSizeEncoder, writer io.Writer, transferType protocol.TransferType, padding PaddingLengthGenerator) *AuthenticationWriter {\n\tw := &AuthenticationWriter{\n\t\tauth:         auth,\n\t\twriter:       buf.NewWriter(writer),\n\t\tsizeParser:   sizeParser,\n\t\ttransferType: transferType,\n\t}\n\tif padding != nil {\n\t\tw.padding = padding\n\t}\n\treturn w\n}\n\nfunc (w *AuthenticationWriter) seal(b []byte) (*buf.Buffer, error) {\n\tencryptedSize := int32(len(b) + w.auth.Overhead())\n\tvar paddingSize int32\n\tif w.padding != nil {\n\t\tpaddingSize = int32(w.padding.NextPaddingLen())\n\t}\n\n\tsizeBytes := w.sizeParser.SizeBytes()\n\ttotalSize := sizeBytes + encryptedSize + paddingSize\n\tif totalSize > buf.Size {\n\t\treturn nil, newError(\"size too large: \", totalSize)\n\t}\n\n\teb := buf.New()\n\tw.sizeParser.Encode(uint16(encryptedSize+paddingSize), eb.Extend(sizeBytes))\n\tif _, err := w.auth.Seal(eb.Extend(encryptedSize)[:0], b); err != nil {\n\t\teb.Release()\n\t\treturn nil, err\n\t}\n\tif paddingSize > 0 {\n\t\t// With size of the chunk and padding length encrypted, the content of padding doesn't matter much.\n\t\tpaddingBytes := eb.Extend(paddingSize)\n\t\tcommon.Must2(rand.Read(paddingBytes))\n\t}\n\n\treturn eb, nil\n}\n\nfunc (w *AuthenticationWriter) writeStream(mb buf.MultiBuffer) error {\n\tdefer buf.ReleaseMulti(mb)\n\n\tvar maxPadding int32\n\tif w.padding != nil {\n\t\tmaxPadding = int32(w.padding.MaxPaddingLen())\n\t}\n\n\tpayloadSize := buf.Size - int32(w.auth.Overhead()) - w.sizeParser.SizeBytes() - maxPadding\n\tmb2Write := make(buf.MultiBuffer, 0, len(mb)+10)\n\n\ttemp := buf.New()\n\tdefer temp.Release()\n\n\trawBytes := temp.Extend(payloadSize)\n\n\tfor {\n\t\tnb, nBytes := buf.SplitBytes(mb, rawBytes)\n\t\tmb = nb\n\n\t\teb, err := w.seal(rawBytes[:nBytes])\n\n\t\tif err != nil {\n\t\t\tbuf.ReleaseMulti(mb2Write)\n\t\t\treturn err\n\t\t}\n\t\tmb2Write = append(mb2Write, eb)\n\t\tif mb.IsEmpty() {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn w.writer.WriteMultiBuffer(mb2Write)\n}\n\nfunc (w *AuthenticationWriter) writePacket(mb buf.MultiBuffer) error {\n\tdefer buf.ReleaseMulti(mb)\n\n\tmb2Write := make(buf.MultiBuffer, 0, len(mb)+1)\n\n\tfor _, b := range mb {\n\t\tif b.IsEmpty() {\n\t\t\tcontinue\n\t\t}\n\n\t\teb, err := w.seal(b.Bytes())\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tmb2Write = append(mb2Write, eb)\n\t}\n\n\tif mb2Write.IsEmpty() {\n\t\treturn nil\n\t}\n\n\treturn w.writer.WriteMultiBuffer(mb2Write)\n}\n\n// WriteMultiBuffer implements buf.Writer.\nfunc (w *AuthenticationWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {\n\tif mb.IsEmpty() {\n\t\teb, err := w.seal([]byte{})\n\t\tcommon.Must(err)\n\t\treturn w.writer.WriteMultiBuffer(buf.MultiBuffer{eb})\n\t}\n\n\tif w.transferType == protocol.TransferTypeStream {\n\t\treturn w.writeStream(mb)\n\t}\n\n\treturn w.writePacket(mb)\n}\n"
  },
  {
    "path": "common/crypto/auth_test.go",
    "content": "package crypto_test\n\nimport (\n\t\"bytes\"\n\t\"crypto/aes\"\n\t\"crypto/cipher\"\n\t\"crypto/rand\"\n\t\"io\"\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t. \"v2ray.com/core/common/crypto\"\n\t\"v2ray.com/core/common/protocol\"\n)\n\nfunc TestAuthenticationReaderWriter(t *testing.T) {\n\tkey := make([]byte, 16)\n\trand.Read(key)\n\tblock, err := aes.NewCipher(key)\n\tcommon.Must(err)\n\n\taead, err := cipher.NewGCM(block)\n\tcommon.Must(err)\n\n\tconst payloadSize = 1024 * 80\n\trawPayload := make([]byte, payloadSize)\n\trand.Read(rawPayload)\n\n\tpayload := buf.MergeBytes(nil, rawPayload)\n\n\tcache := bytes.NewBuffer(nil)\n\tiv := make([]byte, 12)\n\trand.Read(iv)\n\n\twriter := NewAuthenticationWriter(&AEADAuthenticator{\n\t\tAEAD:                    aead,\n\t\tNonceGenerator:          GenerateStaticBytes(iv),\n\t\tAdditionalDataGenerator: GenerateEmptyBytes(),\n\t}, PlainChunkSizeParser{}, cache, protocol.TransferTypeStream, nil)\n\n\tcommon.Must(writer.WriteMultiBuffer(payload))\n\tif cache.Len() <= 1024*80 {\n\t\tt.Error(\"cache len: \", cache.Len())\n\t}\n\tcommon.Must(writer.WriteMultiBuffer(buf.MultiBuffer{}))\n\n\treader := NewAuthenticationReader(&AEADAuthenticator{\n\t\tAEAD:                    aead,\n\t\tNonceGenerator:          GenerateStaticBytes(iv),\n\t\tAdditionalDataGenerator: GenerateEmptyBytes(),\n\t}, PlainChunkSizeParser{}, cache, protocol.TransferTypeStream, nil)\n\n\tvar mb buf.MultiBuffer\n\n\tfor mb.Len() < payloadSize {\n\t\tmb2, err := reader.ReadMultiBuffer()\n\t\tcommon.Must(err)\n\n\t\tmb, _ = buf.MergeMulti(mb, mb2)\n\t}\n\n\tif mb.Len() != payloadSize {\n\t\tt.Error(\"mb len: \", mb.Len())\n\t}\n\n\tmbContent := make([]byte, payloadSize)\n\tbuf.SplitBytes(mb, mbContent)\n\tif r := cmp.Diff(mbContent, rawPayload); r != \"\" {\n\t\tt.Error(r)\n\t}\n\n\t_, err = reader.ReadMultiBuffer()\n\tif err != io.EOF {\n\t\tt.Error(\"error: \", err)\n\t}\n}\n\nfunc TestAuthenticationReaderWriterPacket(t *testing.T) {\n\tkey := make([]byte, 16)\n\tcommon.Must2(rand.Read(key))\n\tblock, err := aes.NewCipher(key)\n\tcommon.Must(err)\n\n\taead, err := cipher.NewGCM(block)\n\tcommon.Must(err)\n\n\tcache := buf.New()\n\tiv := make([]byte, 12)\n\trand.Read(iv)\n\n\twriter := NewAuthenticationWriter(&AEADAuthenticator{\n\t\tAEAD:                    aead,\n\t\tNonceGenerator:          GenerateStaticBytes(iv),\n\t\tAdditionalDataGenerator: GenerateEmptyBytes(),\n\t}, PlainChunkSizeParser{}, cache, protocol.TransferTypePacket, nil)\n\n\tvar payload buf.MultiBuffer\n\tpb1 := buf.New()\n\tpb1.Write([]byte(\"abcd\"))\n\tpayload = append(payload, pb1)\n\n\tpb2 := buf.New()\n\tpb2.Write([]byte(\"efgh\"))\n\tpayload = append(payload, pb2)\n\n\tcommon.Must(writer.WriteMultiBuffer(payload))\n\tif cache.Len() == 0 {\n\t\tt.Error(\"cache len: \", cache.Len())\n\t}\n\n\tcommon.Must(writer.WriteMultiBuffer(buf.MultiBuffer{}))\n\n\treader := NewAuthenticationReader(&AEADAuthenticator{\n\t\tAEAD:                    aead,\n\t\tNonceGenerator:          GenerateStaticBytes(iv),\n\t\tAdditionalDataGenerator: GenerateEmptyBytes(),\n\t}, PlainChunkSizeParser{}, cache, protocol.TransferTypePacket, nil)\n\n\tmb, err := reader.ReadMultiBuffer()\n\tcommon.Must(err)\n\n\tmb, b1 := buf.SplitFirst(mb)\n\tif b1.String() != \"abcd\" {\n\t\tt.Error(\"b1: \", b1.String())\n\t}\n\n\tmb, b2 := buf.SplitFirst(mb)\n\tif b2.String() != \"efgh\" {\n\t\tt.Error(\"b2: \", b2.String())\n\t}\n\n\tif !mb.IsEmpty() {\n\t\tt.Error(\"not empty\")\n\t}\n\n\t_, err = reader.ReadMultiBuffer()\n\tif err != io.EOF {\n\t\tt.Error(\"error: \", err)\n\t}\n}\n"
  },
  {
    "path": "common/crypto/benchmark_test.go",
    "content": "package crypto_test\n\nimport (\n\t\"crypto/cipher\"\n\t\"testing\"\n\n\t. \"v2ray.com/core/common/crypto\"\n)\n\nconst benchSize = 1024 * 1024\n\nfunc benchmarkStream(b *testing.B, c cipher.Stream) {\n\tb.SetBytes(benchSize)\n\tinput := make([]byte, benchSize)\n\toutput := make([]byte, benchSize)\n\tb.ResetTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\tc.XORKeyStream(output, input)\n\t}\n}\n\nfunc BenchmarkChaCha20(b *testing.B) {\n\tkey := make([]byte, 32)\n\tnonce := make([]byte, 8)\n\tc := NewChaCha20Stream(key, nonce)\n\tbenchmarkStream(b, c)\n}\n\nfunc BenchmarkChaCha20IETF(b *testing.B) {\n\tkey := make([]byte, 32)\n\tnonce := make([]byte, 12)\n\tc := NewChaCha20Stream(key, nonce)\n\tbenchmarkStream(b, c)\n}\n\nfunc BenchmarkAESEncryption(b *testing.B) {\n\tkey := make([]byte, 32)\n\tiv := make([]byte, 16)\n\tc := NewAesEncryptionStream(key, iv)\n\n\tbenchmarkStream(b, c)\n}\n\nfunc BenchmarkAESDecryption(b *testing.B) {\n\tkey := make([]byte, 32)\n\tiv := make([]byte, 16)\n\tc := NewAesDecryptionStream(key, iv)\n\n\tbenchmarkStream(b, c)\n}\n"
  },
  {
    "path": "common/crypto/chacha20.go",
    "content": "package crypto\n\nimport (\n\t\"crypto/cipher\"\n\n\t\"v2ray.com/core/common/crypto/internal\"\n)\n\n// NewChaCha20Stream creates a new Chacha20 encryption/descryption stream based on give key and IV.\n// Caller must ensure the length of key is 32 bytes, and length of IV is either 8 or 12 bytes.\nfunc NewChaCha20Stream(key []byte, iv []byte) cipher.Stream {\n\treturn internal.NewChaCha20Stream(key, iv, 20)\n}\n"
  },
  {
    "path": "common/crypto/chacha20_test.go",
    "content": "package crypto_test\n\nimport (\n\t\"crypto/rand\"\n\t\"encoding/hex\"\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\n\t\"v2ray.com/core/common\"\n\t. \"v2ray.com/core/common/crypto\"\n)\n\nfunc mustDecodeHex(s string) []byte {\n\tb, err := hex.DecodeString(s)\n\tcommon.Must(err)\n\treturn b\n}\n\nfunc TestChaCha20Stream(t *testing.T) {\n\tvar cases = []struct {\n\t\tkey    []byte\n\t\tiv     []byte\n\t\toutput []byte\n\t}{\n\t\t{\n\t\t\tkey: mustDecodeHex(\"0000000000000000000000000000000000000000000000000000000000000000\"),\n\t\t\tiv:  mustDecodeHex(\"0000000000000000\"),\n\t\t\toutput: mustDecodeHex(\"76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7\" +\n\t\t\t\t\"da41597c5157488d7724e03fb8d84a376a43b8f41518a11cc387b669b2ee6586\" +\n\t\t\t\t\"9f07e7be5551387a98ba977c732d080dcb0f29a048e3656912c6533e32ee7aed\" +\n\t\t\t\t\"29b721769ce64e43d57133b074d839d531ed1f28510afb45ace10a1f4b794d6f\"),\n\t\t},\n\t\t{\n\t\t\tkey: mustDecodeHex(\"5555555555555555555555555555555555555555555555555555555555555555\"),\n\t\t\tiv:  mustDecodeHex(\"5555555555555555\"),\n\t\t\toutput: mustDecodeHex(\"bea9411aa453c5434a5ae8c92862f564396855a9ea6e22d6d3b50ae1b3663311\" +\n\t\t\t\t\"a4a3606c671d605ce16c3aece8e61ea145c59775017bee2fa6f88afc758069f7\" +\n\t\t\t\t\"e0b8f676e644216f4d2a3422d7fa36c6c4931aca950e9da42788e6d0b6d1cd83\" +\n\t\t\t\t\"8ef652e97b145b14871eae6c6804c7004db5ac2fce4c68c726d004b10fcaba86\"),\n\t\t},\n\t\t{\n\t\t\tkey:    mustDecodeHex(\"0000000000000000000000000000000000000000000000000000000000000000\"),\n\t\t\tiv:     mustDecodeHex(\"000000000000000000000000\"),\n\t\t\toutput: mustDecodeHex(\"76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7da41597c5157488d7724e03fb8d84a376a43b8f41518a11cc387b669b2ee6586\"),\n\t\t},\n\t}\n\tfor _, c := range cases {\n\t\ts := NewChaCha20Stream(c.key, c.iv)\n\t\tinput := make([]byte, len(c.output))\n\t\tactualOutout := make([]byte, len(c.output))\n\t\ts.XORKeyStream(actualOutout, input)\n\t\tif r := cmp.Diff(c.output, actualOutout); r != \"\" {\n\t\t\tt.Fatal(r)\n\t\t}\n\t}\n}\n\nfunc TestChaCha20Decoding(t *testing.T) {\n\tkey := make([]byte, 32)\n\tcommon.Must2(rand.Read(key))\n\tiv := make([]byte, 8)\n\tcommon.Must2(rand.Read(iv))\n\tstream := NewChaCha20Stream(key, iv)\n\n\tpayload := make([]byte, 1024)\n\tcommon.Must2(rand.Read(payload))\n\n\tx := make([]byte, len(payload))\n\tstream.XORKeyStream(x, payload)\n\n\tstream2 := NewChaCha20Stream(key, iv)\n\tstream2.XORKeyStream(x, x)\n\tif r := cmp.Diff(x, payload); r != \"\" {\n\t\tt.Fatal(r)\n\t}\n}\n"
  },
  {
    "path": "common/crypto/chunk.go",
    "content": "package crypto\n\nimport (\n\t\"encoding/binary\"\n\t\"io\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n)\n\n// ChunkSizeDecoder is a utility class to decode size value from bytes.\ntype ChunkSizeDecoder interface {\n\tSizeBytes() int32\n\tDecode([]byte) (uint16, error)\n}\n\n// ChunkSizeEncoder is a utility class to encode size value into bytes.\ntype ChunkSizeEncoder interface {\n\tSizeBytes() int32\n\tEncode(uint16, []byte) []byte\n}\n\ntype PaddingLengthGenerator interface {\n\tMaxPaddingLen() uint16\n\tNextPaddingLen() uint16\n}\n\ntype PlainChunkSizeParser struct{}\n\nfunc (PlainChunkSizeParser) SizeBytes() int32 {\n\treturn 2\n}\n\nfunc (PlainChunkSizeParser) Encode(size uint16, b []byte) []byte {\n\tbinary.BigEndian.PutUint16(b, size)\n\treturn b[:2]\n}\n\nfunc (PlainChunkSizeParser) Decode(b []byte) (uint16, error) {\n\treturn binary.BigEndian.Uint16(b), nil\n}\n\ntype AEADChunkSizeParser struct {\n\tAuth *AEADAuthenticator\n}\n\nfunc (p *AEADChunkSizeParser) SizeBytes() int32 {\n\treturn 2 + int32(p.Auth.Overhead())\n}\n\nfunc (p *AEADChunkSizeParser) Encode(size uint16, b []byte) []byte {\n\tbinary.BigEndian.PutUint16(b, size-uint16(p.Auth.Overhead()))\n\tb, err := p.Auth.Seal(b[:0], b[:2])\n\tcommon.Must(err)\n\treturn b\n}\n\nfunc (p *AEADChunkSizeParser) Decode(b []byte) (uint16, error) {\n\tb, err := p.Auth.Open(b[:0], b)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn binary.BigEndian.Uint16(b) + uint16(p.Auth.Overhead()), nil\n}\n\ntype ChunkStreamReader struct {\n\tsizeDecoder ChunkSizeDecoder\n\treader      *buf.BufferedReader\n\n\tbuffer       []byte\n\tleftOverSize int32\n\tmaxNumChunk  uint32\n\tnumChunk     uint32\n}\n\nfunc NewChunkStreamReader(sizeDecoder ChunkSizeDecoder, reader io.Reader) *ChunkStreamReader {\n\treturn NewChunkStreamReaderWithChunkCount(sizeDecoder, reader, 0)\n}\n\nfunc NewChunkStreamReaderWithChunkCount(sizeDecoder ChunkSizeDecoder, reader io.Reader, maxNumChunk uint32) *ChunkStreamReader {\n\tr := &ChunkStreamReader{\n\t\tsizeDecoder: sizeDecoder,\n\t\tbuffer:      make([]byte, sizeDecoder.SizeBytes()),\n\t\tmaxNumChunk: maxNumChunk,\n\t}\n\tif breader, ok := reader.(*buf.BufferedReader); ok {\n\t\tr.reader = breader\n\t} else {\n\t\tr.reader = &buf.BufferedReader{Reader: buf.NewReader(reader)}\n\t}\n\n\treturn r\n}\n\nfunc (r *ChunkStreamReader) readSize() (uint16, error) {\n\tif _, err := io.ReadFull(r.reader, r.buffer); err != nil {\n\t\treturn 0, err\n\t}\n\treturn r.sizeDecoder.Decode(r.buffer)\n}\n\nfunc (r *ChunkStreamReader) ReadMultiBuffer() (buf.MultiBuffer, error) {\n\tsize := r.leftOverSize\n\tif size == 0 {\n\t\tr.numChunk++\n\t\tif r.maxNumChunk > 0 && r.numChunk > r.maxNumChunk {\n\t\t\treturn nil, io.EOF\n\t\t}\n\t\tnextSize, err := r.readSize()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif nextSize == 0 {\n\t\t\treturn nil, io.EOF\n\t\t}\n\t\tsize = int32(nextSize)\n\t}\n\tr.leftOverSize = size\n\n\tmb, err := r.reader.ReadAtMost(size)\n\tif !mb.IsEmpty() {\n\t\tr.leftOverSize -= mb.Len()\n\t\treturn mb, nil\n\t}\n\treturn nil, err\n}\n\ntype ChunkStreamWriter struct {\n\tsizeEncoder ChunkSizeEncoder\n\twriter      buf.Writer\n}\n\nfunc NewChunkStreamWriter(sizeEncoder ChunkSizeEncoder, writer io.Writer) *ChunkStreamWriter {\n\treturn &ChunkStreamWriter{\n\t\tsizeEncoder: sizeEncoder,\n\t\twriter:      buf.NewWriter(writer),\n\t}\n}\n\nfunc (w *ChunkStreamWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {\n\tconst sliceSize = 8192\n\tmbLen := mb.Len()\n\tmb2Write := make(buf.MultiBuffer, 0, mbLen/buf.Size+mbLen/sliceSize+2)\n\n\tfor {\n\t\tmb2, slice := buf.SplitSize(mb, sliceSize)\n\t\tmb = mb2\n\n\t\tb := buf.New()\n\t\tw.sizeEncoder.Encode(uint16(slice.Len()), b.Extend(w.sizeEncoder.SizeBytes()))\n\t\tmb2Write = append(mb2Write, b)\n\t\tmb2Write = append(mb2Write, slice...)\n\n\t\tif mb.IsEmpty() {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn w.writer.WriteMultiBuffer(mb2Write)\n}\n"
  },
  {
    "path": "common/crypto/chunk_test.go",
    "content": "package crypto_test\n\nimport (\n\t\"bytes\"\n\t\"io\"\n\t\"testing\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t. \"v2ray.com/core/common/crypto\"\n)\n\nfunc TestChunkStreamIO(t *testing.T) {\n\tcache := bytes.NewBuffer(make([]byte, 0, 8192))\n\n\twriter := NewChunkStreamWriter(PlainChunkSizeParser{}, cache)\n\treader := NewChunkStreamReader(PlainChunkSizeParser{}, cache)\n\n\tb := buf.New()\n\tb.WriteString(\"abcd\")\n\tcommon.Must(writer.WriteMultiBuffer(buf.MultiBuffer{b}))\n\n\tb = buf.New()\n\tb.WriteString(\"efg\")\n\tcommon.Must(writer.WriteMultiBuffer(buf.MultiBuffer{b}))\n\n\tcommon.Must(writer.WriteMultiBuffer(buf.MultiBuffer{}))\n\n\tif cache.Len() != 13 {\n\t\tt.Fatalf(\"Cache length is %d, want 13\", cache.Len())\n\t}\n\n\tmb, err := reader.ReadMultiBuffer()\n\tcommon.Must(err)\n\n\tif s := mb.String(); s != \"abcd\" {\n\t\tt.Error(\"content: \", s)\n\t}\n\n\tmb, err = reader.ReadMultiBuffer()\n\tcommon.Must(err)\n\n\tif s := mb.String(); s != \"efg\" {\n\t\tt.Error(\"content: \", s)\n\t}\n\n\t_, err = reader.ReadMultiBuffer()\n\tif err != io.EOF {\n\t\tt.Error(\"error: \", err)\n\t}\n}\n"
  },
  {
    "path": "common/crypto/crypto.go",
    "content": "// Package crypto provides common crypto libraries for V2Ray.\npackage crypto // import \"v2ray.com/core/common/crypto\"\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n"
  },
  {
    "path": "common/crypto/errors.generated.go",
    "content": "package crypto\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "common/crypto/internal/chacha.go",
    "content": "package internal\n\n//go:generate go run chacha_core_gen.go\n\nimport (\n\t\"encoding/binary\"\n)\n\nconst (\n\twordSize  = 4                    // the size of ChaCha20's words\n\tstateSize = 16                   // the size of ChaCha20's state, in words\n\tblockSize = stateSize * wordSize // the size of ChaCha20's block, in bytes\n)\n\ntype ChaCha20Stream struct {\n\tstate  [stateSize]uint32 // the state as an array of 16 32-bit words\n\tblock  [blockSize]byte   // the keystream as an array of 64 bytes\n\toffset int               // the offset of used bytes in block\n\trounds int\n}\n\nfunc NewChaCha20Stream(key []byte, nonce []byte, rounds int) *ChaCha20Stream {\n\ts := new(ChaCha20Stream)\n\t// the magic constants for 256-bit keys\n\ts.state[0] = 0x61707865\n\ts.state[1] = 0x3320646e\n\ts.state[2] = 0x79622d32\n\ts.state[3] = 0x6b206574\n\n\tfor i := 0; i < 8; i++ {\n\t\ts.state[i+4] = binary.LittleEndian.Uint32(key[i*4 : i*4+4])\n\t}\n\n\tswitch len(nonce) {\n\tcase 8:\n\t\ts.state[14] = binary.LittleEndian.Uint32(nonce[0:])\n\t\ts.state[15] = binary.LittleEndian.Uint32(nonce[4:])\n\tcase 12:\n\t\ts.state[13] = binary.LittleEndian.Uint32(nonce[0:4])\n\t\ts.state[14] = binary.LittleEndian.Uint32(nonce[4:8])\n\t\ts.state[15] = binary.LittleEndian.Uint32(nonce[8:12])\n\tdefault:\n\t\tpanic(\"bad nonce length\")\n\t}\n\n\ts.rounds = rounds\n\tChaCha20Block(&s.state, s.block[:], s.rounds)\n\treturn s\n}\n\nfunc (s *ChaCha20Stream) XORKeyStream(dst, src []byte) {\n\t// Stride over the input in 64-byte blocks, minus the amount of keystream\n\t// previously used. This will produce best results when processing blocks\n\t// of a size evenly divisible by 64.\n\ti := 0\n\tmax := len(src)\n\tfor i < max {\n\t\tgap := blockSize - s.offset\n\n\t\tlimit := i + gap\n\t\tif limit > max {\n\t\t\tlimit = max\n\t\t}\n\n\t\to := s.offset\n\t\tfor j := i; j < limit; j++ {\n\t\t\tdst[j] = src[j] ^ s.block[o]\n\t\t\to++\n\t\t}\n\n\t\ti += gap\n\t\ts.offset = o\n\n\t\tif o == blockSize {\n\t\t\ts.offset = 0\n\t\t\ts.state[12]++\n\t\t\tChaCha20Block(&s.state, s.block[:], s.rounds)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "common/crypto/internal/chacha_core.generated.go",
    "content": "package internal\n\nimport \"encoding/binary\"\n\nfunc ChaCha20Block(s *[16]uint32, out []byte, rounds int) {\n\tvar x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 = s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9], s[10], s[11], s[12], s[13], s[14], s[15]\n\tfor i := 0; i < rounds; i += 2 {\n\t\tvar x uint32\n\n\t\tx0 += x4\n\t\tx = x12 ^ x0\n\t\tx12 = (x << 16) | (x >> (32 - 16))\n\t\tx8 += x12\n\t\tx = x4 ^ x8\n\t\tx4 = (x << 12) | (x >> (32 - 12))\n\t\tx0 += x4\n\t\tx = x12 ^ x0\n\t\tx12 = (x << 8) | (x >> (32 - 8))\n\t\tx8 += x12\n\t\tx = x4 ^ x8\n\t\tx4 = (x << 7) | (x >> (32 - 7))\n\t\tx1 += x5\n\t\tx = x13 ^ x1\n\t\tx13 = (x << 16) | (x >> (32 - 16))\n\t\tx9 += x13\n\t\tx = x5 ^ x9\n\t\tx5 = (x << 12) | (x >> (32 - 12))\n\t\tx1 += x5\n\t\tx = x13 ^ x1\n\t\tx13 = (x << 8) | (x >> (32 - 8))\n\t\tx9 += x13\n\t\tx = x5 ^ x9\n\t\tx5 = (x << 7) | (x >> (32 - 7))\n\t\tx2 += x6\n\t\tx = x14 ^ x2\n\t\tx14 = (x << 16) | (x >> (32 - 16))\n\t\tx10 += x14\n\t\tx = x6 ^ x10\n\t\tx6 = (x << 12) | (x >> (32 - 12))\n\t\tx2 += x6\n\t\tx = x14 ^ x2\n\t\tx14 = (x << 8) | (x >> (32 - 8))\n\t\tx10 += x14\n\t\tx = x6 ^ x10\n\t\tx6 = (x << 7) | (x >> (32 - 7))\n\t\tx3 += x7\n\t\tx = x15 ^ x3\n\t\tx15 = (x << 16) | (x >> (32 - 16))\n\t\tx11 += x15\n\t\tx = x7 ^ x11\n\t\tx7 = (x << 12) | (x >> (32 - 12))\n\t\tx3 += x7\n\t\tx = x15 ^ x3\n\t\tx15 = (x << 8) | (x >> (32 - 8))\n\t\tx11 += x15\n\t\tx = x7 ^ x11\n\t\tx7 = (x << 7) | (x >> (32 - 7))\n\t\tx0 += x5\n\t\tx = x15 ^ x0\n\t\tx15 = (x << 16) | (x >> (32 - 16))\n\t\tx10 += x15\n\t\tx = x5 ^ x10\n\t\tx5 = (x << 12) | (x >> (32 - 12))\n\t\tx0 += x5\n\t\tx = x15 ^ x0\n\t\tx15 = (x << 8) | (x >> (32 - 8))\n\t\tx10 += x15\n\t\tx = x5 ^ x10\n\t\tx5 = (x << 7) | (x >> (32 - 7))\n\t\tx1 += x6\n\t\tx = x12 ^ x1\n\t\tx12 = (x << 16) | (x >> (32 - 16))\n\t\tx11 += x12\n\t\tx = x6 ^ x11\n\t\tx6 = (x << 12) | (x >> (32 - 12))\n\t\tx1 += x6\n\t\tx = x12 ^ x1\n\t\tx12 = (x << 8) | (x >> (32 - 8))\n\t\tx11 += x12\n\t\tx = x6 ^ x11\n\t\tx6 = (x << 7) | (x >> (32 - 7))\n\t\tx2 += x7\n\t\tx = x13 ^ x2\n\t\tx13 = (x << 16) | (x >> (32 - 16))\n\t\tx8 += x13\n\t\tx = x7 ^ x8\n\t\tx7 = (x << 12) | (x >> (32 - 12))\n\t\tx2 += x7\n\t\tx = x13 ^ x2\n\t\tx13 = (x << 8) | (x >> (32 - 8))\n\t\tx8 += x13\n\t\tx = x7 ^ x8\n\t\tx7 = (x << 7) | (x >> (32 - 7))\n\t\tx3 += x4\n\t\tx = x14 ^ x3\n\t\tx14 = (x << 16) | (x >> (32 - 16))\n\t\tx9 += x14\n\t\tx = x4 ^ x9\n\t\tx4 = (x << 12) | (x >> (32 - 12))\n\t\tx3 += x4\n\t\tx = x14 ^ x3\n\t\tx14 = (x << 8) | (x >> (32 - 8))\n\t\tx9 += x14\n\t\tx = x4 ^ x9\n\t\tx4 = (x << 7) | (x >> (32 - 7))\n\t}\n\tbinary.LittleEndian.PutUint32(out[0:4], s[0]+x0)\n\tbinary.LittleEndian.PutUint32(out[4:8], s[1]+x1)\n\tbinary.LittleEndian.PutUint32(out[8:12], s[2]+x2)\n\tbinary.LittleEndian.PutUint32(out[12:16], s[3]+x3)\n\tbinary.LittleEndian.PutUint32(out[16:20], s[4]+x4)\n\tbinary.LittleEndian.PutUint32(out[20:24], s[5]+x5)\n\tbinary.LittleEndian.PutUint32(out[24:28], s[6]+x6)\n\tbinary.LittleEndian.PutUint32(out[28:32], s[7]+x7)\n\tbinary.LittleEndian.PutUint32(out[32:36], s[8]+x8)\n\tbinary.LittleEndian.PutUint32(out[36:40], s[9]+x9)\n\tbinary.LittleEndian.PutUint32(out[40:44], s[10]+x10)\n\tbinary.LittleEndian.PutUint32(out[44:48], s[11]+x11)\n\tbinary.LittleEndian.PutUint32(out[48:52], s[12]+x12)\n\tbinary.LittleEndian.PutUint32(out[52:56], s[13]+x13)\n\tbinary.LittleEndian.PutUint32(out[56:60], s[14]+x14)\n\tbinary.LittleEndian.PutUint32(out[60:64], s[15]+x15)\n}\n"
  },
  {
    "path": "common/crypto/internal/chacha_core_gen.go",
    "content": "// +build generate\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n)\n\nfunc writeQuarterRound(file *os.File, a, b, c, d int) {\n\tadd := \"x%d+=x%d\\n\"\n\txor := \"x=x%d^x%d\\n\"\n\trotate := \"x%d=(x << %d) | (x >> (32 - %d))\\n\"\n\n\tfmt.Fprintf(file, add, a, b)\n\tfmt.Fprintf(file, xor, d, a)\n\tfmt.Fprintf(file, rotate, d, 16, 16)\n\n\tfmt.Fprintf(file, add, c, d)\n\tfmt.Fprintf(file, xor, b, c)\n\tfmt.Fprintf(file, rotate, b, 12, 12)\n\n\tfmt.Fprintf(file, add, a, b)\n\tfmt.Fprintf(file, xor, d, a)\n\tfmt.Fprintf(file, rotate, d, 8, 8)\n\n\tfmt.Fprintf(file, add, c, d)\n\tfmt.Fprintf(file, xor, b, c)\n\tfmt.Fprintf(file, rotate, b, 7, 7)\n}\n\nfunc writeChacha20Block(file *os.File) {\n\tfmt.Fprintln(file, `\nfunc ChaCha20Block(s *[16]uint32, out []byte, rounds int) {\n  var x0,x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15 = s[0],s[1],s[2],s[3],s[4],s[5],s[6],s[7],s[8],s[9],s[10],s[11],s[12],s[13],s[14],s[15]\n\tfor i := 0; i < rounds; i+=2 {\n    var x uint32\n    `)\n\n\twriteQuarterRound(file, 0, 4, 8, 12)\n\twriteQuarterRound(file, 1, 5, 9, 13)\n\twriteQuarterRound(file, 2, 6, 10, 14)\n\twriteQuarterRound(file, 3, 7, 11, 15)\n\twriteQuarterRound(file, 0, 5, 10, 15)\n\twriteQuarterRound(file, 1, 6, 11, 12)\n\twriteQuarterRound(file, 2, 7, 8, 13)\n\twriteQuarterRound(file, 3, 4, 9, 14)\n\tfmt.Fprintln(file, \"}\")\n\tfor i := 0; i < 16; i++ {\n\t\tfmt.Fprintf(file, \"binary.LittleEndian.PutUint32(out[%d:%d], s[%d]+x%d)\\n\", i*4, i*4+4, i, i)\n\t}\n\tfmt.Fprintln(file, \"}\")\n\tfmt.Fprintln(file)\n}\n\nfunc main() {\n\tfile, err := os.OpenFile(\"chacha_core.generated.go\", os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644)\n\tif err != nil {\n\t\tlog.Fatalf(\"Failed to generate chacha_core.go: %v\", err)\n\t}\n\tdefer file.Close()\n\n\tfmt.Fprintln(file, \"package internal\")\n\tfmt.Fprintln(file)\n\tfmt.Fprintln(file, \"import \\\"encoding/binary\\\"\")\n\tfmt.Fprintln(file)\n\twriteChacha20Block(file)\n}\n"
  },
  {
    "path": "common/crypto/io.go",
    "content": "package crypto\n\nimport (\n\t\"crypto/cipher\"\n\t\"io\"\n\n\t\"v2ray.com/core/common/buf\"\n)\n\ntype CryptionReader struct {\n\tstream cipher.Stream\n\treader io.Reader\n}\n\nfunc NewCryptionReader(stream cipher.Stream, reader io.Reader) *CryptionReader {\n\treturn &CryptionReader{\n\t\tstream: stream,\n\t\treader: reader,\n\t}\n}\n\nfunc (r *CryptionReader) Read(data []byte) (int, error) {\n\tnBytes, err := r.reader.Read(data)\n\tif nBytes > 0 {\n\t\tr.stream.XORKeyStream(data[:nBytes], data[:nBytes])\n\t}\n\treturn nBytes, err\n}\n\nvar (\n\t_ buf.Writer = (*CryptionWriter)(nil)\n)\n\ntype CryptionWriter struct {\n\tstream    cipher.Stream\n\twriter    io.Writer\n\tbufWriter buf.Writer\n}\n\n// NewCryptionWriter creates a new CryptionWriter.\nfunc NewCryptionWriter(stream cipher.Stream, writer io.Writer) *CryptionWriter {\n\treturn &CryptionWriter{\n\t\tstream:    stream,\n\t\twriter:    writer,\n\t\tbufWriter: buf.NewWriter(writer),\n\t}\n}\n\n// Write implements io.Writer.Write().\nfunc (w *CryptionWriter) Write(data []byte) (int, error) {\n\tw.stream.XORKeyStream(data, data)\n\n\tif err := buf.WriteAllBytes(w.writer, data); err != nil {\n\t\treturn 0, err\n\t}\n\treturn len(data), nil\n}\n\n// WriteMultiBuffer implements buf.Writer.\nfunc (w *CryptionWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {\n\tfor _, b := range mb {\n\t\tw.stream.XORKeyStream(b.Bytes(), b.Bytes())\n\t}\n\n\treturn w.bufWriter.WriteMultiBuffer(mb)\n}\n"
  },
  {
    "path": "common/dice/dice.go",
    "content": "// Package dice contains common functions to generate random number.\n// It also initialize math/rand with the time in seconds at launch time.\npackage dice // import \"v2ray.com/core/common/dice\"\n\nimport (\n\t\"math/rand\"\n\t\"time\"\n)\n\n// Roll returns a non-negative number between 0 (inclusive) and n (exclusive).\nfunc Roll(n int) int {\n\tif n == 1 {\n\t\treturn 0\n\t}\n\treturn rand.Intn(n)\n}\n\n// Roll returns a non-negative number between 0 (inclusive) and n (exclusive).\nfunc RollDeterministic(n int, seed int64) int {\n\tif n == 1 {\n\t\treturn 0\n\t}\n\treturn rand.New(rand.NewSource(seed)).Intn(n)\n}\n\n// RollUint16 returns a random uint16 value.\nfunc RollUint16() uint16 {\n\treturn uint16(rand.Intn(65536))\n}\n\nfunc RollUint64() uint64 {\n\treturn rand.Uint64()\n}\n\nfunc NewDeterministicDice(seed int64) *deterministicDice {\n\treturn &deterministicDice{rand.New(rand.NewSource(seed))}\n}\n\ntype deterministicDice struct {\n\t*rand.Rand\n}\n\nfunc (dd *deterministicDice) Roll(n int) int {\n\tif n == 1 {\n\t\treturn 0\n\t}\n\treturn dd.Intn(n)\n}\n\nfunc init() {\n\trand.Seed(time.Now().Unix())\n}\n"
  },
  {
    "path": "common/dice/dice_test.go",
    "content": "package dice_test\n\nimport (\n\t\"math/rand\"\n\t\"testing\"\n\n\t. \"v2ray.com/core/common/dice\"\n)\n\nfunc BenchmarkRoll1(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tRoll(1)\n\t}\n}\n\nfunc BenchmarkRoll20(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tRoll(20)\n\t}\n}\n\nfunc BenchmarkIntn1(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\trand.Intn(1)\n\t}\n}\n\nfunc BenchmarkIntn20(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\trand.Intn(20)\n\t}\n}\n"
  },
  {
    "path": "common/errors/errorgen/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"v2ray.com/core/common\"\n)\n\nfunc main() {\n\tpwd, err := os.Getwd()\n\tif err != nil {\n\t\tfmt.Println(\"can not get current working directory\")\n\t\tos.Exit(1)\n\t}\n\tpkg := filepath.Base(pwd)\n\tif pkg == \"v2ray-core\" {\n\t\tpkg = \"core\"\n\t}\n\n\tmoduleName, gmnErr := common.GetModuleName(pwd)\n\tif gmnErr != nil {\n\t\tfmt.Println(\"can not get module path\", gmnErr)\n\t\tos.Exit(1)\n\t}\n\n\tfile, err := os.OpenFile(\"errors.generated.go\", os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644)\n\tif err != nil {\n\t\tlog.Fatalf(\"Failed to generate errors.generated.go: %v\", err)\n\t\tos.Exit(1)\n\t}\n\tdefer file.Close()\n\n\tfmt.Fprintln(file, \"package\", pkg)\n\tfmt.Fprintln(file, \"\")\n\tfmt.Fprintln(file, \"import \\\"\"+moduleName+\"/common/errors\\\"\")\n\tfmt.Fprintln(file, \"\")\n\tfmt.Fprintln(file, \"type errPathObjHolder struct{}\")\n\tfmt.Fprintln(file, \"\")\n\tfmt.Fprintln(file, \"func newError(values ...interface{}) *errors.Error {\")\n\tfmt.Fprintln(file, \"\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\")\n\tfmt.Fprintln(file, \"}\")\n}\n"
  },
  {
    "path": "common/errors/errors.go",
    "content": "// Package errors is a drop-in replacement for Golang lib 'errors'.\npackage errors // import \"v2ray.com/core/common/errors\"\n\nimport (\n\t\"os\"\n\t\"reflect\"\n\t\"strings\"\n\n\t\"v2ray.com/core/common/log\"\n\t\"v2ray.com/core/common/serial\"\n)\n\ntype hasInnerError interface {\n\t// Inner returns the underlying error of this one.\n\tInner() error\n}\n\ntype hasSeverity interface {\n\tSeverity() log.Severity\n}\n\n// Error is an error object with underlying error.\ntype Error struct {\n\tpathObj  interface{}\n\tprefix   []interface{}\n\tmessage  []interface{}\n\tinner    error\n\tseverity log.Severity\n}\n\nfunc (err *Error) WithPathObj(obj interface{}) *Error {\n\terr.pathObj = obj\n\treturn err\n}\n\nfunc (err *Error) pkgPath() string {\n\tif err.pathObj == nil {\n\t\treturn \"\"\n\t}\n\treturn reflect.TypeOf(err.pathObj).PkgPath()\n}\n\n// Error implements error.Error().\nfunc (err *Error) Error() string {\n\tbuilder := strings.Builder{}\n\tfor _, prefix := range err.prefix {\n\t\tbuilder.WriteByte('[')\n\t\tbuilder.WriteString(serial.ToString(prefix))\n\t\tbuilder.WriteString(\"] \")\n\t}\n\n\tpath := err.pkgPath()\n\tif len(path) > 0 {\n\t\tbuilder.WriteString(path)\n\t\tbuilder.WriteString(\": \")\n\t}\n\n\tmsg := serial.Concat(err.message...)\n\tbuilder.WriteString(msg)\n\n\tif err.inner != nil {\n\t\tbuilder.WriteString(\" > \")\n\t\tbuilder.WriteString(err.inner.Error())\n\t}\n\n\treturn builder.String()\n}\n\n// Inner implements hasInnerError.Inner()\nfunc (err *Error) Inner() error {\n\tif err.inner == nil {\n\t\treturn nil\n\t}\n\treturn err.inner\n}\n\nfunc (err *Error) Base(e error) *Error {\n\terr.inner = e\n\treturn err\n}\n\nfunc (err *Error) atSeverity(s log.Severity) *Error {\n\terr.severity = s\n\treturn err\n}\n\nfunc (err *Error) Severity() log.Severity {\n\tif err.inner == nil {\n\t\treturn err.severity\n\t}\n\n\tif s, ok := err.inner.(hasSeverity); ok {\n\t\tas := s.Severity()\n\t\tif as < err.severity {\n\t\t\treturn as\n\t\t}\n\t}\n\n\treturn err.severity\n}\n\n// AtDebug sets the severity to debug.\nfunc (err *Error) AtDebug() *Error {\n\treturn err.atSeverity(log.Severity_Debug)\n}\n\n// AtInfo sets the severity to info.\nfunc (err *Error) AtInfo() *Error {\n\treturn err.atSeverity(log.Severity_Info)\n}\n\n// AtWarning sets the severity to warning.\nfunc (err *Error) AtWarning() *Error {\n\treturn err.atSeverity(log.Severity_Warning)\n}\n\n// AtError sets the severity to error.\nfunc (err *Error) AtError() *Error {\n\treturn err.atSeverity(log.Severity_Error)\n}\n\n// String returns the string representation of this error.\nfunc (err *Error) String() string {\n\treturn err.Error()\n}\n\n// WriteToLog writes current error into log.\nfunc (err *Error) WriteToLog(opts ...ExportOption) {\n\tvar holder ExportOptionHolder\n\n\tfor _, opt := range opts {\n\t\topt(&holder)\n\t}\n\n\tif holder.SessionID > 0 {\n\t\terr.prefix = append(err.prefix, holder.SessionID)\n\t}\n\n\tlog.Record(&log.GeneralMessage{\n\t\tSeverity: GetSeverity(err),\n\t\tContent:  err,\n\t})\n}\n\ntype ExportOptionHolder struct {\n\tSessionID uint32\n}\n\ntype ExportOption func(*ExportOptionHolder)\n\n// New returns a new error object with message formed from given arguments.\nfunc New(msg ...interface{}) *Error {\n\treturn &Error{\n\t\tmessage:  msg,\n\t\tseverity: log.Severity_Info,\n\t}\n}\n\n// Cause returns the root cause of this error.\nfunc Cause(err error) error {\n\tif err == nil {\n\t\treturn nil\n\t}\nL:\n\tfor {\n\t\tswitch inner := err.(type) {\n\t\tcase hasInnerError:\n\t\t\tif inner.Inner() == nil {\n\t\t\t\tbreak L\n\t\t\t}\n\t\t\terr = inner.Inner()\n\t\tcase *os.PathError:\n\t\t\tif inner.Err == nil {\n\t\t\t\tbreak L\n\t\t\t}\n\t\t\terr = inner.Err\n\t\tcase *os.SyscallError:\n\t\t\tif inner.Err == nil {\n\t\t\t\tbreak L\n\t\t\t}\n\t\t\terr = inner.Err\n\t\tdefault:\n\t\t\tbreak L\n\t\t}\n\t}\n\treturn err\n}\n\n// GetSeverity returns the actual severity of the error, including inner errors.\nfunc GetSeverity(err error) log.Severity {\n\tif s, ok := err.(hasSeverity); ok {\n\t\treturn s.Severity()\n\t}\n\treturn log.Severity_Info\n}\n"
  },
  {
    "path": "common/errors/errors_test.go",
    "content": "package errors_test\n\nimport (\n\t\"io\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\n\t. \"v2ray.com/core/common/errors\"\n\t\"v2ray.com/core/common/log\"\n)\n\nfunc TestError(t *testing.T) {\n\terr := New(\"TestError\")\n\tif v := GetSeverity(err); v != log.Severity_Info {\n\t\tt.Error(\"severity: \", v)\n\t}\n\n\terr = New(\"TestError2\").Base(io.EOF)\n\tif v := GetSeverity(err); v != log.Severity_Info {\n\t\tt.Error(\"severity: \", v)\n\t}\n\n\terr = New(\"TestError3\").Base(io.EOF).AtWarning()\n\tif v := GetSeverity(err); v != log.Severity_Warning {\n\t\tt.Error(\"severity: \", v)\n\t}\n\n\terr = New(\"TestError4\").Base(io.EOF).AtWarning()\n\terr = New(\"TestError5\").Base(err)\n\tif v := GetSeverity(err); v != log.Severity_Warning {\n\t\tt.Error(\"severity: \", v)\n\t}\n\tif v := err.Error(); !strings.Contains(v, \"EOF\") {\n\t\tt.Error(\"error: \", v)\n\t}\n}\n\ntype e struct{}\n\nfunc TestErrorMessage(t *testing.T) {\n\tdata := []struct {\n\t\terr error\n\t\tmsg string\n\t}{\n\t\t{\n\t\t\terr: New(\"a\").Base(New(\"b\")).WithPathObj(e{}),\n\t\t\tmsg: \"v2ray.com/core/common/errors_test: a > b\",\n\t\t},\n\t\t{\n\t\t\terr: New(\"a\").Base(New(\"b\").WithPathObj(e{})),\n\t\t\tmsg: \"a > v2ray.com/core/common/errors_test: b\",\n\t\t},\n\t}\n\n\tfor _, d := range data {\n\t\tif diff := cmp.Diff(d.msg, d.err.Error()); diff != \"\" {\n\t\t\tt.Error(diff)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "common/errors/multi_error.go",
    "content": "package errors\n\nimport (\n\t\"strings\"\n)\n\ntype multiError []error\n\nfunc (e multiError) Error() string {\n\tvar r strings.Builder\n\tr.WriteString(\"multierr: \")\n\tfor _, err := range e {\n\t\tr.WriteString(err.Error())\n\t\tr.WriteString(\" | \")\n\t}\n\treturn r.String()\n}\n\nfunc Combine(maybeError ...error) error {\n\tvar errs multiError\n\tfor _, err := range maybeError {\n\t\tif err != nil {\n\t\t\terrs = append(errs, err)\n\t\t}\n\t}\n\tif len(errs) == 0 {\n\t\treturn nil\n\t}\n\treturn errs\n}\n"
  },
  {
    "path": "common/errors.generated.go",
    "content": "package common\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "common/interfaces.go",
    "content": "package common\n\nimport \"v2ray.com/core/common/errors\"\n\n// Closable is the interface for objects that can release its resources.\n//\n// v2ray:api:beta\ntype Closable interface {\n\t// Close release all resources used by this object, including goroutines.\n\tClose() error\n}\n\n// Interruptible is an interface for objects that can be stopped before its completion.\n//\n// v2ray:api:beta\ntype Interruptible interface {\n\tInterrupt()\n}\n\n// Close closes the obj if it is a Closable.\n//\n// v2ray:api:beta\nfunc Close(obj interface{}) error {\n\tif c, ok := obj.(Closable); ok {\n\t\treturn c.Close()\n\t}\n\treturn nil\n}\n\n// Interrupt calls Interrupt() if object implements Interruptible interface, or Close() if the object implements Closable interface.\n//\n// v2ray:api:beta\nfunc Interrupt(obj interface{}) error {\n\tif c, ok := obj.(Interruptible); ok {\n\t\tc.Interrupt()\n\t\treturn nil\n\t}\n\treturn Close(obj)\n}\n\n// Runnable is the interface for objects that can start to work and stop on demand.\ntype Runnable interface {\n\t// Start starts the runnable object. Upon the method returning nil, the object begins to function properly.\n\tStart() error\n\n\tClosable\n}\n\n// HasType is the interface for objects that knows its type.\ntype HasType interface {\n\t// Type returns the type of the object.\n\t// Usually it returns (*Type)(nil) of the object.\n\tType() interface{}\n}\n\n// ChainedClosable is a Closable that consists of multiple Closable objects.\ntype ChainedClosable []Closable\n\n// Close implements Closable.\nfunc (cc ChainedClosable) Close() error {\n\tvar errs []error\n\tfor _, c := range cc {\n\t\tif err := c.Close(); err != nil {\n\t\t\terrs = append(errs, err)\n\t\t}\n\t}\n\treturn errors.Combine(errs...)\n}\n"
  },
  {
    "path": "common/log/access.go",
    "content": "package log\n\nimport (\n\t\"context\"\n\t\"strings\"\n\n\t\"v2ray.com/core/common/serial\"\n)\n\ntype logKey int\n\nconst (\n\taccessMessageKey logKey = iota\n)\n\ntype AccessStatus string\n\nconst (\n\tAccessAccepted = AccessStatus(\"accepted\")\n\tAccessRejected = AccessStatus(\"rejected\")\n)\n\ntype AccessMessage struct {\n\tFrom   interface{}\n\tTo     interface{}\n\tStatus AccessStatus\n\tReason interface{}\n\tEmail  string\n\tDetour string\n}\n\nfunc (m *AccessMessage) String() string {\n\tbuilder := strings.Builder{}\n\tbuilder.WriteString(serial.ToString(m.From))\n\tbuilder.WriteByte(' ')\n\tbuilder.WriteString(string(m.Status))\n\tbuilder.WriteByte(' ')\n\tbuilder.WriteString(serial.ToString(m.To))\n\tbuilder.WriteByte(' ')\n\tif len(m.Detour) > 0 {\n\t\tbuilder.WriteByte('[')\n\t\tbuilder.WriteString(m.Detour)\n\t\tbuilder.WriteString(\"] \")\n\t}\n\tbuilder.WriteString(serial.ToString(m.Reason))\n\n\tif len(m.Email) > 0 {\n\t\tbuilder.WriteString(\"email:\")\n\t\tbuilder.WriteString(m.Email)\n\t\tbuilder.WriteByte(' ')\n\t}\n\treturn builder.String()\n}\n\nfunc ContextWithAccessMessage(ctx context.Context, accessMessage *AccessMessage) context.Context {\n\treturn context.WithValue(ctx, accessMessageKey, accessMessage)\n}\n\nfunc AccessMessageFromContext(ctx context.Context) *AccessMessage {\n\tif accessMessage, ok := ctx.Value(accessMessageKey).(*AccessMessage); ok {\n\t\treturn accessMessage\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "common/log/log.go",
    "content": "package log // import \"v2ray.com/core/common/log\"\n\nimport (\n\t\"sync\"\n\n\t\"v2ray.com/core/common/serial\"\n)\n\n// Message is the interface for all log messages.\ntype Message interface {\n\tString() string\n}\n\n// Handler is the interface for log handler.\ntype Handler interface {\n\tHandle(msg Message)\n}\n\n// GeneralMessage is a general log message that can contain all kind of content.\ntype GeneralMessage struct {\n\tSeverity Severity\n\tContent  interface{}\n}\n\n// String implements Message.\nfunc (m *GeneralMessage) String() string {\n\treturn serial.Concat(\"[\", m.Severity, \"] \", m.Content)\n}\n\n// Record writes a message into log stream.\nfunc Record(msg Message) {\n\tlogHandler.Handle(msg)\n}\n\nvar (\n\tlogHandler syncHandler\n)\n\n// RegisterHandler register a new handler as current log handler. Previous registered handler will be discarded.\nfunc RegisterHandler(handler Handler) {\n\tif handler == nil {\n\t\tpanic(\"Log handler is nil\")\n\t}\n\tlogHandler.Set(handler)\n}\n\ntype syncHandler struct {\n\tsync.RWMutex\n\tHandler\n}\n\nfunc (h *syncHandler) Handle(msg Message) {\n\th.RLock()\n\tdefer h.RUnlock()\n\n\tif h.Handler != nil {\n\t\th.Handler.Handle(msg)\n\t}\n}\n\nfunc (h *syncHandler) Set(handler Handler) {\n\th.Lock()\n\tdefer h.Unlock()\n\n\th.Handler = handler\n}\n"
  },
  {
    "path": "common/log/log.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: common/log/log.proto\n\npackage log\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype Severity int32\n\nconst (\n\tSeverity_Unknown Severity = 0\n\tSeverity_Error   Severity = 1\n\tSeverity_Warning Severity = 2\n\tSeverity_Info    Severity = 3\n\tSeverity_Debug   Severity = 4\n)\n\n// Enum value maps for Severity.\nvar (\n\tSeverity_name = map[int32]string{\n\t\t0: \"Unknown\",\n\t\t1: \"Error\",\n\t\t2: \"Warning\",\n\t\t3: \"Info\",\n\t\t4: \"Debug\",\n\t}\n\tSeverity_value = map[string]int32{\n\t\t\"Unknown\": 0,\n\t\t\"Error\":   1,\n\t\t\"Warning\": 2,\n\t\t\"Info\":    3,\n\t\t\"Debug\":   4,\n\t}\n)\n\nfunc (x Severity) Enum() *Severity {\n\tp := new(Severity)\n\t*p = x\n\treturn p\n}\n\nfunc (x Severity) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (Severity) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_common_log_log_proto_enumTypes[0].Descriptor()\n}\n\nfunc (Severity) Type() protoreflect.EnumType {\n\treturn &file_common_log_log_proto_enumTypes[0]\n}\n\nfunc (x Severity) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use Severity.Descriptor instead.\nfunc (Severity) EnumDescriptor() ([]byte, []int) {\n\treturn file_common_log_log_proto_rawDescGZIP(), []int{0}\n}\n\nvar File_common_log_log_proto protoreflect.FileDescriptor\n\nvar file_common_log_log_proto_rawDesc = []byte{\n\t0x0a, 0x14, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6c, 0x6f, 0x67, 0x2f, 0x6c, 0x6f, 0x67,\n\t0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x15, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,\n\t0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6c, 0x6f, 0x67, 0x2a, 0x44, 0x0a,\n\t0x08, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x6e, 0x6b,\n\t0x6e, 0x6f, 0x77, 0x6e, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x10,\n\t0x01, 0x12, 0x0b, 0x0a, 0x07, 0x57, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x10, 0x02, 0x12, 0x08,\n\t0x0a, 0x04, 0x49, 0x6e, 0x66, 0x6f, 0x10, 0x03, 0x12, 0x09, 0x0a, 0x05, 0x44, 0x65, 0x62, 0x75,\n\t0x67, 0x10, 0x04, 0x42, 0x50, 0x0a, 0x19, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,\n\t0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6c, 0x6f, 0x67,\n\t0x50, 0x01, 0x5a, 0x19, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f,\n\t0x72, 0x65, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6c, 0x6f, 0x67, 0xaa, 0x02, 0x15,\n\t0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f,\n\t0x6e, 0x2e, 0x4c, 0x6f, 0x67, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_common_log_log_proto_rawDescOnce sync.Once\n\tfile_common_log_log_proto_rawDescData = file_common_log_log_proto_rawDesc\n)\n\nfunc file_common_log_log_proto_rawDescGZIP() []byte {\n\tfile_common_log_log_proto_rawDescOnce.Do(func() {\n\t\tfile_common_log_log_proto_rawDescData = protoimpl.X.CompressGZIP(file_common_log_log_proto_rawDescData)\n\t})\n\treturn file_common_log_log_proto_rawDescData\n}\n\nvar file_common_log_log_proto_enumTypes = make([]protoimpl.EnumInfo, 1)\nvar file_common_log_log_proto_goTypes = []interface{}{\n\t(Severity)(0), // 0: v2ray.core.common.log.Severity\n}\nvar file_common_log_log_proto_depIdxs = []int32{\n\t0, // [0:0] is the sub-list for method output_type\n\t0, // [0:0] is the sub-list for method input_type\n\t0, // [0:0] is the sub-list for extension type_name\n\t0, // [0:0] is the sub-list for extension extendee\n\t0, // [0:0] is the sub-list for field type_name\n}\n\nfunc init() { file_common_log_log_proto_init() }\nfunc file_common_log_log_proto_init() {\n\tif File_common_log_log_proto != nil {\n\t\treturn\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_common_log_log_proto_rawDesc,\n\t\t\tNumEnums:      1,\n\t\t\tNumMessages:   0,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_common_log_log_proto_goTypes,\n\t\tDependencyIndexes: file_common_log_log_proto_depIdxs,\n\t\tEnumInfos:         file_common_log_log_proto_enumTypes,\n\t}.Build()\n\tFile_common_log_log_proto = out.File\n\tfile_common_log_log_proto_rawDesc = nil\n\tfile_common_log_log_proto_goTypes = nil\n\tfile_common_log_log_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "common/log/log.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.common.log;\noption csharp_namespace = \"V2Ray.Core.Common.Log\";\noption go_package = \"v2ray.com/core/common/log\";\noption java_package = \"com.v2ray.core.common.log\";\noption java_multiple_files = true;\n\nenum Severity {\n  Unknown = 0;\n  Error = 1;\n  Warning = 2;\n  Info = 3;\n  Debug = 4;\n}\n"
  },
  {
    "path": "common/log/log_test.go",
    "content": "package log_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\n\t\"v2ray.com/core/common/log\"\n\t\"v2ray.com/core/common/net\"\n)\n\ntype testLogger struct {\n\tvalue string\n}\n\nfunc (l *testLogger) Handle(msg log.Message) {\n\tl.value = msg.String()\n}\n\nfunc TestLogRecord(t *testing.T) {\n\tvar logger testLogger\n\tlog.RegisterHandler(&logger)\n\n\tip := \"8.8.8.8\"\n\tlog.Record(&log.GeneralMessage{\n\t\tSeverity: log.Severity_Error,\n\t\tContent:  net.ParseAddress(ip),\n\t})\n\n\tif diff := cmp.Diff(\"[Error] \"+ip, logger.value); diff != \"\" {\n\t\tt.Error(diff)\n\t}\n}\n"
  },
  {
    "path": "common/log/logger.go",
    "content": "package log\n\nimport (\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"time\"\n\n\t\"v2ray.com/core/common/platform\"\n\t\"v2ray.com/core/common/signal/done\"\n\t\"v2ray.com/core/common/signal/semaphore\"\n)\n\n// Writer is the interface for writing logs.\ntype Writer interface {\n\tWrite(string) error\n\tio.Closer\n}\n\n// WriterCreator is a function to create LogWriters.\ntype WriterCreator func() Writer\n\ntype generalLogger struct {\n\tcreator WriterCreator\n\tbuffer  chan Message\n\taccess  *semaphore.Instance\n\tdone    *done.Instance\n}\n\n// NewLogger returns a generic log handler that can handle all type of messages.\nfunc NewLogger(logWriterCreator WriterCreator) Handler {\n\treturn &generalLogger{\n\t\tcreator: logWriterCreator,\n\t\tbuffer:  make(chan Message, 16),\n\t\taccess:  semaphore.New(1),\n\t\tdone:    done.New(),\n\t}\n}\n\nfunc (l *generalLogger) run() {\n\tdefer l.access.Signal()\n\n\tdataWritten := false\n\tticker := time.NewTicker(time.Minute)\n\tdefer ticker.Stop()\n\n\tlogger := l.creator()\n\tif logger == nil {\n\t\treturn\n\t}\n\tdefer logger.Close() // nolint: errcheck\n\n\tfor {\n\t\tselect {\n\t\tcase <-l.done.Wait():\n\t\t\treturn\n\t\tcase msg := <-l.buffer:\n\t\t\tlogger.Write(msg.String() + platform.LineSeparator()) // nolint: errcheck\n\t\t\tdataWritten = true\n\t\tcase <-ticker.C:\n\t\t\tif !dataWritten {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tdataWritten = false\n\t\t}\n\t}\n}\n\nfunc (l *generalLogger) Handle(msg Message) {\n\tselect {\n\tcase l.buffer <- msg:\n\tdefault:\n\t}\n\n\tselect {\n\tcase <-l.access.Wait():\n\t\tgo l.run()\n\tdefault:\n\t}\n}\n\nfunc (l *generalLogger) Close() error {\n\treturn l.done.Close()\n}\n\ntype consoleLogWriter struct {\n\tlogger *log.Logger\n}\n\nfunc (w *consoleLogWriter) Write(s string) error {\n\tw.logger.Print(s)\n\treturn nil\n}\n\nfunc (w *consoleLogWriter) Close() error {\n\treturn nil\n}\n\ntype fileLogWriter struct {\n\tfile   *os.File\n\tlogger *log.Logger\n}\n\nfunc (w *fileLogWriter) Write(s string) error {\n\tw.logger.Print(s)\n\treturn nil\n}\n\nfunc (w *fileLogWriter) Close() error {\n\treturn w.file.Close()\n}\n\n// CreateStdoutLogWriter returns a LogWriterCreator that creates LogWriter for stdout.\nfunc CreateStdoutLogWriter() WriterCreator {\n\treturn func() Writer {\n\t\treturn &consoleLogWriter{\n\t\t\tlogger: log.New(os.Stdout, \"\", log.Ldate|log.Ltime),\n\t\t}\n\t}\n}\n\n// CreateStderrLogWriter returns a LogWriterCreator that creates LogWriter for stderr.\nfunc CreateStderrLogWriter() WriterCreator {\n\treturn func() Writer {\n\t\treturn &consoleLogWriter{\n\t\t\tlogger: log.New(os.Stderr, \"\", log.Ldate|log.Ltime),\n\t\t}\n\t}\n}\n\n// CreateFileLogWriter returns a LogWriterCreator that creates LogWriter for the given file.\nfunc CreateFileLogWriter(path string) (WriterCreator, error) {\n\tfile, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfile.Close()\n\treturn func() Writer {\n\t\tfile, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)\n\t\tif err != nil {\n\t\t\treturn nil\n\t\t}\n\t\treturn &fileLogWriter{\n\t\t\tfile:   file,\n\t\t\tlogger: log.New(file, \"\", log.Ldate|log.Ltime),\n\t\t}\n\t}, nil\n}\n\nfunc init() {\n\tRegisterHandler(NewLogger(CreateStdoutLogWriter()))\n}\n"
  },
  {
    "path": "common/log/logger_test.go",
    "content": "package log_test\n\nimport (\n\t\"io/ioutil\"\n\t\"os\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t. \"v2ray.com/core/common/log\"\n)\n\nfunc TestFileLogger(t *testing.T) {\n\tf, err := ioutil.TempFile(\"\", \"vtest\")\n\tcommon.Must(err)\n\tpath := f.Name()\n\tcommon.Must(f.Close())\n\n\tcreator, err := CreateFileLogWriter(path)\n\tcommon.Must(err)\n\n\thandler := NewLogger(creator)\n\thandler.Handle(&GeneralMessage{Content: \"Test Log\"})\n\ttime.Sleep(2 * time.Second)\n\n\tcommon.Must(common.Close(handler))\n\n\tf, err = os.Open(path)\n\tcommon.Must(err)\n\tdefer f.Close() // nolint: errcheck\n\n\tb, err := buf.ReadAllToBytes(f)\n\tcommon.Must(err)\n\tif !strings.Contains(string(b), \"Test Log\") {\n\t\tt.Fatal(\"Expect log text contains 'Test Log', but actually: \", string(b))\n\t}\n}\n"
  },
  {
    "path": "common/mux/client.go",
    "content": "package mux\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"sync\"\n\t\"time\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/errors\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/session\"\n\t\"v2ray.com/core/common/signal/done\"\n\t\"v2ray.com/core/common/task\"\n\t\"v2ray.com/core/proxy\"\n\t\"v2ray.com/core/transport\"\n\t\"v2ray.com/core/transport/internet\"\n\t\"v2ray.com/core/transport/pipe\"\n)\n\ntype ClientManager struct {\n\tEnabled bool // wheather mux is enabled from user config\n\tPicker  WorkerPicker\n}\n\nfunc (m *ClientManager) Dispatch(ctx context.Context, link *transport.Link) error {\n\tfor i := 0; i < 16; i++ {\n\t\tworker, err := m.Picker.PickAvailable()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif worker.Dispatch(ctx, link) {\n\t\t\treturn nil\n\t\t}\n\t}\n\n\treturn newError(\"unable to find an available mux client\").AtWarning()\n}\n\ntype WorkerPicker interface {\n\tPickAvailable() (*ClientWorker, error)\n}\n\ntype IncrementalWorkerPicker struct {\n\tFactory ClientWorkerFactory\n\n\taccess      sync.Mutex\n\tworkers     []*ClientWorker\n\tcleanupTask *task.Periodic\n}\n\nfunc (p *IncrementalWorkerPicker) cleanupFunc() error {\n\tp.access.Lock()\n\tdefer p.access.Unlock()\n\n\tif len(p.workers) == 0 {\n\t\treturn newError(\"no worker\")\n\t}\n\n\tp.cleanup()\n\treturn nil\n}\n\nfunc (p *IncrementalWorkerPicker) cleanup() {\n\tvar activeWorkers []*ClientWorker\n\tfor _, w := range p.workers {\n\t\tif !w.Closed() {\n\t\t\tactiveWorkers = append(activeWorkers, w)\n\t\t}\n\t}\n\tp.workers = activeWorkers\n}\n\nfunc (p *IncrementalWorkerPicker) findAvailable() int {\n\tfor idx, w := range p.workers {\n\t\tif !w.IsFull() {\n\t\t\treturn idx\n\t\t}\n\t}\n\n\treturn -1\n}\n\nfunc (p *IncrementalWorkerPicker) pickInternal() (*ClientWorker, bool, error) {\n\tp.access.Lock()\n\tdefer p.access.Unlock()\n\n\tidx := p.findAvailable()\n\tif idx >= 0 {\n\t\tn := len(p.workers)\n\t\tif n > 1 && idx != n-1 {\n\t\t\tp.workers[n-1], p.workers[idx] = p.workers[idx], p.workers[n-1]\n\t\t}\n\t\treturn p.workers[idx], false, nil\n\t}\n\n\tp.cleanup()\n\n\tworker, err := p.Factory.Create()\n\tif err != nil {\n\t\treturn nil, false, err\n\t}\n\tp.workers = append(p.workers, worker)\n\n\tif p.cleanupTask == nil {\n\t\tp.cleanupTask = &task.Periodic{\n\t\t\tInterval: time.Second * 30,\n\t\t\tExecute:  p.cleanupFunc,\n\t\t}\n\t}\n\n\treturn worker, true, nil\n}\n\nfunc (p *IncrementalWorkerPicker) PickAvailable() (*ClientWorker, error) {\n\tworker, start, err := p.pickInternal()\n\tif start {\n\t\tcommon.Must(p.cleanupTask.Start())\n\t}\n\n\treturn worker, err\n}\n\ntype ClientWorkerFactory interface {\n\tCreate() (*ClientWorker, error)\n}\n\ntype DialingWorkerFactory struct {\n\tProxy    proxy.Outbound\n\tDialer   internet.Dialer\n\tStrategy ClientStrategy\n}\n\nfunc (f *DialingWorkerFactory) Create() (*ClientWorker, error) {\n\topts := []pipe.Option{pipe.WithSizeLimit(64 * 1024)}\n\tuplinkReader, upLinkWriter := pipe.New(opts...)\n\tdownlinkReader, downlinkWriter := pipe.New(opts...)\n\n\tc, err := NewClientWorker(transport.Link{\n\t\tReader: downlinkReader,\n\t\tWriter: upLinkWriter,\n\t}, f.Strategy)\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tgo func(p proxy.Outbound, d internet.Dialer, c common.Closable) {\n\t\tctx := session.ContextWithOutbound(context.Background(), &session.Outbound{\n\t\t\tTarget: net.TCPDestination(muxCoolAddress, muxCoolPort),\n\t\t})\n\t\tctx, cancel := context.WithCancel(ctx)\n\n\t\tif err := p.Process(ctx, &transport.Link{Reader: uplinkReader, Writer: downlinkWriter}, d); err != nil {\n\t\t\terrors.New(\"failed to handler mux client connection\").Base(err).WriteToLog()\n\t\t}\n\t\tcommon.Must(c.Close())\n\t\tcancel()\n\t}(f.Proxy, f.Dialer, c.done)\n\n\treturn c, nil\n}\n\ntype ClientStrategy struct {\n\tMaxConcurrency uint32\n\tMaxConnection  uint32\n}\n\ntype ClientWorker struct {\n\tsessionManager *SessionManager\n\tlink           transport.Link\n\tdone           *done.Instance\n\tstrategy       ClientStrategy\n}\n\nvar muxCoolAddress = net.DomainAddress(\"v1.mux.cool\")\nvar muxCoolPort = net.Port(9527)\n\n// NewClientWorker creates a new mux.Client.\nfunc NewClientWorker(stream transport.Link, s ClientStrategy) (*ClientWorker, error) {\n\tc := &ClientWorker{\n\t\tsessionManager: NewSessionManager(),\n\t\tlink:           stream,\n\t\tdone:           done.New(),\n\t\tstrategy:       s,\n\t}\n\n\tgo c.fetchOutput()\n\tgo c.monitor()\n\n\treturn c, nil\n}\n\nfunc (m *ClientWorker) TotalConnections() uint32 {\n\treturn uint32(m.sessionManager.Count())\n}\n\nfunc (m *ClientWorker) ActiveConnections() uint32 {\n\treturn uint32(m.sessionManager.Size())\n}\n\n// Closed returns true if this Client is closed.\nfunc (m *ClientWorker) Closed() bool {\n\treturn m.done.Done()\n}\n\nfunc (m *ClientWorker) monitor() {\n\ttimer := time.NewTicker(time.Second * 16)\n\tdefer timer.Stop()\n\n\tfor {\n\t\tselect {\n\t\tcase <-m.done.Wait():\n\t\t\tm.sessionManager.Close()\n\t\t\tcommon.Close(m.link.Writer)     // nolint: errcheck\n\t\t\tcommon.Interrupt(m.link.Reader) // nolint: errcheck\n\t\t\treturn\n\t\tcase <-timer.C:\n\t\t\tsize := m.sessionManager.Size()\n\t\t\tif size == 0 && m.sessionManager.CloseIfNoSession() {\n\t\t\t\tcommon.Must(m.done.Close())\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc writeFirstPayload(reader buf.Reader, writer *Writer) error {\n\terr := buf.CopyOnceTimeout(reader, writer, time.Millisecond*100)\n\tif err == buf.ErrNotTimeoutReader || err == buf.ErrReadTimeout {\n\t\treturn writer.WriteMultiBuffer(buf.MultiBuffer{})\n\t}\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc fetchInput(ctx context.Context, s *Session, output buf.Writer) {\n\tdest := session.OutboundFromContext(ctx).Target\n\ttransferType := protocol.TransferTypeStream\n\tif dest.Network == net.Network_UDP {\n\t\ttransferType = protocol.TransferTypePacket\n\t}\n\ts.transferType = transferType\n\twriter := NewWriter(s.ID, dest, output, transferType)\n\tdefer s.Close()      // nolint: errcheck\n\tdefer writer.Close() // nolint: errcheck\n\n\tnewError(\"dispatching request to \", dest).WriteToLog(session.ExportIDToError(ctx))\n\tif err := writeFirstPayload(s.input, writer); err != nil {\n\t\tnewError(\"failed to write first payload\").Base(err).WriteToLog(session.ExportIDToError(ctx))\n\t\twriter.hasError = true\n\t\tcommon.Interrupt(s.input)\n\t\treturn\n\t}\n\n\tif err := buf.Copy(s.input, writer); err != nil {\n\t\tnewError(\"failed to fetch all input\").Base(err).WriteToLog(session.ExportIDToError(ctx))\n\t\twriter.hasError = true\n\t\tcommon.Interrupt(s.input)\n\t\treturn\n\t}\n}\n\nfunc (m *ClientWorker) IsClosing() bool {\n\tsm := m.sessionManager\n\tif m.strategy.MaxConnection > 0 && sm.Count() >= int(m.strategy.MaxConnection) {\n\t\treturn true\n\t}\n\treturn false\n}\n\nfunc (m *ClientWorker) IsFull() bool {\n\tif m.IsClosing() || m.Closed() {\n\t\treturn true\n\t}\n\n\tsm := m.sessionManager\n\tif m.strategy.MaxConcurrency > 0 && sm.Size() >= int(m.strategy.MaxConcurrency) {\n\t\treturn true\n\t}\n\treturn false\n}\n\nfunc (m *ClientWorker) Dispatch(ctx context.Context, link *transport.Link) bool {\n\tif m.IsFull() || m.Closed() {\n\t\treturn false\n\t}\n\n\tsm := m.sessionManager\n\ts := sm.Allocate()\n\tif s == nil {\n\t\treturn false\n\t}\n\ts.input = link.Reader\n\ts.output = link.Writer\n\tgo fetchInput(ctx, s, m.link.Writer)\n\treturn true\n}\n\nfunc (m *ClientWorker) handleStatueKeepAlive(meta *FrameMetadata, reader *buf.BufferedReader) error {\n\tif meta.Option.Has(OptionData) {\n\t\treturn buf.Copy(NewStreamReader(reader), buf.Discard)\n\t}\n\treturn nil\n}\n\nfunc (m *ClientWorker) handleStatusNew(meta *FrameMetadata, reader *buf.BufferedReader) error {\n\tif meta.Option.Has(OptionData) {\n\t\treturn buf.Copy(NewStreamReader(reader), buf.Discard)\n\t}\n\treturn nil\n}\n\nfunc (m *ClientWorker) handleStatusKeep(meta *FrameMetadata, reader *buf.BufferedReader) error {\n\tif !meta.Option.Has(OptionData) {\n\t\treturn nil\n\t}\n\n\ts, found := m.sessionManager.Get(meta.SessionID)\n\tif !found {\n\t\t// Notify remote peer to close this session.\n\t\tclosingWriter := NewResponseWriter(meta.SessionID, m.link.Writer, protocol.TransferTypeStream)\n\t\tclosingWriter.Close()\n\n\t\treturn buf.Copy(NewStreamReader(reader), buf.Discard)\n\t}\n\n\trr := s.NewReader(reader)\n\terr := buf.Copy(rr, s.output)\n\tif err != nil && buf.IsWriteError(err) {\n\t\tnewError(\"failed to write to downstream. closing session \", s.ID).Base(err).WriteToLog()\n\n\t\t// Notify remote peer to close this session.\n\t\tclosingWriter := NewResponseWriter(meta.SessionID, m.link.Writer, protocol.TransferTypeStream)\n\t\tclosingWriter.Close()\n\n\t\tdrainErr := buf.Copy(rr, buf.Discard)\n\t\tcommon.Interrupt(s.input)\n\t\ts.Close()\n\t\treturn drainErr\n\t}\n\n\treturn err\n}\n\nfunc (m *ClientWorker) handleStatusEnd(meta *FrameMetadata, reader *buf.BufferedReader) error {\n\tif s, found := m.sessionManager.Get(meta.SessionID); found {\n\t\tif meta.Option.Has(OptionError) {\n\t\t\tcommon.Interrupt(s.input)\n\t\t\tcommon.Interrupt(s.output)\n\t\t}\n\t\ts.Close()\n\t}\n\tif meta.Option.Has(OptionData) {\n\t\treturn buf.Copy(NewStreamReader(reader), buf.Discard)\n\t}\n\treturn nil\n}\n\nfunc (m *ClientWorker) fetchOutput() {\n\tdefer func() {\n\t\tcommon.Must(m.done.Close())\n\t}()\n\n\treader := &buf.BufferedReader{Reader: m.link.Reader}\n\n\tvar meta FrameMetadata\n\tfor {\n\t\terr := meta.Unmarshal(reader)\n\t\tif err != nil {\n\t\t\tif errors.Cause(err) != io.EOF {\n\t\t\t\tnewError(\"failed to read metadata\").Base(err).WriteToLog()\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\n\t\tswitch meta.SessionStatus {\n\t\tcase SessionStatusKeepAlive:\n\t\t\terr = m.handleStatueKeepAlive(&meta, reader)\n\t\tcase SessionStatusEnd:\n\t\t\terr = m.handleStatusEnd(&meta, reader)\n\t\tcase SessionStatusNew:\n\t\t\terr = m.handleStatusNew(&meta, reader)\n\t\tcase SessionStatusKeep:\n\t\t\terr = m.handleStatusKeep(&meta, reader)\n\t\tdefault:\n\t\t\tstatus := meta.SessionStatus\n\t\t\tnewError(\"unknown status: \", status).AtError().WriteToLog()\n\t\t\treturn\n\t\t}\n\n\t\tif err != nil {\n\t\t\tnewError(\"failed to process data\").Base(err).WriteToLog()\n\t\t\treturn\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "common/mux/client_test.go",
    "content": "package mux_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/golang/mock/gomock\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/errors\"\n\t\"v2ray.com/core/common/mux\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/session\"\n\t\"v2ray.com/core/testing/mocks\"\n\t\"v2ray.com/core/transport\"\n\t\"v2ray.com/core/transport/pipe\"\n)\n\nfunc TestIncrementalPickerFailure(t *testing.T) {\n\tmockCtl := gomock.NewController(t)\n\tdefer mockCtl.Finish()\n\n\tmockWorkerFactory := mocks.NewMuxClientWorkerFactory(mockCtl)\n\tmockWorkerFactory.EXPECT().Create().Return(nil, errors.New(\"test\"))\n\n\tpicker := mux.IncrementalWorkerPicker{\n\t\tFactory: mockWorkerFactory,\n\t}\n\n\t_, err := picker.PickAvailable()\n\tif err == nil {\n\t\tt.Error(\"expected error, but nil\")\n\t}\n}\n\nfunc TestClientWorkerEOF(t *testing.T) {\n\treader, writer := pipe.New(pipe.WithoutSizeLimit())\n\tcommon.Must(writer.Close())\n\n\tworker, err := mux.NewClientWorker(transport.Link{Reader: reader, Writer: writer}, mux.ClientStrategy{})\n\tcommon.Must(err)\n\n\ttime.Sleep(time.Millisecond * 500)\n\n\tf := worker.Dispatch(context.Background(), nil)\n\tif f {\n\t\tt.Error(\"expected failed dispatching, but actually not\")\n\t}\n}\n\nfunc TestClientWorkerClose(t *testing.T) {\n\tmockCtl := gomock.NewController(t)\n\tdefer mockCtl.Finish()\n\n\tr1, w1 := pipe.New(pipe.WithoutSizeLimit())\n\tworker1, err := mux.NewClientWorker(transport.Link{\n\t\tReader: r1,\n\t\tWriter: w1,\n\t}, mux.ClientStrategy{\n\t\tMaxConcurrency: 4,\n\t\tMaxConnection:  4,\n\t})\n\tcommon.Must(err)\n\n\tr2, w2 := pipe.New(pipe.WithoutSizeLimit())\n\tworker2, err := mux.NewClientWorker(transport.Link{\n\t\tReader: r2,\n\t\tWriter: w2,\n\t}, mux.ClientStrategy{\n\t\tMaxConcurrency: 4,\n\t\tMaxConnection:  4,\n\t})\n\tcommon.Must(err)\n\n\tfactory := mocks.NewMuxClientWorkerFactory(mockCtl)\n\tgomock.InOrder(\n\t\tfactory.EXPECT().Create().Return(worker1, nil),\n\t\tfactory.EXPECT().Create().Return(worker2, nil),\n\t)\n\n\tpicker := &mux.IncrementalWorkerPicker{\n\t\tFactory: factory,\n\t}\n\tmanager := &mux.ClientManager{\n\t\tPicker: picker,\n\t}\n\n\ttr1, tw1 := pipe.New(pipe.WithoutSizeLimit())\n\tctx1 := session.ContextWithOutbound(context.Background(), &session.Outbound{\n\t\tTarget: net.TCPDestination(net.DomainAddress(\"www.v2ray.com\"), 80),\n\t})\n\tcommon.Must(manager.Dispatch(ctx1, &transport.Link{\n\t\tReader: tr1,\n\t\tWriter: tw1,\n\t}))\n\tdefer tw1.Close()\n\n\tcommon.Must(w1.Close())\n\n\ttime.Sleep(time.Millisecond * 500)\n\tif !worker1.Closed() {\n\t\tt.Error(\"worker1 is not finished\")\n\t}\n\n\ttr2, tw2 := pipe.New(pipe.WithoutSizeLimit())\n\tctx2 := session.ContextWithOutbound(context.Background(), &session.Outbound{\n\t\tTarget: net.TCPDestination(net.DomainAddress(\"www.v2ray.com\"), 80),\n\t})\n\tcommon.Must(manager.Dispatch(ctx2, &transport.Link{\n\t\tReader: tr2,\n\t\tWriter: tw2,\n\t}))\n\tdefer tw2.Close()\n\n\tcommon.Must(w2.Close())\n}\n"
  },
  {
    "path": "common/mux/errors.generated.go",
    "content": "package mux\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "common/mux/frame.go",
    "content": "package mux\n\nimport (\n\t\"encoding/binary\"\n\t\"io\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/bitmask\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/serial\"\n)\n\ntype SessionStatus byte\n\nconst (\n\tSessionStatusNew       SessionStatus = 0x01\n\tSessionStatusKeep      SessionStatus = 0x02\n\tSessionStatusEnd       SessionStatus = 0x03\n\tSessionStatusKeepAlive SessionStatus = 0x04\n)\n\nconst (\n\tOptionData  bitmask.Byte = 0x01\n\tOptionError bitmask.Byte = 0x02\n)\n\ntype TargetNetwork byte\n\nconst (\n\tTargetNetworkTCP TargetNetwork = 0x01\n\tTargetNetworkUDP TargetNetwork = 0x02\n)\n\nvar addrParser = protocol.NewAddressParser(\n\tprotocol.AddressFamilyByte(byte(protocol.AddressTypeIPv4), net.AddressFamilyIPv4),\n\tprotocol.AddressFamilyByte(byte(protocol.AddressTypeDomain), net.AddressFamilyDomain),\n\tprotocol.AddressFamilyByte(byte(protocol.AddressTypeIPv6), net.AddressFamilyIPv6),\n\tprotocol.PortThenAddress(),\n)\n\n/*\nFrame format\n2 bytes - length\n2 bytes - session id\n1 bytes - status\n1 bytes - option\n\n1 byte - network\n2 bytes - port\nn bytes - address\n\n*/\n\ntype FrameMetadata struct {\n\tTarget        net.Destination\n\tSessionID     uint16\n\tOption        bitmask.Byte\n\tSessionStatus SessionStatus\n}\n\nfunc (f FrameMetadata) WriteTo(b *buf.Buffer) error {\n\tlenBytes := b.Extend(2)\n\n\tlen0 := b.Len()\n\tsessionBytes := b.Extend(2)\n\tbinary.BigEndian.PutUint16(sessionBytes, f.SessionID)\n\n\tcommon.Must(b.WriteByte(byte(f.SessionStatus)))\n\tcommon.Must(b.WriteByte(byte(f.Option)))\n\n\tif f.SessionStatus == SessionStatusNew {\n\t\tswitch f.Target.Network {\n\t\tcase net.Network_TCP:\n\t\t\tcommon.Must(b.WriteByte(byte(TargetNetworkTCP)))\n\t\tcase net.Network_UDP:\n\t\t\tcommon.Must(b.WriteByte(byte(TargetNetworkUDP)))\n\t\t}\n\n\t\tif err := addrParser.WriteAddressPort(b, f.Target.Address, f.Target.Port); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tlen1 := b.Len()\n\tbinary.BigEndian.PutUint16(lenBytes, uint16(len1-len0))\n\treturn nil\n}\n\n// Unmarshal reads FrameMetadata from the given reader.\nfunc (f *FrameMetadata) Unmarshal(reader io.Reader) error {\n\tmetaLen, err := serial.ReadUint16(reader)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif metaLen > 512 {\n\t\treturn newError(\"invalid metalen \", metaLen).AtError()\n\t}\n\n\tb := buf.New()\n\tdefer b.Release()\n\n\tif _, err := b.ReadFullFrom(reader, int32(metaLen)); err != nil {\n\t\treturn err\n\t}\n\treturn f.UnmarshalFromBuffer(b)\n}\n\n// UnmarshalFromBuffer reads a FrameMetadata from the given buffer.\n// Visible for testing only.\nfunc (f *FrameMetadata) UnmarshalFromBuffer(b *buf.Buffer) error {\n\tif b.Len() < 4 {\n\t\treturn newError(\"insufficient buffer: \", b.Len())\n\t}\n\n\tf.SessionID = binary.BigEndian.Uint16(b.BytesTo(2))\n\tf.SessionStatus = SessionStatus(b.Byte(2))\n\tf.Option = bitmask.Byte(b.Byte(3))\n\tf.Target.Network = net.Network_Unknown\n\n\tif f.SessionStatus == SessionStatusNew {\n\t\tif b.Len() < 8 {\n\t\t\treturn newError(\"insufficient buffer: \", b.Len())\n\t\t}\n\t\tnetwork := TargetNetwork(b.Byte(4))\n\t\tb.Advance(5)\n\n\t\taddr, port, err := addrParser.ReadAddressPort(nil, b)\n\t\tif err != nil {\n\t\t\treturn newError(\"failed to parse address and port\").Base(err)\n\t\t}\n\n\t\tswitch network {\n\t\tcase TargetNetworkTCP:\n\t\t\tf.Target = net.TCPDestination(addr, port)\n\t\tcase TargetNetworkUDP:\n\t\t\tf.Target = net.UDPDestination(addr, port)\n\t\tdefault:\n\t\t\treturn newError(\"unknown network type: \", network)\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "common/mux/frame_test.go",
    "content": "package mux_test\n\nimport (\n\t\"testing\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/mux\"\n\t\"v2ray.com/core/common/net\"\n)\n\nfunc BenchmarkFrameWrite(b *testing.B) {\n\tframe := mux.FrameMetadata{\n\t\tTarget:        net.TCPDestination(net.DomainAddress(\"www.v2ray.com\"), net.Port(80)),\n\t\tSessionID:     1,\n\t\tSessionStatus: mux.SessionStatusNew,\n\t}\n\twriter := buf.New()\n\tdefer writer.Release()\n\n\tfor i := 0; i < b.N; i++ {\n\t\tcommon.Must(frame.WriteTo(writer))\n\t\twriter.Clear()\n\t}\n}\n"
  },
  {
    "path": "common/mux/mux.go",
    "content": "package mux\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n"
  },
  {
    "path": "common/mux/mux_test.go",
    "content": "package mux_test\n\nimport (\n\t\"io\"\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t. \"v2ray.com/core/common/mux\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/transport/pipe\"\n)\n\nfunc readAll(reader buf.Reader) (buf.MultiBuffer, error) {\n\tvar mb buf.MultiBuffer\n\tfor {\n\t\tb, err := reader.ReadMultiBuffer()\n\t\tif err == io.EOF {\n\t\t\tbreak\n\t\t}\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tmb = append(mb, b...)\n\t}\n\treturn mb, nil\n}\n\nfunc TestReaderWriter(t *testing.T) {\n\tpReader, pWriter := pipe.New(pipe.WithSizeLimit(1024))\n\n\tdest := net.TCPDestination(net.DomainAddress(\"v2ray.com\"), 80)\n\twriter := NewWriter(1, dest, pWriter, protocol.TransferTypeStream)\n\n\tdest2 := net.TCPDestination(net.LocalHostIP, 443)\n\twriter2 := NewWriter(2, dest2, pWriter, protocol.TransferTypeStream)\n\n\tdest3 := net.TCPDestination(net.LocalHostIPv6, 18374)\n\twriter3 := NewWriter(3, dest3, pWriter, protocol.TransferTypeStream)\n\n\twritePayload := func(writer *Writer, payload ...byte) error {\n\t\tb := buf.New()\n\t\tb.Write(payload)\n\t\treturn writer.WriteMultiBuffer(buf.MultiBuffer{b})\n\t}\n\n\tcommon.Must(writePayload(writer, 'a', 'b', 'c', 'd'))\n\tcommon.Must(writePayload(writer2))\n\n\tcommon.Must(writePayload(writer, 'e', 'f', 'g', 'h'))\n\tcommon.Must(writePayload(writer3, 'x'))\n\n\twriter.Close()\n\twriter3.Close()\n\n\tcommon.Must(writePayload(writer2, 'y'))\n\twriter2.Close()\n\n\tbytesReader := &buf.BufferedReader{Reader: pReader}\n\n\t{\n\t\tvar meta FrameMetadata\n\t\tcommon.Must(meta.Unmarshal(bytesReader))\n\t\tif r := cmp.Diff(meta, FrameMetadata{\n\t\t\tSessionID:     1,\n\t\t\tSessionStatus: SessionStatusNew,\n\t\t\tTarget:        dest,\n\t\t\tOption:        OptionData,\n\t\t}); r != \"\" {\n\t\t\tt.Error(\"metadata: \", r)\n\t\t}\n\n\t\tdata, err := readAll(NewStreamReader(bytesReader))\n\t\tcommon.Must(err)\n\t\tif s := data.String(); s != \"abcd\" {\n\t\t\tt.Error(\"data: \", s)\n\t\t}\n\t}\n\n\t{\n\t\tvar meta FrameMetadata\n\t\tcommon.Must(meta.Unmarshal(bytesReader))\n\t\tif r := cmp.Diff(meta, FrameMetadata{\n\t\t\tSessionStatus: SessionStatusNew,\n\t\t\tSessionID:     2,\n\t\t\tOption:        0,\n\t\t\tTarget:        dest2,\n\t\t}); r != \"\" {\n\t\t\tt.Error(\"meta: \", r)\n\t\t}\n\t}\n\n\t{\n\t\tvar meta FrameMetadata\n\t\tcommon.Must(meta.Unmarshal(bytesReader))\n\t\tif r := cmp.Diff(meta, FrameMetadata{\n\t\t\tSessionID:     1,\n\t\t\tSessionStatus: SessionStatusKeep,\n\t\t\tOption:        1,\n\t\t}); r != \"\" {\n\t\t\tt.Error(\"meta: \", r)\n\t\t}\n\n\t\tdata, err := readAll(NewStreamReader(bytesReader))\n\t\tcommon.Must(err)\n\t\tif s := data.String(); s != \"efgh\" {\n\t\t\tt.Error(\"data: \", s)\n\t\t}\n\t}\n\n\t{\n\t\tvar meta FrameMetadata\n\t\tcommon.Must(meta.Unmarshal(bytesReader))\n\t\tif r := cmp.Diff(meta, FrameMetadata{\n\t\t\tSessionID:     3,\n\t\t\tSessionStatus: SessionStatusNew,\n\t\t\tOption:        1,\n\t\t\tTarget:        dest3,\n\t\t}); r != \"\" {\n\t\t\tt.Error(\"meta: \", r)\n\t\t}\n\n\t\tdata, err := readAll(NewStreamReader(bytesReader))\n\t\tcommon.Must(err)\n\t\tif s := data.String(); s != \"x\" {\n\t\t\tt.Error(\"data: \", s)\n\t\t}\n\t}\n\n\t{\n\t\tvar meta FrameMetadata\n\t\tcommon.Must(meta.Unmarshal(bytesReader))\n\t\tif r := cmp.Diff(meta, FrameMetadata{\n\t\t\tSessionID:     1,\n\t\t\tSessionStatus: SessionStatusEnd,\n\t\t\tOption:        0,\n\t\t}); r != \"\" {\n\t\t\tt.Error(\"meta: \", r)\n\t\t}\n\t}\n\n\t{\n\t\tvar meta FrameMetadata\n\t\tcommon.Must(meta.Unmarshal(bytesReader))\n\t\tif r := cmp.Diff(meta, FrameMetadata{\n\t\t\tSessionID:     3,\n\t\t\tSessionStatus: SessionStatusEnd,\n\t\t\tOption:        0,\n\t\t}); r != \"\" {\n\t\t\tt.Error(\"meta: \", r)\n\t\t}\n\t}\n\n\t{\n\t\tvar meta FrameMetadata\n\t\tcommon.Must(meta.Unmarshal(bytesReader))\n\t\tif r := cmp.Diff(meta, FrameMetadata{\n\t\t\tSessionID:     2,\n\t\t\tSessionStatus: SessionStatusKeep,\n\t\t\tOption:        1,\n\t\t}); r != \"\" {\n\t\t\tt.Error(\"meta: \", r)\n\t\t}\n\n\t\tdata, err := readAll(NewStreamReader(bytesReader))\n\t\tcommon.Must(err)\n\t\tif s := data.String(); s != \"y\" {\n\t\t\tt.Error(\"data: \", s)\n\t\t}\n\t}\n\n\t{\n\t\tvar meta FrameMetadata\n\t\tcommon.Must(meta.Unmarshal(bytesReader))\n\t\tif r := cmp.Diff(meta, FrameMetadata{\n\t\t\tSessionID:     2,\n\t\t\tSessionStatus: SessionStatusEnd,\n\t\t\tOption:        0,\n\t\t}); r != \"\" {\n\t\t\tt.Error(\"meta: \", r)\n\t\t}\n\t}\n\n\tpWriter.Close()\n\n\t{\n\t\tvar meta FrameMetadata\n\t\terr := meta.Unmarshal(bytesReader)\n\t\tif err == nil {\n\t\t\tt.Error(\"nil error\")\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "common/mux/reader.go",
    "content": "package mux\n\nimport (\n\t\"io\"\n\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/crypto\"\n\t\"v2ray.com/core/common/serial\"\n)\n\n// PacketReader is an io.Reader that reads whole chunk of Mux frames every time.\ntype PacketReader struct {\n\treader io.Reader\n\teof    bool\n}\n\n// NewPacketReader creates a new PacketReader.\nfunc NewPacketReader(reader io.Reader) *PacketReader {\n\treturn &PacketReader{\n\t\treader: reader,\n\t\teof:    false,\n\t}\n}\n\n// ReadMultiBuffer implements buf.Reader.\nfunc (r *PacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {\n\tif r.eof {\n\t\treturn nil, io.EOF\n\t}\n\n\tsize, err := serial.ReadUint16(r.reader)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif size > buf.Size {\n\t\treturn nil, newError(\"packet size too large: \", size)\n\t}\n\n\tb := buf.New()\n\tif _, err := b.ReadFullFrom(r.reader, int32(size)); err != nil {\n\t\tb.Release()\n\t\treturn nil, err\n\t}\n\tr.eof = true\n\treturn buf.MultiBuffer{b}, nil\n}\n\n// NewStreamReader creates a new StreamReader.\nfunc NewStreamReader(reader *buf.BufferedReader) buf.Reader {\n\treturn crypto.NewChunkStreamReaderWithChunkCount(crypto.PlainChunkSizeParser{}, reader, 1)\n}\n"
  },
  {
    "path": "common/mux/server.go",
    "content": "package mux\n\nimport (\n\t\"context\"\n\t\"io\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/errors\"\n\t\"v2ray.com/core/common/log\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/session\"\n\t\"v2ray.com/core/features/routing\"\n\t\"v2ray.com/core/transport\"\n\t\"v2ray.com/core/transport/pipe\"\n)\n\ntype Server struct {\n\tdispatcher routing.Dispatcher\n}\n\n// NewServer creates a new mux.Server.\nfunc NewServer(ctx context.Context) *Server {\n\ts := &Server{}\n\tcore.RequireFeatures(ctx, func(d routing.Dispatcher) {\n\t\ts.dispatcher = d\n\t})\n\treturn s\n}\n\n// Type implements common.HasType.\nfunc (s *Server) Type() interface{} {\n\treturn s.dispatcher.Type()\n}\n\n// Dispatch implements routing.Dispatcher\nfunc (s *Server) Dispatch(ctx context.Context, dest net.Destination) (*transport.Link, error) {\n\tif dest.Address != muxCoolAddress {\n\t\treturn s.dispatcher.Dispatch(ctx, dest)\n\t}\n\n\topts := pipe.OptionsFromContext(ctx)\n\tuplinkReader, uplinkWriter := pipe.New(opts...)\n\tdownlinkReader, downlinkWriter := pipe.New(opts...)\n\n\t_, err := NewServerWorker(ctx, s.dispatcher, &transport.Link{\n\t\tReader: uplinkReader,\n\t\tWriter: downlinkWriter,\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &transport.Link{Reader: downlinkReader, Writer: uplinkWriter}, nil\n}\n\n// Start implements common.Runnable.\nfunc (s *Server) Start() error {\n\treturn nil\n}\n\n// Close implements common.Closable.\nfunc (s *Server) Close() error {\n\treturn nil\n}\n\ntype ServerWorker struct {\n\tdispatcher     routing.Dispatcher\n\tlink           *transport.Link\n\tsessionManager *SessionManager\n}\n\nfunc NewServerWorker(ctx context.Context, d routing.Dispatcher, link *transport.Link) (*ServerWorker, error) {\n\tworker := &ServerWorker{\n\t\tdispatcher:     d,\n\t\tlink:           link,\n\t\tsessionManager: NewSessionManager(),\n\t}\n\tgo worker.run(ctx)\n\treturn worker, nil\n}\n\nfunc handle(ctx context.Context, s *Session, output buf.Writer) {\n\twriter := NewResponseWriter(s.ID, output, s.transferType)\n\tif err := buf.Copy(s.input, writer); err != nil {\n\t\tnewError(\"session \", s.ID, \" ends.\").Base(err).WriteToLog(session.ExportIDToError(ctx))\n\t\twriter.hasError = true\n\t}\n\n\twriter.Close()\n\ts.Close()\n}\n\nfunc (w *ServerWorker) ActiveConnections() uint32 {\n\treturn uint32(w.sessionManager.Size())\n}\n\nfunc (w *ServerWorker) Closed() bool {\n\treturn w.sessionManager.Closed()\n}\n\nfunc (w *ServerWorker) handleStatusKeepAlive(meta *FrameMetadata, reader *buf.BufferedReader) error {\n\tif meta.Option.Has(OptionData) {\n\t\treturn buf.Copy(NewStreamReader(reader), buf.Discard)\n\t}\n\treturn nil\n}\n\nfunc (w *ServerWorker) handleStatusNew(ctx context.Context, meta *FrameMetadata, reader *buf.BufferedReader) error {\n\tnewError(\"received request for \", meta.Target).WriteToLog(session.ExportIDToError(ctx))\n\t{\n\t\tmsg := &log.AccessMessage{\n\t\t\tTo:     meta.Target,\n\t\t\tStatus: log.AccessAccepted,\n\t\t\tReason: \"\",\n\t\t}\n\t\tif inbound := session.InboundFromContext(ctx); inbound != nil && inbound.Source.IsValid() {\n\t\t\tmsg.From = inbound.Source\n\t\t\tmsg.Email = inbound.User.Email\n\t\t}\n\t\tctx = log.ContextWithAccessMessage(ctx, msg)\n\t}\n\tlink, err := w.dispatcher.Dispatch(ctx, meta.Target)\n\tif err != nil {\n\t\tif meta.Option.Has(OptionData) {\n\t\t\tbuf.Copy(NewStreamReader(reader), buf.Discard)\n\t\t}\n\t\treturn newError(\"failed to dispatch request.\").Base(err)\n\t}\n\ts := &Session{\n\t\tinput:        link.Reader,\n\t\toutput:       link.Writer,\n\t\tparent:       w.sessionManager,\n\t\tID:           meta.SessionID,\n\t\ttransferType: protocol.TransferTypeStream,\n\t}\n\tif meta.Target.Network == net.Network_UDP {\n\t\ts.transferType = protocol.TransferTypePacket\n\t}\n\tw.sessionManager.Add(s)\n\tgo handle(ctx, s, w.link.Writer)\n\tif !meta.Option.Has(OptionData) {\n\t\treturn nil\n\t}\n\n\trr := s.NewReader(reader)\n\tif err := buf.Copy(rr, s.output); err != nil {\n\t\tbuf.Copy(rr, buf.Discard)\n\t\tcommon.Interrupt(s.input)\n\t\treturn s.Close()\n\t}\n\treturn nil\n}\n\nfunc (w *ServerWorker) handleStatusKeep(meta *FrameMetadata, reader *buf.BufferedReader) error {\n\tif !meta.Option.Has(OptionData) {\n\t\treturn nil\n\t}\n\n\ts, found := w.sessionManager.Get(meta.SessionID)\n\tif !found {\n\t\t// Notify remote peer to close this session.\n\t\tclosingWriter := NewResponseWriter(meta.SessionID, w.link.Writer, protocol.TransferTypeStream)\n\t\tclosingWriter.Close()\n\n\t\treturn buf.Copy(NewStreamReader(reader), buf.Discard)\n\t}\n\n\trr := s.NewReader(reader)\n\terr := buf.Copy(rr, s.output)\n\n\tif err != nil && buf.IsWriteError(err) {\n\t\tnewError(\"failed to write to downstream writer. closing session \", s.ID).Base(err).WriteToLog()\n\n\t\t// Notify remote peer to close this session.\n\t\tclosingWriter := NewResponseWriter(meta.SessionID, w.link.Writer, protocol.TransferTypeStream)\n\t\tclosingWriter.Close()\n\n\t\tdrainErr := buf.Copy(rr, buf.Discard)\n\t\tcommon.Interrupt(s.input)\n\t\ts.Close()\n\t\treturn drainErr\n\t}\n\n\treturn err\n}\n\nfunc (w *ServerWorker) handleStatusEnd(meta *FrameMetadata, reader *buf.BufferedReader) error {\n\tif s, found := w.sessionManager.Get(meta.SessionID); found {\n\t\tif meta.Option.Has(OptionError) {\n\t\t\tcommon.Interrupt(s.input)\n\t\t\tcommon.Interrupt(s.output)\n\t\t}\n\t\ts.Close()\n\t}\n\tif meta.Option.Has(OptionData) {\n\t\treturn buf.Copy(NewStreamReader(reader), buf.Discard)\n\t}\n\treturn nil\n}\n\nfunc (w *ServerWorker) handleFrame(ctx context.Context, reader *buf.BufferedReader) error {\n\tvar meta FrameMetadata\n\terr := meta.Unmarshal(reader)\n\tif err != nil {\n\t\treturn newError(\"failed to read metadata\").Base(err)\n\t}\n\n\tswitch meta.SessionStatus {\n\tcase SessionStatusKeepAlive:\n\t\terr = w.handleStatusKeepAlive(&meta, reader)\n\tcase SessionStatusEnd:\n\t\terr = w.handleStatusEnd(&meta, reader)\n\tcase SessionStatusNew:\n\t\terr = w.handleStatusNew(ctx, &meta, reader)\n\tcase SessionStatusKeep:\n\t\terr = w.handleStatusKeep(&meta, reader)\n\tdefault:\n\t\tstatus := meta.SessionStatus\n\t\treturn newError(\"unknown status: \", status).AtError()\n\t}\n\n\tif err != nil {\n\t\treturn newError(\"failed to process data\").Base(err)\n\t}\n\treturn nil\n}\n\nfunc (w *ServerWorker) run(ctx context.Context) {\n\tinput := w.link.Reader\n\treader := &buf.BufferedReader{Reader: input}\n\n\tdefer w.sessionManager.Close() // nolint: errcheck\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn\n\t\tdefault:\n\t\t\terr := w.handleFrame(ctx, reader)\n\t\t\tif err != nil {\n\t\t\t\tif errors.Cause(err) != io.EOF {\n\t\t\t\t\tnewError(\"unexpected EOF\").Base(err).WriteToLog(session.ExportIDToError(ctx))\n\t\t\t\t\tcommon.Interrupt(input)\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "common/mux/session.go",
    "content": "package mux\n\nimport (\n\t\"sync\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/protocol\"\n)\n\ntype SessionManager struct {\n\tsync.RWMutex\n\tsessions map[uint16]*Session\n\tcount    uint16\n\tclosed   bool\n}\n\nfunc NewSessionManager() *SessionManager {\n\treturn &SessionManager{\n\t\tcount:    0,\n\t\tsessions: make(map[uint16]*Session, 16),\n\t}\n}\n\nfunc (m *SessionManager) Closed() bool {\n\tm.RLock()\n\tdefer m.RUnlock()\n\n\treturn m.closed\n}\n\nfunc (m *SessionManager) Size() int {\n\tm.RLock()\n\tdefer m.RUnlock()\n\n\treturn len(m.sessions)\n}\n\nfunc (m *SessionManager) Count() int {\n\tm.RLock()\n\tdefer m.RUnlock()\n\n\treturn int(m.count)\n}\n\nfunc (m *SessionManager) Allocate() *Session {\n\tm.Lock()\n\tdefer m.Unlock()\n\n\tif m.closed {\n\t\treturn nil\n\t}\n\n\tm.count++\n\ts := &Session{\n\t\tID:     m.count,\n\t\tparent: m,\n\t}\n\tm.sessions[s.ID] = s\n\treturn s\n}\n\nfunc (m *SessionManager) Add(s *Session) {\n\tm.Lock()\n\tdefer m.Unlock()\n\n\tif m.closed {\n\t\treturn\n\t}\n\n\tm.count++\n\tm.sessions[s.ID] = s\n}\n\nfunc (m *SessionManager) Remove(id uint16) {\n\tm.Lock()\n\tdefer m.Unlock()\n\n\tif m.closed {\n\t\treturn\n\t}\n\n\tdelete(m.sessions, id)\n\n\tif len(m.sessions) == 0 {\n\t\tm.sessions = make(map[uint16]*Session, 16)\n\t}\n}\n\nfunc (m *SessionManager) Get(id uint16) (*Session, bool) {\n\tm.RLock()\n\tdefer m.RUnlock()\n\n\tif m.closed {\n\t\treturn nil, false\n\t}\n\n\ts, found := m.sessions[id]\n\treturn s, found\n}\n\nfunc (m *SessionManager) CloseIfNoSession() bool {\n\tm.Lock()\n\tdefer m.Unlock()\n\n\tif m.closed {\n\t\treturn true\n\t}\n\n\tif len(m.sessions) != 0 {\n\t\treturn false\n\t}\n\n\tm.closed = true\n\treturn true\n}\n\nfunc (m *SessionManager) Close() error {\n\tm.Lock()\n\tdefer m.Unlock()\n\n\tif m.closed {\n\t\treturn nil\n\t}\n\n\tm.closed = true\n\n\tfor _, s := range m.sessions {\n\t\tcommon.Close(s.input)  // nolint: errcheck\n\t\tcommon.Close(s.output) // nolint: errcheck\n\t}\n\n\tm.sessions = nil\n\treturn nil\n}\n\n// Session represents a client connection in a Mux connection.\ntype Session struct {\n\tinput        buf.Reader\n\toutput       buf.Writer\n\tparent       *SessionManager\n\tID           uint16\n\ttransferType protocol.TransferType\n}\n\n// Close closes all resources associated with this session.\nfunc (s *Session) Close() error {\n\tcommon.Close(s.output) // nolint: errcheck\n\tcommon.Close(s.input)  // nolint: errcheck\n\ts.parent.Remove(s.ID)\n\treturn nil\n}\n\n// NewReader creates a buf.Reader based on the transfer type of this Session.\nfunc (s *Session) NewReader(reader *buf.BufferedReader) buf.Reader {\n\tif s.transferType == protocol.TransferTypeStream {\n\t\treturn NewStreamReader(reader)\n\t}\n\treturn NewPacketReader(reader)\n}\n"
  },
  {
    "path": "common/mux/session_test.go",
    "content": "package mux_test\n\nimport (\n\t\"testing\"\n\n\t. \"v2ray.com/core/common/mux\"\n)\n\nfunc TestSessionManagerAdd(t *testing.T) {\n\tm := NewSessionManager()\n\n\ts := m.Allocate()\n\tif s.ID != 1 {\n\t\tt.Error(\"id: \", s.ID)\n\t}\n\tif m.Size() != 1 {\n\t\tt.Error(\"size: \", m.Size())\n\t}\n\n\ts = m.Allocate()\n\tif s.ID != 2 {\n\t\tt.Error(\"id: \", s.ID)\n\t}\n\tif m.Size() != 2 {\n\t\tt.Error(\"size: \", m.Size())\n\t}\n\n\ts = &Session{\n\t\tID: 4,\n\t}\n\tm.Add(s)\n\tif s.ID != 4 {\n\t\tt.Error(\"id: \", s.ID)\n\t}\n\tif m.Size() != 3 {\n\t\tt.Error(\"size: \", m.Size())\n\t}\n}\n\nfunc TestSessionManagerClose(t *testing.T) {\n\tm := NewSessionManager()\n\ts := m.Allocate()\n\n\tif m.CloseIfNoSession() {\n\t\tt.Error(\"able to close\")\n\t}\n\tm.Remove(s.ID)\n\tif !m.CloseIfNoSession() {\n\t\tt.Error(\"not able to close\")\n\t}\n}\n"
  },
  {
    "path": "common/mux/writer.go",
    "content": "package mux\n\nimport (\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/serial\"\n)\n\ntype Writer struct {\n\tdest         net.Destination\n\twriter       buf.Writer\n\tid           uint16\n\tfollowup     bool\n\thasError     bool\n\ttransferType protocol.TransferType\n}\n\nfunc NewWriter(id uint16, dest net.Destination, writer buf.Writer, transferType protocol.TransferType) *Writer {\n\treturn &Writer{\n\t\tid:           id,\n\t\tdest:         dest,\n\t\twriter:       writer,\n\t\tfollowup:     false,\n\t\ttransferType: transferType,\n\t}\n}\n\nfunc NewResponseWriter(id uint16, writer buf.Writer, transferType protocol.TransferType) *Writer {\n\treturn &Writer{\n\t\tid:           id,\n\t\twriter:       writer,\n\t\tfollowup:     true,\n\t\ttransferType: transferType,\n\t}\n}\n\nfunc (w *Writer) getNextFrameMeta() FrameMetadata {\n\tmeta := FrameMetadata{\n\t\tSessionID: w.id,\n\t\tTarget:    w.dest,\n\t}\n\n\tif w.followup {\n\t\tmeta.SessionStatus = SessionStatusKeep\n\t} else {\n\t\tw.followup = true\n\t\tmeta.SessionStatus = SessionStatusNew\n\t}\n\n\treturn meta\n}\n\nfunc (w *Writer) writeMetaOnly() error {\n\tmeta := w.getNextFrameMeta()\n\tb := buf.New()\n\tif err := meta.WriteTo(b); err != nil {\n\t\treturn err\n\t}\n\treturn w.writer.WriteMultiBuffer(buf.MultiBuffer{b})\n}\n\nfunc writeMetaWithFrame(writer buf.Writer, meta FrameMetadata, data buf.MultiBuffer) error {\n\tframe := buf.New()\n\tif err := meta.WriteTo(frame); err != nil {\n\t\treturn err\n\t}\n\tif _, err := serial.WriteUint16(frame, uint16(data.Len())); err != nil {\n\t\treturn err\n\t}\n\n\tmb2 := make(buf.MultiBuffer, 0, len(data)+1)\n\tmb2 = append(mb2, frame)\n\tmb2 = append(mb2, data...)\n\treturn writer.WriteMultiBuffer(mb2)\n}\n\nfunc (w *Writer) writeData(mb buf.MultiBuffer) error {\n\tmeta := w.getNextFrameMeta()\n\tmeta.Option.Set(OptionData)\n\n\treturn writeMetaWithFrame(w.writer, meta, mb)\n}\n\n// WriteMultiBuffer implements buf.Writer.\nfunc (w *Writer) WriteMultiBuffer(mb buf.MultiBuffer) error {\n\tdefer buf.ReleaseMulti(mb)\n\n\tif mb.IsEmpty() {\n\t\treturn w.writeMetaOnly()\n\t}\n\n\tfor !mb.IsEmpty() {\n\t\tvar chunk buf.MultiBuffer\n\t\tif w.transferType == protocol.TransferTypeStream {\n\t\t\tmb, chunk = buf.SplitSize(mb, 8*1024)\n\t\t} else {\n\t\t\tmb2, b := buf.SplitFirst(mb)\n\t\t\tmb = mb2\n\t\t\tchunk = buf.MultiBuffer{b}\n\t\t}\n\t\tif err := w.writeData(chunk); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Close implements common.Closable.\nfunc (w *Writer) Close() error {\n\tmeta := FrameMetadata{\n\t\tSessionID:     w.id,\n\t\tSessionStatus: SessionStatusEnd,\n\t}\n\tif w.hasError {\n\t\tmeta.Option.Set(OptionError)\n\t}\n\n\tframe := buf.New()\n\tcommon.Must(meta.WriteTo(frame))\n\n\tw.writer.WriteMultiBuffer(buf.MultiBuffer{frame}) // nolint: errcheck\n\treturn nil\n}\n"
  },
  {
    "path": "common/net/address.go",
    "content": "package net\n\nimport (\n\t\"bytes\"\n\t\"net\"\n\t\"strings\"\n)\n\nvar (\n\t// LocalHostIP is a constant value for localhost IP in IPv4.\n\tLocalHostIP = IPAddress([]byte{127, 0, 0, 1})\n\n\t// AnyIP is a constant value for any IP in IPv4.\n\tAnyIP = IPAddress([]byte{0, 0, 0, 0})\n\n\t// LocalHostDomain is a constant value for localhost domain.\n\tLocalHostDomain = DomainAddress(\"localhost\")\n\n\t// LocalHostIPv6 is a constant value for localhost IP in IPv6.\n\tLocalHostIPv6 = IPAddress([]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1})\n\n\t// AnyIPv6 is a constant value for any IP in IPv6.\n\tAnyIPv6 = IPAddress([]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})\n)\n\n// AddressFamily is the type of address.\ntype AddressFamily byte\n\nconst (\n\t// AddressFamilyIPv4 represents address as IPv4\n\tAddressFamilyIPv4 = AddressFamily(0)\n\n\t// AddressFamilyIPv6 represents address as IPv6\n\tAddressFamilyIPv6 = AddressFamily(1)\n\n\t// AddressFamilyDomain represents address as Domain\n\tAddressFamilyDomain = AddressFamily(2)\n)\n\n// IsIPv4 returns true if current AddressFamily is IPv4.\nfunc (af AddressFamily) IsIPv4() bool {\n\treturn af == AddressFamilyIPv4\n}\n\n// IsIPv6 returns true if current AddressFamily is IPv6.\nfunc (af AddressFamily) IsIPv6() bool {\n\treturn af == AddressFamilyIPv6\n}\n\n// IsIP returns true if current AddressFamily is IPv6 or IPv4.\nfunc (af AddressFamily) IsIP() bool {\n\treturn af == AddressFamilyIPv4 || af == AddressFamilyIPv6\n}\n\n// IsDomain returns true if current AddressFamily is Domain.\nfunc (af AddressFamily) IsDomain() bool {\n\treturn af == AddressFamilyDomain\n}\n\n// Address represents a network address to be communicated with. It may be an IP address or domain\n// address, not both. This interface doesn't resolve IP address for a given domain.\ntype Address interface {\n\tIP() net.IP     // IP of this Address\n\tDomain() string // Domain of this Address\n\tFamily() AddressFamily\n\n\tString() string // String representation of this Address\n}\n\nfunc isAlphaNum(c byte) bool {\n\treturn (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')\n}\n\n// ParseAddress parses a string into an Address. The return value will be an IPAddress when\n// the string is in the form of IPv4 or IPv6 address, or a DomainAddress otherwise.\nfunc ParseAddress(addr string) Address {\n\t// Handle IPv6 address in form as \"[2001:4860:0:2001::68]\"\n\tlenAddr := len(addr)\n\tif lenAddr > 0 && addr[0] == '[' && addr[lenAddr-1] == ']' {\n\t\taddr = addr[1 : lenAddr-1]\n\t\tlenAddr -= 2\n\t}\n\n\tif lenAddr > 0 && (!isAlphaNum(addr[0]) || !isAlphaNum(addr[len(addr)-1])) {\n\t\taddr = strings.TrimSpace(addr)\n\t}\n\n\tip := net.ParseIP(addr)\n\tif ip != nil {\n\t\treturn IPAddress(ip)\n\t}\n\treturn DomainAddress(addr)\n}\n\nvar bytes0 = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}\n\n// IPAddress creates an Address with given IP.\nfunc IPAddress(ip []byte) Address {\n\tswitch len(ip) {\n\tcase net.IPv4len:\n\t\tvar addr ipv4Address = [4]byte{ip[0], ip[1], ip[2], ip[3]}\n\t\treturn addr\n\tcase net.IPv6len:\n\t\tif bytes.Equal(ip[:10], bytes0) && ip[10] == 0xff && ip[11] == 0xff {\n\t\t\treturn IPAddress(ip[12:16])\n\t\t}\n\t\tvar addr ipv6Address = [16]byte{\n\t\t\tip[0], ip[1], ip[2], ip[3],\n\t\t\tip[4], ip[5], ip[6], ip[7],\n\t\t\tip[8], ip[9], ip[10], ip[11],\n\t\t\tip[12], ip[13], ip[14], ip[15],\n\t\t}\n\t\treturn addr\n\tdefault:\n\t\tnewError(\"invalid IP format: \", ip).AtError().WriteToLog()\n\t\treturn nil\n\t}\n}\n\n// DomainAddress creates an Address with given domain.\nfunc DomainAddress(domain string) Address {\n\treturn domainAddress(domain)\n}\n\ntype ipv4Address [4]byte\n\nfunc (a ipv4Address) IP() net.IP {\n\treturn net.IP(a[:])\n}\n\nfunc (ipv4Address) Domain() string {\n\tpanic(\"Calling Domain() on an IPv4Address.\")\n}\n\nfunc (ipv4Address) Family() AddressFamily {\n\treturn AddressFamilyIPv4\n}\n\nfunc (a ipv4Address) String() string {\n\treturn a.IP().String()\n}\n\ntype ipv6Address [16]byte\n\nfunc (a ipv6Address) IP() net.IP {\n\treturn net.IP(a[:])\n}\n\nfunc (ipv6Address) Domain() string {\n\tpanic(\"Calling Domain() on an IPv6Address.\")\n}\n\nfunc (ipv6Address) Family() AddressFamily {\n\treturn AddressFamilyIPv6\n}\n\nfunc (a ipv6Address) String() string {\n\treturn \"[\" + a.IP().String() + \"]\"\n}\n\ntype domainAddress string\n\nfunc (domainAddress) IP() net.IP {\n\tpanic(\"Calling IP() on a DomainAddress.\")\n}\n\nfunc (a domainAddress) Domain() string {\n\treturn string(a)\n}\n\nfunc (domainAddress) Family() AddressFamily {\n\treturn AddressFamilyDomain\n}\n\nfunc (a domainAddress) String() string {\n\treturn a.Domain()\n}\n\n// AsAddress translates IPOrDomain to Address.\nfunc (d *IPOrDomain) AsAddress() Address {\n\tif d == nil {\n\t\treturn nil\n\t}\n\tswitch addr := d.Address.(type) {\n\tcase *IPOrDomain_Ip:\n\t\treturn IPAddress(addr.Ip)\n\tcase *IPOrDomain_Domain:\n\t\treturn DomainAddress(addr.Domain)\n\t}\n\tpanic(\"Common|Net: Invalid address.\")\n}\n\n// NewIPOrDomain translates Address to IPOrDomain\nfunc NewIPOrDomain(addr Address) *IPOrDomain {\n\tswitch addr.Family() {\n\tcase AddressFamilyDomain:\n\t\treturn &IPOrDomain{\n\t\t\tAddress: &IPOrDomain_Domain{\n\t\t\t\tDomain: addr.Domain(),\n\t\t\t},\n\t\t}\n\tcase AddressFamilyIPv4, AddressFamilyIPv6:\n\t\treturn &IPOrDomain{\n\t\t\tAddress: &IPOrDomain_Ip{\n\t\t\t\tIp: addr.IP(),\n\t\t\t},\n\t\t}\n\tdefault:\n\t\tpanic(\"Unknown Address type.\")\n\t}\n}\n"
  },
  {
    "path": "common/net/address.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: common/net/address.proto\n\npackage net\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\n// Address of a network host. It may be either an IP address or a domain\n// address.\ntype IPOrDomain struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Types that are assignable to Address:\n\t//\t*IPOrDomain_Ip\n\t//\t*IPOrDomain_Domain\n\tAddress isIPOrDomain_Address `protobuf_oneof:\"address\"`\n}\n\nfunc (x *IPOrDomain) Reset() {\n\t*x = IPOrDomain{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_common_net_address_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *IPOrDomain) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*IPOrDomain) ProtoMessage() {}\n\nfunc (x *IPOrDomain) ProtoReflect() protoreflect.Message {\n\tmi := &file_common_net_address_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use IPOrDomain.ProtoReflect.Descriptor instead.\nfunc (*IPOrDomain) Descriptor() ([]byte, []int) {\n\treturn file_common_net_address_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (m *IPOrDomain) GetAddress() isIPOrDomain_Address {\n\tif m != nil {\n\t\treturn m.Address\n\t}\n\treturn nil\n}\n\nfunc (x *IPOrDomain) GetIp() []byte {\n\tif x, ok := x.GetAddress().(*IPOrDomain_Ip); ok {\n\t\treturn x.Ip\n\t}\n\treturn nil\n}\n\nfunc (x *IPOrDomain) GetDomain() string {\n\tif x, ok := x.GetAddress().(*IPOrDomain_Domain); ok {\n\t\treturn x.Domain\n\t}\n\treturn \"\"\n}\n\ntype isIPOrDomain_Address interface {\n\tisIPOrDomain_Address()\n}\n\ntype IPOrDomain_Ip struct {\n\t// IP address. Must by either 4 or 16 bytes.\n\tIp []byte `protobuf:\"bytes,1,opt,name=ip,proto3,oneof\"`\n}\n\ntype IPOrDomain_Domain struct {\n\t// Domain address.\n\tDomain string `protobuf:\"bytes,2,opt,name=domain,proto3,oneof\"`\n}\n\nfunc (*IPOrDomain_Ip) isIPOrDomain_Address() {}\n\nfunc (*IPOrDomain_Domain) isIPOrDomain_Address() {}\n\nvar File_common_net_address_proto protoreflect.FileDescriptor\n\nvar file_common_net_address_proto_rawDesc = []byte{\n\t0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x61, 0x64, 0x64,\n\t0x72, 0x65, 0x73, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x15, 0x76, 0x32, 0x72, 0x61,\n\t0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65,\n\t0x74, 0x22, 0x43, 0x0a, 0x0a, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12,\n\t0x10, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x02, 0x69,\n\t0x70, 0x12, 0x18, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28,\n\t0x09, 0x48, 0x00, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x42, 0x09, 0x0a, 0x07, 0x61,\n\t0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x50, 0x0a, 0x19, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32,\n\t0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e,\n\t0x6e, 0x65, 0x74, 0x50, 0x01, 0x5a, 0x19, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d,\n\t0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74,\n\t0xaa, 0x02, 0x15, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x43, 0x6f,\n\t0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4e, 0x65, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_common_net_address_proto_rawDescOnce sync.Once\n\tfile_common_net_address_proto_rawDescData = file_common_net_address_proto_rawDesc\n)\n\nfunc file_common_net_address_proto_rawDescGZIP() []byte {\n\tfile_common_net_address_proto_rawDescOnce.Do(func() {\n\t\tfile_common_net_address_proto_rawDescData = protoimpl.X.CompressGZIP(file_common_net_address_proto_rawDescData)\n\t})\n\treturn file_common_net_address_proto_rawDescData\n}\n\nvar file_common_net_address_proto_msgTypes = make([]protoimpl.MessageInfo, 1)\nvar file_common_net_address_proto_goTypes = []interface{}{\n\t(*IPOrDomain)(nil), // 0: v2ray.core.common.net.IPOrDomain\n}\nvar file_common_net_address_proto_depIdxs = []int32{\n\t0, // [0:0] is the sub-list for method output_type\n\t0, // [0:0] is the sub-list for method input_type\n\t0, // [0:0] is the sub-list for extension type_name\n\t0, // [0:0] is the sub-list for extension extendee\n\t0, // [0:0] is the sub-list for field type_name\n}\n\nfunc init() { file_common_net_address_proto_init() }\nfunc file_common_net_address_proto_init() {\n\tif File_common_net_address_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_common_net_address_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*IPOrDomain); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\tfile_common_net_address_proto_msgTypes[0].OneofWrappers = []interface{}{\n\t\t(*IPOrDomain_Ip)(nil),\n\t\t(*IPOrDomain_Domain)(nil),\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_common_net_address_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   1,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_common_net_address_proto_goTypes,\n\t\tDependencyIndexes: file_common_net_address_proto_depIdxs,\n\t\tMessageInfos:      file_common_net_address_proto_msgTypes,\n\t}.Build()\n\tFile_common_net_address_proto = out.File\n\tfile_common_net_address_proto_rawDesc = nil\n\tfile_common_net_address_proto_goTypes = nil\n\tfile_common_net_address_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "common/net/address.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.common.net;\noption csharp_namespace = \"V2Ray.Core.Common.Net\";\noption go_package = \"v2ray.com/core/common/net\";\noption java_package = \"com.v2ray.core.common.net\";\noption java_multiple_files = true;\n\n// Address of a network host. It may be either an IP address or a domain\n// address.\nmessage IPOrDomain {\n  oneof address {\n    // IP address. Must by either 4 or 16 bytes.\n    bytes ip = 1;\n\n    // Domain address.\n    string domain = 2;\n  }\n}\n"
  },
  {
    "path": "common/net/address_test.go",
    "content": "package net_test\n\nimport (\n\t\"net\"\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\n\t. \"v2ray.com/core/common/net\"\n)\n\nfunc TestAddressProperty(t *testing.T) {\n\ttype addrProprty struct {\n\t\tIP     []byte\n\t\tDomain string\n\t\tFamily AddressFamily\n\t\tString string\n\t}\n\n\ttestCases := []struct {\n\t\tInput  Address\n\t\tOutput addrProprty\n\t}{\n\t\t{\n\t\t\tInput: IPAddress([]byte{byte(1), byte(2), byte(3), byte(4)}),\n\t\t\tOutput: addrProprty{\n\t\t\t\tIP:     []byte{byte(1), byte(2), byte(3), byte(4)},\n\t\t\t\tFamily: AddressFamilyIPv4,\n\t\t\t\tString: \"1.2.3.4\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tInput: IPAddress([]byte{\n\t\t\t\tbyte(1), byte(2), byte(3), byte(4),\n\t\t\t\tbyte(1), byte(2), byte(3), byte(4),\n\t\t\t\tbyte(1), byte(2), byte(3), byte(4),\n\t\t\t\tbyte(1), byte(2), byte(3), byte(4),\n\t\t\t}),\n\t\t\tOutput: addrProprty{\n\t\t\t\tIP: []byte{\n\t\t\t\t\tbyte(1), byte(2), byte(3), byte(4),\n\t\t\t\t\tbyte(1), byte(2), byte(3), byte(4),\n\t\t\t\t\tbyte(1), byte(2), byte(3), byte(4),\n\t\t\t\t\tbyte(1), byte(2), byte(3), byte(4),\n\t\t\t\t},\n\t\t\t\tFamily: AddressFamilyIPv6,\n\t\t\t\tString: \"[102:304:102:304:102:304:102:304]\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tInput: IPAddress([]byte{\n\t\t\t\tbyte(0), byte(0), byte(0), byte(0),\n\t\t\t\tbyte(0), byte(0), byte(0), byte(0),\n\t\t\t\tbyte(0), byte(0), byte(255), byte(255),\n\t\t\t\tbyte(1), byte(2), byte(3), byte(4),\n\t\t\t}),\n\t\t\tOutput: addrProprty{\n\t\t\t\tIP:     []byte{byte(1), byte(2), byte(3), byte(4)},\n\t\t\t\tFamily: AddressFamilyIPv4,\n\t\t\t\tString: \"1.2.3.4\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tInput: DomainAddress(\"v2ray.com\"),\n\t\t\tOutput: addrProprty{\n\t\t\t\tDomain: \"v2ray.com\",\n\t\t\t\tFamily: AddressFamilyDomain,\n\t\t\t\tString: \"v2ray.com\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tInput: IPAddress(net.IPv4(1, 2, 3, 4)),\n\t\t\tOutput: addrProprty{\n\t\t\t\tIP:     []byte{byte(1), byte(2), byte(3), byte(4)},\n\t\t\t\tFamily: AddressFamilyIPv4,\n\t\t\t\tString: \"1.2.3.4\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tInput: ParseAddress(\"[2001:4860:0:2001::68]\"),\n\t\t\tOutput: addrProprty{\n\t\t\t\tIP:     []byte{0x20, 0x01, 0x48, 0x60, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68},\n\t\t\t\tFamily: AddressFamilyIPv6,\n\t\t\t\tString: \"[2001:4860:0:2001::68]\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tInput: ParseAddress(\"::0\"),\n\t\t\tOutput: addrProprty{\n\t\t\t\tIP:     AnyIPv6.IP(),\n\t\t\t\tFamily: AddressFamilyIPv6,\n\t\t\t\tString: \"[::]\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tInput: ParseAddress(\"[::ffff:123.151.71.143]\"),\n\t\t\tOutput: addrProprty{\n\t\t\t\tIP:     []byte{123, 151, 71, 143},\n\t\t\t\tFamily: AddressFamilyIPv4,\n\t\t\t\tString: \"123.151.71.143\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tInput: NewIPOrDomain(ParseAddress(\"v2ray.com\")).AsAddress(),\n\t\t\tOutput: addrProprty{\n\t\t\t\tDomain: \"v2ray.com\",\n\t\t\t\tFamily: AddressFamilyDomain,\n\t\t\t\tString: \"v2ray.com\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tInput: NewIPOrDomain(ParseAddress(\"8.8.8.8\")).AsAddress(),\n\t\t\tOutput: addrProprty{\n\t\t\t\tIP:     []byte{8, 8, 8, 8},\n\t\t\t\tFamily: AddressFamilyIPv4,\n\t\t\t\tString: \"8.8.8.8\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tInput: NewIPOrDomain(ParseAddress(\"[2001:4860:0:2001::68]\")).AsAddress(),\n\t\t\tOutput: addrProprty{\n\t\t\t\tIP:     []byte{0x20, 0x01, 0x48, 0x60, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68},\n\t\t\t\tFamily: AddressFamilyIPv6,\n\t\t\t\tString: \"[2001:4860:0:2001::68]\",\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, testCase := range testCases {\n\t\tactual := addrProprty{\n\t\t\tFamily: testCase.Input.Family(),\n\t\t\tString: testCase.Input.String(),\n\t\t}\n\t\tif testCase.Input.Family().IsIP() {\n\t\t\tactual.IP = testCase.Input.IP()\n\t\t} else {\n\t\t\tactual.Domain = testCase.Input.Domain()\n\t\t}\n\n\t\tif r := cmp.Diff(actual, testCase.Output); r != \"\" {\n\t\t\tt.Error(\"for input: \", testCase.Input, \":\", r)\n\t\t}\n\t}\n}\n\nfunc TestInvalidAddressConvertion(t *testing.T) {\n\tpanics := func(f func()) (ret bool) {\n\t\tdefer func() {\n\t\t\tif r := recover(); r != nil {\n\t\t\t\tret = true\n\t\t\t}\n\t\t}()\n\t\tf()\n\t\treturn false\n\t}\n\n\ttestCases := []func(){\n\t\tfunc() { ParseAddress(\"8.8.8.8\").Domain() },\n\t\tfunc() { ParseAddress(\"2001:4860:0:2001::68\").Domain() },\n\t\tfunc() { ParseAddress(\"v2ray.com\").IP() },\n\t}\n\tfor idx, testCase := range testCases {\n\t\tif !panics(testCase) {\n\t\t\tt.Error(\"case \", idx, \" failed\")\n\t\t}\n\t}\n}\n\nfunc BenchmarkParseAddressIPv4(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\taddr := ParseAddress(\"8.8.8.8\")\n\t\tif addr.Family() != AddressFamilyIPv4 {\n\t\t\tpanic(\"not ipv4\")\n\t\t}\n\t}\n}\n\nfunc BenchmarkParseAddressIPv6(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\taddr := ParseAddress(\"2001:4860:0:2001::68\")\n\t\tif addr.Family() != AddressFamilyIPv6 {\n\t\t\tpanic(\"not ipv6\")\n\t\t}\n\t}\n}\n\nfunc BenchmarkParseAddressDomain(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\taddr := ParseAddress(\"v2ray.com\")\n\t\tif addr.Family() != AddressFamilyDomain {\n\t\t\tpanic(\"not domain\")\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "common/net/connection.go",
    "content": "// +build !confonly\n\npackage net\n\nimport (\n\t\"io\"\n\t\"net\"\n\t\"time\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/signal/done\"\n)\n\ntype ConnectionOption func(*connection)\n\nfunc ConnectionLocalAddr(a net.Addr) ConnectionOption {\n\treturn func(c *connection) {\n\t\tc.local = a\n\t}\n}\n\nfunc ConnectionRemoteAddr(a net.Addr) ConnectionOption {\n\treturn func(c *connection) {\n\t\tc.remote = a\n\t}\n}\n\nfunc ConnectionInput(writer io.Writer) ConnectionOption {\n\treturn func(c *connection) {\n\t\tc.writer = buf.NewWriter(writer)\n\t}\n}\n\nfunc ConnectionInputMulti(writer buf.Writer) ConnectionOption {\n\treturn func(c *connection) {\n\t\tc.writer = writer\n\t}\n}\n\nfunc ConnectionOutput(reader io.Reader) ConnectionOption {\n\treturn func(c *connection) {\n\t\tc.reader = &buf.BufferedReader{Reader: buf.NewReader(reader)}\n\t}\n}\n\nfunc ConnectionOutputMulti(reader buf.Reader) ConnectionOption {\n\treturn func(c *connection) {\n\t\tc.reader = &buf.BufferedReader{Reader: reader}\n\t}\n}\n\nfunc ConnectionOutputMultiUDP(reader buf.Reader) ConnectionOption {\n\treturn func(c *connection) {\n\t\tc.reader = &buf.BufferedReader{\n\t\t\tReader:  reader,\n\t\t\tSpliter: buf.SplitFirstBytes,\n\t\t}\n\t}\n}\n\nfunc ConnectionOnClose(n io.Closer) ConnectionOption {\n\treturn func(c *connection) {\n\t\tc.onClose = n\n\t}\n}\n\nfunc NewConnection(opts ...ConnectionOption) net.Conn {\n\tc := &connection{\n\t\tdone: done.New(),\n\t\tlocal: &net.TCPAddr{\n\t\t\tIP:   []byte{0, 0, 0, 0},\n\t\t\tPort: 0,\n\t\t},\n\t\tremote: &net.TCPAddr{\n\t\t\tIP:   []byte{0, 0, 0, 0},\n\t\t\tPort: 0,\n\t\t},\n\t}\n\n\tfor _, opt := range opts {\n\t\topt(c)\n\t}\n\n\treturn c\n}\n\ntype connection struct {\n\treader  *buf.BufferedReader\n\twriter  buf.Writer\n\tdone    *done.Instance\n\tonClose io.Closer\n\tlocal   Addr\n\tremote  Addr\n}\n\nfunc (c *connection) Read(b []byte) (int, error) {\n\treturn c.reader.Read(b)\n}\n\n// ReadMultiBuffer implements buf.Reader.\nfunc (c *connection) ReadMultiBuffer() (buf.MultiBuffer, error) {\n\treturn c.reader.ReadMultiBuffer()\n}\n\n// Write implements net.Conn.Write().\nfunc (c *connection) Write(b []byte) (int, error) {\n\tif c.done.Done() {\n\t\treturn 0, io.ErrClosedPipe\n\t}\n\n\tl := len(b)\n\tmb := make(buf.MultiBuffer, 0, l/buf.Size+1)\n\tmb = buf.MergeBytes(mb, b)\n\treturn l, c.writer.WriteMultiBuffer(mb)\n}\n\nfunc (c *connection) WriteMultiBuffer(mb buf.MultiBuffer) error {\n\tif c.done.Done() {\n\t\tbuf.ReleaseMulti(mb)\n\t\treturn io.ErrClosedPipe\n\t}\n\n\treturn c.writer.WriteMultiBuffer(mb)\n}\n\n// Close implements net.Conn.Close().\nfunc (c *connection) Close() error {\n\tcommon.Must(c.done.Close())\n\tcommon.Interrupt(c.reader)\n\tcommon.Close(c.writer)\n\tif c.onClose != nil {\n\t\treturn c.onClose.Close()\n\t}\n\n\treturn nil\n}\n\n// LocalAddr implements net.Conn.LocalAddr().\nfunc (c *connection) LocalAddr() net.Addr {\n\treturn c.local\n}\n\n// RemoteAddr implements net.Conn.RemoteAddr().\nfunc (c *connection) RemoteAddr() net.Addr {\n\treturn c.remote\n}\n\n// SetDeadline implements net.Conn.SetDeadline().\nfunc (c *connection) SetDeadline(t time.Time) error {\n\treturn nil\n}\n\n// SetReadDeadline implements net.Conn.SetReadDeadline().\nfunc (c *connection) SetReadDeadline(t time.Time) error {\n\treturn nil\n}\n\n// SetWriteDeadline implements net.Conn.SetWriteDeadline().\nfunc (c *connection) SetWriteDeadline(t time.Time) error {\n\treturn nil\n}\n"
  },
  {
    "path": "common/net/destination.go",
    "content": "package net\n\nimport (\n\t\"net\"\n\t\"strings\"\n)\n\n// Destination represents a network destination including address and protocol (tcp / udp).\ntype Destination struct {\n\tAddress Address\n\tPort    Port\n\tNetwork Network\n}\n\n// DestinationFromAddr generates a Destination from a net address.\nfunc DestinationFromAddr(addr net.Addr) Destination {\n\tswitch addr := addr.(type) {\n\tcase *net.TCPAddr:\n\t\treturn TCPDestination(IPAddress(addr.IP), Port(addr.Port))\n\tcase *net.UDPAddr:\n\t\treturn UDPDestination(IPAddress(addr.IP), Port(addr.Port))\n\tcase *net.UnixAddr:\n\t\t// TODO: deal with Unix domain socket\n\t\treturn TCPDestination(LocalHostIP, Port(9))\n\tdefault:\n\t\tpanic(\"Net: Unknown address type.\")\n\t}\n}\n\n// ParseDestination converts a destination from its string presentation.\nfunc ParseDestination(dest string) (Destination, error) {\n\td := Destination{\n\t\tAddress: AnyIP,\n\t\tPort:    Port(0),\n\t}\n\tif strings.HasPrefix(dest, \"tcp:\") {\n\t\td.Network = Network_TCP\n\t\tdest = dest[4:]\n\t} else if strings.HasPrefix(dest, \"udp:\") {\n\t\td.Network = Network_UDP\n\t\tdest = dest[4:]\n\t}\n\n\thstr, pstr, err := SplitHostPort(dest)\n\tif err != nil {\n\t\treturn d, err\n\t}\n\tif len(hstr) > 0 {\n\t\td.Address = ParseAddress(hstr)\n\t}\n\tif len(pstr) > 0 {\n\t\tport, err := PortFromString(pstr)\n\t\tif err != nil {\n\t\t\treturn d, err\n\t\t}\n\t\td.Port = port\n\t}\n\treturn d, nil\n}\n\n// TCPDestination creates a TCP destination with given address\nfunc TCPDestination(address Address, port Port) Destination {\n\treturn Destination{\n\t\tNetwork: Network_TCP,\n\t\tAddress: address,\n\t\tPort:    port,\n\t}\n}\n\n// UDPDestination creates a UDP destination with given address\nfunc UDPDestination(address Address, port Port) Destination {\n\treturn Destination{\n\t\tNetwork: Network_UDP,\n\t\tAddress: address,\n\t\tPort:    port,\n\t}\n}\n\n// NetAddr returns the network address in this Destination in string form.\nfunc (d Destination) NetAddr() string {\n\treturn d.Address.String() + \":\" + d.Port.String()\n}\n\n// String returns the strings form of this Destination.\nfunc (d Destination) String() string {\n\tprefix := \"unknown:\"\n\tswitch d.Network {\n\tcase Network_TCP:\n\t\tprefix = \"tcp:\"\n\tcase Network_UDP:\n\t\tprefix = \"udp:\"\n\t}\n\treturn prefix + d.NetAddr()\n}\n\n// IsValid returns true if this Destination is valid.\nfunc (d Destination) IsValid() bool {\n\treturn d.Network != Network_Unknown\n}\n\n// AsDestination converts current Endpoint into Destination.\nfunc (p *Endpoint) AsDestination() Destination {\n\treturn Destination{\n\t\tNetwork: p.Network,\n\t\tAddress: p.Address.AsAddress(),\n\t\tPort:    Port(p.Port),\n\t}\n}\n"
  },
  {
    "path": "common/net/destination.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: common/net/destination.proto\n\npackage net\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\n// Endpoint of a network connection.\ntype Endpoint struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tNetwork Network     `protobuf:\"varint,1,opt,name=network,proto3,enum=v2ray.core.common.net.Network\" json:\"network,omitempty\"`\n\tAddress *IPOrDomain `protobuf:\"bytes,2,opt,name=address,proto3\" json:\"address,omitempty\"`\n\tPort    uint32      `protobuf:\"varint,3,opt,name=port,proto3\" json:\"port,omitempty\"`\n}\n\nfunc (x *Endpoint) Reset() {\n\t*x = Endpoint{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_common_net_destination_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Endpoint) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Endpoint) ProtoMessage() {}\n\nfunc (x *Endpoint) ProtoReflect() protoreflect.Message {\n\tmi := &file_common_net_destination_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Endpoint.ProtoReflect.Descriptor instead.\nfunc (*Endpoint) Descriptor() ([]byte, []int) {\n\treturn file_common_net_destination_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *Endpoint) GetNetwork() Network {\n\tif x != nil {\n\t\treturn x.Network\n\t}\n\treturn Network_Unknown\n}\n\nfunc (x *Endpoint) GetAddress() *IPOrDomain {\n\tif x != nil {\n\t\treturn x.Address\n\t}\n\treturn nil\n}\n\nfunc (x *Endpoint) GetPort() uint32 {\n\tif x != nil {\n\t\treturn x.Port\n\t}\n\treturn 0\n}\n\nvar File_common_net_destination_proto protoreflect.FileDescriptor\n\nvar file_common_net_destination_proto_rawDesc = []byte{\n\t0x0a, 0x1c, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x64, 0x65, 0x73,\n\t0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x15,\n\t0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,\n\t0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x1a, 0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65,\n\t0x74, 0x2f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a,\n\t0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x61, 0x64, 0x64, 0x72,\n\t0x65, 0x73, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x95, 0x01, 0x0a, 0x08, 0x45, 0x6e,\n\t0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x38, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72,\n\t0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,\n\t0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e,\n\t0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b,\n\t0x12, 0x3b, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28,\n\t0x0b, 0x32, 0x21, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63,\n\t0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f,\n\t0x6d, 0x61, 0x69, 0x6e, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a,\n\t0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72,\n\t0x74, 0x42, 0x50, 0x0a, 0x19, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,\n\t0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x50, 0x01,\n\t0x5a, 0x19, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65,\n\t0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0xaa, 0x02, 0x15, 0x56, 0x32,\n\t0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e,\n\t0x4e, 0x65, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_common_net_destination_proto_rawDescOnce sync.Once\n\tfile_common_net_destination_proto_rawDescData = file_common_net_destination_proto_rawDesc\n)\n\nfunc file_common_net_destination_proto_rawDescGZIP() []byte {\n\tfile_common_net_destination_proto_rawDescOnce.Do(func() {\n\t\tfile_common_net_destination_proto_rawDescData = protoimpl.X.CompressGZIP(file_common_net_destination_proto_rawDescData)\n\t})\n\treturn file_common_net_destination_proto_rawDescData\n}\n\nvar file_common_net_destination_proto_msgTypes = make([]protoimpl.MessageInfo, 1)\nvar file_common_net_destination_proto_goTypes = []interface{}{\n\t(*Endpoint)(nil),   // 0: v2ray.core.common.net.Endpoint\n\t(Network)(0),       // 1: v2ray.core.common.net.Network\n\t(*IPOrDomain)(nil), // 2: v2ray.core.common.net.IPOrDomain\n}\nvar file_common_net_destination_proto_depIdxs = []int32{\n\t1, // 0: v2ray.core.common.net.Endpoint.network:type_name -> v2ray.core.common.net.Network\n\t2, // 1: v2ray.core.common.net.Endpoint.address:type_name -> v2ray.core.common.net.IPOrDomain\n\t2, // [2:2] is the sub-list for method output_type\n\t2, // [2:2] is the sub-list for method input_type\n\t2, // [2:2] is the sub-list for extension type_name\n\t2, // [2:2] is the sub-list for extension extendee\n\t0, // [0:2] is the sub-list for field type_name\n}\n\nfunc init() { file_common_net_destination_proto_init() }\nfunc file_common_net_destination_proto_init() {\n\tif File_common_net_destination_proto != nil {\n\t\treturn\n\t}\n\tfile_common_net_network_proto_init()\n\tfile_common_net_address_proto_init()\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_common_net_destination_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Endpoint); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_common_net_destination_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   1,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_common_net_destination_proto_goTypes,\n\t\tDependencyIndexes: file_common_net_destination_proto_depIdxs,\n\t\tMessageInfos:      file_common_net_destination_proto_msgTypes,\n\t}.Build()\n\tFile_common_net_destination_proto = out.File\n\tfile_common_net_destination_proto_rawDesc = nil\n\tfile_common_net_destination_proto_goTypes = nil\n\tfile_common_net_destination_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "common/net/destination.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.common.net;\noption csharp_namespace = \"V2Ray.Core.Common.Net\";\noption go_package = \"v2ray.com/core/common/net\";\noption java_package = \"com.v2ray.core.common.net\";\noption java_multiple_files = true;\n\nimport \"common/net/network.proto\";\nimport \"common/net/address.proto\";\n\n// Endpoint of a network connection.\nmessage Endpoint {\n  Network network = 1;\n  IPOrDomain address = 2;\n  uint32 port = 3;\n}\n"
  },
  {
    "path": "common/net/destination_test.go",
    "content": "package net_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\n\t. \"v2ray.com/core/common/net\"\n)\n\nfunc TestDestinationProperty(t *testing.T) {\n\ttestCases := []struct {\n\t\tInput     Destination\n\t\tNetwork   Network\n\t\tString    string\n\t\tNetString string\n\t}{\n\t\t{\n\t\t\tInput:     TCPDestination(IPAddress([]byte{1, 2, 3, 4}), 80),\n\t\t\tNetwork:   Network_TCP,\n\t\t\tString:    \"tcp:1.2.3.4:80\",\n\t\t\tNetString: \"1.2.3.4:80\",\n\t\t},\n\t\t{\n\t\t\tInput:     UDPDestination(IPAddress([]byte{0x20, 0x01, 0x48, 0x60, 0x48, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x88}), 53),\n\t\t\tNetwork:   Network_UDP,\n\t\t\tString:    \"udp:[2001:4860:4860::8888]:53\",\n\t\t\tNetString: \"[2001:4860:4860::8888]:53\",\n\t\t},\n\t}\n\n\tfor _, testCase := range testCases {\n\t\tdest := testCase.Input\n\t\tif r := cmp.Diff(dest.Network, testCase.Network); r != \"\" {\n\t\t\tt.Error(\"unexpected Network in \", dest.String(), \": \", r)\n\t\t}\n\t\tif r := cmp.Diff(dest.String(), testCase.String); r != \"\" {\n\t\t\tt.Error(r)\n\t\t}\n\t\tif r := cmp.Diff(dest.NetAddr(), testCase.NetString); r != \"\" {\n\t\t\tt.Error(r)\n\t\t}\n\t}\n}\n\nfunc TestDestinationParse(t *testing.T) {\n\tcases := []struct {\n\t\tInput  string\n\t\tOutput Destination\n\t\tError  bool\n\t}{\n\t\t{\n\t\t\tInput:  \"tcp:127.0.0.1:80\",\n\t\t\tOutput: TCPDestination(LocalHostIP, Port(80)),\n\t\t},\n\t\t{\n\t\t\tInput:  \"udp:8.8.8.8:53\",\n\t\t\tOutput: UDPDestination(IPAddress([]byte{8, 8, 8, 8}), Port(53)),\n\t\t},\n\t\t{\n\t\t\tInput: \"8.8.8.8:53\",\n\t\t\tOutput: Destination{\n\t\t\t\tAddress: IPAddress([]byte{8, 8, 8, 8}),\n\t\t\t\tPort:    Port(53),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tInput: \":53\",\n\t\t\tOutput: Destination{\n\t\t\t\tAddress: AnyIP,\n\t\t\t\tPort:    Port(53),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tInput: \"8.8.8.8\",\n\t\t\tError: true,\n\t\t},\n\t\t{\n\t\t\tInput: \"8.8.8.8:http\",\n\t\t\tError: true,\n\t\t},\n\t}\n\n\tfor _, testcase := range cases {\n\t\td, err := ParseDestination(testcase.Input)\n\t\tif !testcase.Error {\n\t\t\tif err != nil {\n\t\t\t\tt.Error(\"for test case: \", testcase.Input, \" expected no error, but got \", err)\n\t\t\t}\n\t\t\tif d != testcase.Output {\n\t\t\t\tt.Error(\"for test case: \", testcase.Input, \" expected output: \", testcase.Output.String(), \" but got \", d.String())\n\t\t\t}\n\t\t} else {\n\t\t\tif err == nil {\n\t\t\t\tt.Error(\"for test case: \", testcase.Input, \" expected error, but got nil\")\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "common/net/errors.generated.go",
    "content": "package net\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "common/net/net.go",
    "content": "// Package net is a drop-in replacement to Golang's net package, with some more functionalities.\npackage net // import \"v2ray.com/core/common/net\"\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n"
  },
  {
    "path": "common/net/network.go",
    "content": "package net\n\nfunc (n Network) SystemString() string {\n\tswitch n {\n\tcase Network_TCP:\n\t\treturn \"tcp\"\n\tcase Network_UDP:\n\t\treturn \"udp\"\n\tdefault:\n\t\treturn \"unknown\"\n\t}\n}\n\n// HasNetwork returns true if the network list has a certain network.\nfunc HasNetwork(list []Network, network Network) bool {\n\tfor _, value := range list {\n\t\tif value == network {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "common/net/network.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: common/net/network.proto\n\npackage net\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype Network int32\n\nconst (\n\tNetwork_Unknown Network = 0\n\t// Deprecated: Do not use.\n\tNetwork_RawTCP Network = 1\n\tNetwork_TCP    Network = 2\n\tNetwork_UDP    Network = 3\n)\n\n// Enum value maps for Network.\nvar (\n\tNetwork_name = map[int32]string{\n\t\t0: \"Unknown\",\n\t\t1: \"RawTCP\",\n\t\t2: \"TCP\",\n\t\t3: \"UDP\",\n\t}\n\tNetwork_value = map[string]int32{\n\t\t\"Unknown\": 0,\n\t\t\"RawTCP\":  1,\n\t\t\"TCP\":     2,\n\t\t\"UDP\":     3,\n\t}\n)\n\nfunc (x Network) Enum() *Network {\n\tp := new(Network)\n\t*p = x\n\treturn p\n}\n\nfunc (x Network) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (Network) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_common_net_network_proto_enumTypes[0].Descriptor()\n}\n\nfunc (Network) Type() protoreflect.EnumType {\n\treturn &file_common_net_network_proto_enumTypes[0]\n}\n\nfunc (x Network) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use Network.Descriptor instead.\nfunc (Network) EnumDescriptor() ([]byte, []int) {\n\treturn file_common_net_network_proto_rawDescGZIP(), []int{0}\n}\n\n// NetworkList is a list of Networks.\ntype NetworkList struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tNetwork []Network `protobuf:\"varint,1,rep,packed,name=network,proto3,enum=v2ray.core.common.net.Network\" json:\"network,omitempty\"`\n}\n\nfunc (x *NetworkList) Reset() {\n\t*x = NetworkList{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_common_net_network_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *NetworkList) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*NetworkList) ProtoMessage() {}\n\nfunc (x *NetworkList) ProtoReflect() protoreflect.Message {\n\tmi := &file_common_net_network_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use NetworkList.ProtoReflect.Descriptor instead.\nfunc (*NetworkList) Descriptor() ([]byte, []int) {\n\treturn file_common_net_network_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *NetworkList) GetNetwork() []Network {\n\tif x != nil {\n\t\treturn x.Network\n\t}\n\treturn nil\n}\n\nvar File_common_net_network_proto protoreflect.FileDescriptor\n\nvar file_common_net_network_proto_rawDesc = []byte{\n\t0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x6e, 0x65, 0x74,\n\t0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x15, 0x76, 0x32, 0x72, 0x61,\n\t0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65,\n\t0x74, 0x22, 0x47, 0x0a, 0x0b, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4c, 0x69, 0x73, 0x74,\n\t0x12, 0x38, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x01, 0x20, 0x03, 0x28,\n\t0x0e, 0x32, 0x1e, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63,\n\t0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72,\n\t0x6b, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2a, 0x38, 0x0a, 0x07, 0x4e, 0x65,\n\t0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e,\n\t0x10, 0x00, 0x12, 0x0e, 0x0a, 0x06, 0x52, 0x61, 0x77, 0x54, 0x43, 0x50, 0x10, 0x01, 0x1a, 0x02,\n\t0x08, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x54, 0x43, 0x50, 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x55,\n\t0x44, 0x50, 0x10, 0x03, 0x42, 0x50, 0x0a, 0x19, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61,\n\t0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65,\n\t0x74, 0x50, 0x01, 0x5a, 0x19, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63,\n\t0x6f, 0x72, 0x65, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0xaa, 0x02,\n\t0x15, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x43, 0x6f, 0x6d, 0x6d,\n\t0x6f, 0x6e, 0x2e, 0x4e, 0x65, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_common_net_network_proto_rawDescOnce sync.Once\n\tfile_common_net_network_proto_rawDescData = file_common_net_network_proto_rawDesc\n)\n\nfunc file_common_net_network_proto_rawDescGZIP() []byte {\n\tfile_common_net_network_proto_rawDescOnce.Do(func() {\n\t\tfile_common_net_network_proto_rawDescData = protoimpl.X.CompressGZIP(file_common_net_network_proto_rawDescData)\n\t})\n\treturn file_common_net_network_proto_rawDescData\n}\n\nvar file_common_net_network_proto_enumTypes = make([]protoimpl.EnumInfo, 1)\nvar file_common_net_network_proto_msgTypes = make([]protoimpl.MessageInfo, 1)\nvar file_common_net_network_proto_goTypes = []interface{}{\n\t(Network)(0),        // 0: v2ray.core.common.net.Network\n\t(*NetworkList)(nil), // 1: v2ray.core.common.net.NetworkList\n}\nvar file_common_net_network_proto_depIdxs = []int32{\n\t0, // 0: v2ray.core.common.net.NetworkList.network:type_name -> v2ray.core.common.net.Network\n\t1, // [1:1] is the sub-list for method output_type\n\t1, // [1:1] is the sub-list for method input_type\n\t1, // [1:1] is the sub-list for extension type_name\n\t1, // [1:1] is the sub-list for extension extendee\n\t0, // [0:1] is the sub-list for field type_name\n}\n\nfunc init() { file_common_net_network_proto_init() }\nfunc file_common_net_network_proto_init() {\n\tif File_common_net_network_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_common_net_network_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*NetworkList); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_common_net_network_proto_rawDesc,\n\t\t\tNumEnums:      1,\n\t\t\tNumMessages:   1,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_common_net_network_proto_goTypes,\n\t\tDependencyIndexes: file_common_net_network_proto_depIdxs,\n\t\tEnumInfos:         file_common_net_network_proto_enumTypes,\n\t\tMessageInfos:      file_common_net_network_proto_msgTypes,\n\t}.Build()\n\tFile_common_net_network_proto = out.File\n\tfile_common_net_network_proto_rawDesc = nil\n\tfile_common_net_network_proto_goTypes = nil\n\tfile_common_net_network_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "common/net/network.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.common.net;\noption csharp_namespace = \"V2Ray.Core.Common.Net\";\noption go_package = \"v2ray.com/core/common/net\";\noption java_package = \"com.v2ray.core.common.net\";\noption java_multiple_files = true;\n\nenum Network {\n  Unknown = 0;\n\n  RawTCP = 1 [deprecated = true];\n  TCP = 2;\n  UDP = 3;\n}\n\n// NetworkList is a list of Networks.\nmessage NetworkList {\n  repeated Network network = 1;\n}\n"
  },
  {
    "path": "common/net/port.go",
    "content": "package net\n\nimport (\n\t\"encoding/binary\"\n\t\"strconv\"\n)\n\n// Port represents a network port in TCP and UDP protocol.\ntype Port uint16\n\n// PortFromBytes converts a byte array to a Port, assuming bytes are in big endian order.\n// @unsafe Caller must ensure that the byte array has at least 2 elements.\nfunc PortFromBytes(port []byte) Port {\n\treturn Port(binary.BigEndian.Uint16(port))\n}\n\n// PortFromInt converts an integer to a Port.\n// @error when the integer is not positive or larger then 65535\nfunc PortFromInt(val uint32) (Port, error) {\n\tif val > 65535 {\n\t\treturn Port(0), newError(\"invalid port range: \", val)\n\t}\n\treturn Port(val), nil\n}\n\n// PortFromString converts a string to a Port.\n// @error when the string is not an integer or the integral value is a not a valid Port.\nfunc PortFromString(s string) (Port, error) {\n\tval, err := strconv.ParseUint(s, 10, 32)\n\tif err != nil {\n\t\treturn Port(0), newError(\"invalid port range: \", s)\n\t}\n\treturn PortFromInt(uint32(val))\n}\n\n// Value return the corresponding uint16 value of a Port.\nfunc (p Port) Value() uint16 {\n\treturn uint16(p)\n}\n\n// String returns the string presentation of a Port.\nfunc (p Port) String() string {\n\treturn strconv.Itoa(int(p))\n}\n\n// FromPort returns the beginning port of this PortRange.\nfunc (p *PortRange) FromPort() Port {\n\treturn Port(p.From)\n}\n\n// ToPort returns the end port of this PortRange.\nfunc (p *PortRange) ToPort() Port {\n\treturn Port(p.To)\n}\n\n// Contains returns true if the given port is within the range of a PortRange.\nfunc (p *PortRange) Contains(port Port) bool {\n\treturn p.FromPort() <= port && port <= p.ToPort()\n}\n\n// SinglePortRange returns a PortRange contains a single port.\nfunc SinglePortRange(p Port) *PortRange {\n\treturn &PortRange{\n\t\tFrom: uint32(p),\n\t\tTo:   uint32(p),\n\t}\n}\n\ntype MemoryPortRange struct {\n\tFrom Port\n\tTo   Port\n}\n\nfunc (r MemoryPortRange) Contains(port Port) bool {\n\treturn r.From <= port && port <= r.To\n}\n\ntype MemoryPortList []MemoryPortRange\n\nfunc PortListFromProto(l *PortList) MemoryPortList {\n\tmpl := make(MemoryPortList, 0, len(l.Range))\n\tfor _, r := range l.Range {\n\t\tmpl = append(mpl, MemoryPortRange{From: Port(r.From), To: Port(r.To)})\n\t}\n\treturn mpl\n}\n\nfunc (mpl MemoryPortList) Contains(port Port) bool {\n\tfor _, pr := range mpl {\n\t\tif pr.Contains(port) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "common/net/port.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: common/net/port.proto\n\npackage net\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\n// PortRange represents a range of ports.\ntype PortRange struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// The port that this range starts from.\n\tFrom uint32 `protobuf:\"varint,1,opt,name=From,proto3\" json:\"From,omitempty\"`\n\t// The port that this range ends with (inclusive).\n\tTo uint32 `protobuf:\"varint,2,opt,name=To,proto3\" json:\"To,omitempty\"`\n}\n\nfunc (x *PortRange) Reset() {\n\t*x = PortRange{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_common_net_port_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *PortRange) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*PortRange) ProtoMessage() {}\n\nfunc (x *PortRange) ProtoReflect() protoreflect.Message {\n\tmi := &file_common_net_port_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use PortRange.ProtoReflect.Descriptor instead.\nfunc (*PortRange) Descriptor() ([]byte, []int) {\n\treturn file_common_net_port_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *PortRange) GetFrom() uint32 {\n\tif x != nil {\n\t\treturn x.From\n\t}\n\treturn 0\n}\n\nfunc (x *PortRange) GetTo() uint32 {\n\tif x != nil {\n\t\treturn x.To\n\t}\n\treturn 0\n}\n\n// PortList is a list of ports.\ntype PortList struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tRange []*PortRange `protobuf:\"bytes,1,rep,name=range,proto3\" json:\"range,omitempty\"`\n}\n\nfunc (x *PortList) Reset() {\n\t*x = PortList{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_common_net_port_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *PortList) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*PortList) ProtoMessage() {}\n\nfunc (x *PortList) ProtoReflect() protoreflect.Message {\n\tmi := &file_common_net_port_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use PortList.ProtoReflect.Descriptor instead.\nfunc (*PortList) Descriptor() ([]byte, []int) {\n\treturn file_common_net_port_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *PortList) GetRange() []*PortRange {\n\tif x != nil {\n\t\treturn x.Range\n\t}\n\treturn nil\n}\n\nvar File_common_net_port_proto protoreflect.FileDescriptor\n\nvar file_common_net_port_proto_rawDesc = []byte{\n\t0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x70, 0x6f, 0x72,\n\t0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x15, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,\n\t0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x22, 0x2f,\n\t0x0a, 0x09, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x46,\n\t0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x46, 0x72, 0x6f, 0x6d, 0x12,\n\t0x0e, 0x0a, 0x02, 0x54, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x02, 0x54, 0x6f, 0x22,\n\t0x42, 0x0a, 0x08, 0x50, 0x6f, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x36, 0x0a, 0x05, 0x72,\n\t0x61, 0x6e, 0x67, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x76, 0x32, 0x72,\n\t0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e,\n\t0x65, 0x74, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x05, 0x72, 0x61,\n\t0x6e, 0x67, 0x65, 0x42, 0x50, 0x0a, 0x19, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,\n\t0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74,\n\t0x50, 0x01, 0x5a, 0x19, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f,\n\t0x72, 0x65, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0xaa, 0x02, 0x15,\n\t0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f,\n\t0x6e, 0x2e, 0x4e, 0x65, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_common_net_port_proto_rawDescOnce sync.Once\n\tfile_common_net_port_proto_rawDescData = file_common_net_port_proto_rawDesc\n)\n\nfunc file_common_net_port_proto_rawDescGZIP() []byte {\n\tfile_common_net_port_proto_rawDescOnce.Do(func() {\n\t\tfile_common_net_port_proto_rawDescData = protoimpl.X.CompressGZIP(file_common_net_port_proto_rawDescData)\n\t})\n\treturn file_common_net_port_proto_rawDescData\n}\n\nvar file_common_net_port_proto_msgTypes = make([]protoimpl.MessageInfo, 2)\nvar file_common_net_port_proto_goTypes = []interface{}{\n\t(*PortRange)(nil), // 0: v2ray.core.common.net.PortRange\n\t(*PortList)(nil),  // 1: v2ray.core.common.net.PortList\n}\nvar file_common_net_port_proto_depIdxs = []int32{\n\t0, // 0: v2ray.core.common.net.PortList.range:type_name -> v2ray.core.common.net.PortRange\n\t1, // [1:1] is the sub-list for method output_type\n\t1, // [1:1] is the sub-list for method input_type\n\t1, // [1:1] is the sub-list for extension type_name\n\t1, // [1:1] is the sub-list for extension extendee\n\t0, // [0:1] is the sub-list for field type_name\n}\n\nfunc init() { file_common_net_port_proto_init() }\nfunc file_common_net_port_proto_init() {\n\tif File_common_net_port_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_common_net_port_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*PortRange); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_common_net_port_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*PortList); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_common_net_port_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   2,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_common_net_port_proto_goTypes,\n\t\tDependencyIndexes: file_common_net_port_proto_depIdxs,\n\t\tMessageInfos:      file_common_net_port_proto_msgTypes,\n\t}.Build()\n\tFile_common_net_port_proto = out.File\n\tfile_common_net_port_proto_rawDesc = nil\n\tfile_common_net_port_proto_goTypes = nil\n\tfile_common_net_port_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "common/net/port.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.common.net;\noption csharp_namespace = \"V2Ray.Core.Common.Net\";\noption go_package = \"v2ray.com/core/common/net\";\noption java_package = \"com.v2ray.core.common.net\";\noption java_multiple_files = true;\n\n// PortRange represents a range of ports.\nmessage PortRange {\n  // The port that this range starts from.\n  uint32 From = 1;\n  // The port that this range ends with (inclusive).\n  uint32 To = 2;\n}\n\n// PortList is a list of ports.\nmessage PortList {\n  repeated PortRange range = 1;\n}\n"
  },
  {
    "path": "common/net/port_test.go",
    "content": "package net_test\n\nimport (\n\t\"testing\"\n\n\t. \"v2ray.com/core/common/net\"\n)\n\nfunc TestPortRangeContains(t *testing.T) {\n\tportRange := &PortRange{\n\t\tFrom: 53,\n\t\tTo:   53,\n\t}\n\n\tif !portRange.Contains(Port(53)) {\n\t\tt.Error(\"expected port range containing 53, but actually not\")\n\t}\n}\n"
  },
  {
    "path": "common/net/system.go",
    "content": "package net\n\nimport \"net\"\n\n// DialTCP is an alias of net.DialTCP.\nvar DialTCP = net.DialTCP\nvar DialUDP = net.DialUDP\nvar DialUnix = net.DialUnix\nvar Dial = net.Dial\n\ntype ListenConfig = net.ListenConfig\n\nvar Listen = net.Listen\nvar ListenTCP = net.ListenTCP\nvar ListenUDP = net.ListenUDP\nvar ListenUnix = net.ListenUnix\n\nvar LookupIP = net.LookupIP\n\nvar FileConn = net.FileConn\n\n// ParseIP is an alias of net.ParseIP\nvar ParseIP = net.ParseIP\n\nvar SplitHostPort = net.SplitHostPort\n\nvar CIDRMask = net.CIDRMask\n\ntype Addr = net.Addr\ntype Conn = net.Conn\ntype PacketConn = net.PacketConn\n\ntype TCPAddr = net.TCPAddr\ntype TCPConn = net.TCPConn\n\ntype UDPAddr = net.UDPAddr\ntype UDPConn = net.UDPConn\n\ntype UnixAddr = net.UnixAddr\ntype UnixConn = net.UnixConn\n\n// IP is an alias for net.IP.\ntype IP = net.IP\ntype IPMask = net.IPMask\ntype IPNet = net.IPNet\n\nconst IPv4len = net.IPv4len\nconst IPv6len = net.IPv6len\n\ntype Error = net.Error\ntype AddrError = net.AddrError\n\ntype Dialer = net.Dialer\ntype Listener = net.Listener\ntype TCPListener = net.TCPListener\ntype UnixListener = net.UnixListener\n\nvar ResolveUnixAddr = net.ResolveUnixAddr\nvar ResolveUDPAddr = net.ResolveUDPAddr\n\ntype Resolver = net.Resolver\n"
  },
  {
    "path": "common/peer/latency.go",
    "content": "package peer\n\nimport (\n\t\"sync\"\n)\n\ntype Latency interface {\n\tValue() uint64\n}\n\ntype HasLatency interface {\n\tConnectionLatency() Latency\n\tHandshakeLatency() Latency\n}\n\ntype AverageLatency struct {\n\taccess sync.Mutex\n\tvalue  uint64\n}\n\nfunc (al *AverageLatency) Update(newValue uint64) {\n\tal.access.Lock()\n\tdefer al.access.Unlock()\n\n\tal.value = (al.value + newValue*2) / 3\n}\n\nfunc (al *AverageLatency) Value() uint64 {\n\treturn al.value\n}\n"
  },
  {
    "path": "common/peer/peer.go",
    "content": "package peer\n"
  },
  {
    "path": "common/platform/ctlcmd/attr_other.go",
    "content": "// +build !windows\n\npackage ctlcmd\n\nimport \"syscall\"\n\nfunc getSysProcAttr() *syscall.SysProcAttr {\n\treturn nil\n}\n"
  },
  {
    "path": "common/platform/ctlcmd/attr_windows.go",
    "content": "// +build windows\n\npackage ctlcmd\n\nimport \"syscall\"\n\nfunc getSysProcAttr() *syscall.SysProcAttr {\n\treturn &syscall.SysProcAttr{\n\t\tHideWindow: true,\n\t}\n}\n"
  },
  {
    "path": "common/platform/ctlcmd/ctlcmd.go",
    "content": "package ctlcmd\n\nimport (\n\t\"io\"\n\t\"os\"\n\t\"os/exec\"\n\t\"strings\"\n\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/platform\"\n)\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n\nfunc Run(args []string, input io.Reader) (buf.MultiBuffer, error) {\n\tv2ctl := platform.GetToolLocation(\"v2ctl\")\n\tif _, err := os.Stat(v2ctl); err != nil {\n\t\treturn nil, newError(\"v2ctl doesn't exist\").Base(err)\n\t}\n\n\tvar errBuffer buf.MultiBufferContainer\n\tvar outBuffer buf.MultiBufferContainer\n\n\tcmd := exec.Command(v2ctl, args...)\n\tcmd.Stderr = &errBuffer\n\tcmd.Stdout = &outBuffer\n\tcmd.SysProcAttr = getSysProcAttr()\n\tif input != nil {\n\t\tcmd.Stdin = input\n\t}\n\n\tif err := cmd.Start(); err != nil {\n\t\treturn nil, newError(\"failed to start v2ctl\").Base(err)\n\t}\n\n\tif err := cmd.Wait(); err != nil {\n\t\tmsg := \"failed to execute v2ctl\"\n\t\tif errBuffer.Len() > 0 {\n\t\t\tmsg += \": \\n\" + strings.TrimSpace(errBuffer.MultiBuffer.String())\n\t\t}\n\t\treturn nil, newError(msg).Base(err)\n\t}\n\n\t// log stderr, info message\n\tif !errBuffer.IsEmpty() {\n\t\tnewError(\"<v2ctl message> \\n\", strings.TrimSpace(errBuffer.MultiBuffer.String())).AtInfo().WriteToLog()\n\t}\n\n\treturn outBuffer.MultiBuffer, nil\n}\n"
  },
  {
    "path": "common/platform/ctlcmd/errors.generated.go",
    "content": "package ctlcmd\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "common/platform/filesystem/file.go",
    "content": "package filesystem\n\nimport (\n\t\"io\"\n\t\"os\"\n\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/platform\"\n)\n\ntype FileReaderFunc func(path string) (io.ReadCloser, error)\n\nvar NewFileReader FileReaderFunc = func(path string) (io.ReadCloser, error) {\n\treturn os.Open(path)\n}\n\nfunc ReadFile(path string) ([]byte, error) {\n\treader, err := NewFileReader(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer reader.Close()\n\n\treturn buf.ReadAllToBytes(reader)\n}\n\nfunc ReadAsset(file string) ([]byte, error) {\n\treturn ReadFile(platform.GetAssetLocation(file))\n}\n\nfunc CopyFile(dst string, src string) error {\n\tbytes, err := ReadFile(src)\n\tif err != nil {\n\t\treturn err\n\t}\n\tf, err := os.OpenFile(dst, os.O_CREATE|os.O_WRONLY, 0644)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer f.Close()\n\n\t_, err = f.Write(bytes)\n\treturn err\n}\n"
  },
  {
    "path": "common/platform/others.go",
    "content": "// +build !windows\n\npackage platform\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n)\n\nfunc ExpandEnv(s string) string {\n\treturn os.ExpandEnv(s)\n}\n\nfunc LineSeparator() string {\n\treturn \"\\n\"\n}\n\nfunc GetToolLocation(file string) string {\n\tconst name = \"v2ray.location.tool\"\n\ttoolPath := EnvFlag{Name: name, AltName: NormalizeEnvName(name)}.GetValue(getExecutableDir)\n\treturn filepath.Join(toolPath, file)\n}\n\n// GetAssetLocation search for `file` in certain locations\nfunc GetAssetLocation(file string) string {\n\tconst name = \"v2ray.location.asset\"\n\tassetPath := NewEnvFlag(name).GetValue(getExecutableDir)\n\tdefPath := filepath.Join(assetPath, file)\n\tfor _, p := range []string{\n\t\tdefPath,\n\t\tfilepath.Join(\"/usr/local/share/v2ray/\", file),\n\t\tfilepath.Join(\"/usr/share/v2ray/\", file),\n\t} {\n\t\tif _, err := os.Stat(p); os.IsNotExist(err) {\n\t\t\tcontinue\n\t\t}\n\n\t\t// asset found\n\t\treturn p\n\t}\n\n\t// asset not found, let the caller throw out the error\n\treturn defPath\n}\n"
  },
  {
    "path": "common/platform/platform.go",
    "content": "package platform // import \"v2ray.com/core/common/platform\"\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n)\n\ntype EnvFlag struct {\n\tName    string\n\tAltName string\n}\n\nfunc NewEnvFlag(name string) EnvFlag {\n\treturn EnvFlag{\n\t\tName:    name,\n\t\tAltName: NormalizeEnvName(name),\n\t}\n}\n\nfunc (f EnvFlag) GetValue(defaultValue func() string) string {\n\tif v, found := os.LookupEnv(f.Name); found {\n\t\treturn v\n\t}\n\tif len(f.AltName) > 0 {\n\t\tif v, found := os.LookupEnv(f.AltName); found {\n\t\t\treturn v\n\t\t}\n\t}\n\n\treturn defaultValue()\n}\n\nfunc (f EnvFlag) GetValueAsInt(defaultValue int) int {\n\tuseDefaultValue := false\n\ts := f.GetValue(func() string {\n\t\tuseDefaultValue = true\n\t\treturn \"\"\n\t})\n\tif useDefaultValue {\n\t\treturn defaultValue\n\t}\n\tv, err := strconv.ParseInt(s, 10, 32)\n\tif err != nil {\n\t\treturn defaultValue\n\t}\n\treturn int(v)\n}\n\nfunc NormalizeEnvName(name string) string {\n\treturn strings.Replace(strings.ToUpper(strings.TrimSpace(name)), \".\", \"_\", -1)\n}\n\nfunc getExecutableDir() string {\n\texec, err := os.Executable()\n\tif err != nil {\n\t\treturn \"\"\n\t}\n\treturn filepath.Dir(exec)\n}\n\nfunc getExecutableSubDir(dir string) func() string {\n\treturn func() string {\n\t\treturn filepath.Join(getExecutableDir(), dir)\n\t}\n}\n\nfunc GetPluginDirectory() string {\n\tconst name = \"v2ray.location.plugin\"\n\tpluginDir := NewEnvFlag(name).GetValue(getExecutableSubDir(\"plugins\"))\n\treturn pluginDir\n}\n\nfunc GetConfigurationPath() string {\n\tconst name = \"v2ray.location.config\"\n\tconfigPath := NewEnvFlag(name).GetValue(getExecutableDir)\n\treturn filepath.Join(configPath, \"config.json\")\n}\n\n// GetConfDirPath reads \"v2ray.location.confdir\"\nfunc GetConfDirPath() string {\n\tconst name = \"v2ray.location.confdir\"\n\tconfigPath := NewEnvFlag(name).GetValue(func() string { return \"\" })\n\treturn configPath\n}\n"
  },
  {
    "path": "common/platform/platform_test.go",
    "content": "package platform_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"testing\"\n\n\t\"v2ray.com/core/common\"\n\t. \"v2ray.com/core/common/platform\"\n)\n\nfunc TestNormalizeEnvName(t *testing.T) {\n\tcases := []struct {\n\t\tinput  string\n\t\toutput string\n\t}{\n\t\t{\n\t\t\tinput:  \"a\",\n\t\t\toutput: \"A\",\n\t\t},\n\t\t{\n\t\t\tinput:  \"a.a\",\n\t\t\toutput: \"A_A\",\n\t\t},\n\t\t{\n\t\t\tinput:  \"A.A.B\",\n\t\t\toutput: \"A_A_B\",\n\t\t},\n\t}\n\tfor _, test := range cases {\n\t\tif v := NormalizeEnvName(test.input); v != test.output {\n\t\t\tt.Error(\"unexpected output: \", v, \" want \", test.output)\n\t\t}\n\t}\n}\n\nfunc TestEnvFlag(t *testing.T) {\n\tif v := (EnvFlag{\n\t\tName: \"xxxxx.y\",\n\t}.GetValueAsInt(10)); v != 10 {\n\t\tt.Error(\"env value: \", v)\n\t}\n}\n\nfunc TestGetAssetLocation(t *testing.T) {\n\texec, err := os.Executable()\n\tcommon.Must(err)\n\n\tloc := GetAssetLocation(\"t\")\n\tif filepath.Dir(loc) != filepath.Dir(exec) {\n\t\tt.Error(\"asset dir: \", loc, \" not in \", exec)\n\t}\n\n\tos.Setenv(\"v2ray.location.asset\", \"/v2ray\")\n\tif runtime.GOOS == \"windows\" {\n\t\tif v := GetAssetLocation(\"t\"); v != \"\\\\v2ray\\\\t\" {\n\t\t\tt.Error(\"asset loc: \", v)\n\t\t}\n\t} else {\n\t\tif v := GetAssetLocation(\"t\"); v != \"/v2ray/t\" {\n\t\t\tt.Error(\"asset loc: \", v)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "common/platform/windows.go",
    "content": "// +build windows\n\npackage platform\n\nimport \"path/filepath\"\n\nfunc ExpandEnv(s string) string {\n\t// TODO\n\treturn s\n}\n\nfunc LineSeparator() string {\n\treturn \"\\r\\n\"\n}\n\nfunc GetToolLocation(file string) string {\n\tconst name = \"v2ray.location.tool\"\n\ttoolPath := EnvFlag{Name: name, AltName: NormalizeEnvName(name)}.GetValue(getExecutableDir)\n\treturn filepath.Join(toolPath, file+\".exe\")\n}\n\n// GetAssetLocation search for `file` in the excutable dir\nfunc GetAssetLocation(file string) string {\n\tconst name = \"v2ray.location.asset\"\n\tassetPath := NewEnvFlag(name).GetValue(getExecutableDir)\n\treturn filepath.Join(assetPath, file)\n}\n"
  },
  {
    "path": "common/protocol/account.go",
    "content": "package protocol\n\n// Account is a user identity used for authentication.\ntype Account interface {\n\tEquals(Account) bool\n}\n\n// AsAccount is an object can be converted into account.\ntype AsAccount interface {\n\tAsAccount() (Account, error)\n}\n"
  },
  {
    "path": "common/protocol/address.go",
    "content": "package protocol\n\nimport (\n\t\"io\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/serial\"\n)\n\ntype AddressOption func(*option)\n\nfunc PortThenAddress() AddressOption {\n\treturn func(p *option) {\n\t\tp.portFirst = true\n\t}\n}\n\nfunc AddressFamilyByte(b byte, f net.AddressFamily) AddressOption {\n\tif b >= 16 {\n\t\tpanic(\"address family byte too big\")\n\t}\n\treturn func(p *option) {\n\t\tp.addrTypeMap[b] = f\n\t\tp.addrByteMap[f] = b\n\t}\n}\n\ntype AddressTypeParser func(byte) byte\n\nfunc WithAddressTypeParser(atp AddressTypeParser) AddressOption {\n\treturn func(p *option) {\n\t\tp.typeParser = atp\n\t}\n}\n\ntype AddressSerializer interface {\n\tReadAddressPort(buffer *buf.Buffer, input io.Reader) (net.Address, net.Port, error)\n\n\tWriteAddressPort(writer io.Writer, addr net.Address, port net.Port) error\n}\n\nconst afInvalid = 255\n\ntype option struct {\n\taddrTypeMap [16]net.AddressFamily\n\taddrByteMap [16]byte\n\tportFirst   bool\n\ttypeParser  AddressTypeParser\n}\n\n// NewAddressParser creates a new AddressParser\nfunc NewAddressParser(options ...AddressOption) AddressSerializer {\n\tvar o option\n\tfor i := range o.addrByteMap {\n\t\to.addrByteMap[i] = afInvalid\n\t}\n\tfor i := range o.addrTypeMap {\n\t\to.addrTypeMap[i] = net.AddressFamily(afInvalid)\n\t}\n\tfor _, opt := range options {\n\t\topt(&o)\n\t}\n\n\tap := &addressParser{\n\t\taddrByteMap: o.addrByteMap,\n\t\taddrTypeMap: o.addrTypeMap,\n\t}\n\n\tif o.typeParser != nil {\n\t\tap.typeParser = o.typeParser\n\t}\n\n\tif o.portFirst {\n\t\treturn portFirstAddressParser{ap: ap}\n\t}\n\n\treturn portLastAddressParser{ap: ap}\n}\n\ntype portFirstAddressParser struct {\n\tap *addressParser\n}\n\nfunc (p portFirstAddressParser) ReadAddressPort(buffer *buf.Buffer, input io.Reader) (net.Address, net.Port, error) {\n\tif buffer == nil {\n\t\tbuffer = buf.New()\n\t\tdefer buffer.Release()\n\t}\n\n\tport, err := readPort(buffer, input)\n\tif err != nil {\n\t\treturn nil, 0, err\n\t}\n\n\taddr, err := p.ap.readAddress(buffer, input)\n\tif err != nil {\n\t\treturn nil, 0, err\n\t}\n\treturn addr, port, nil\n}\n\nfunc (p portFirstAddressParser) WriteAddressPort(writer io.Writer, addr net.Address, port net.Port) error {\n\tif err := writePort(writer, port); err != nil {\n\t\treturn err\n\t}\n\n\treturn p.ap.writeAddress(writer, addr)\n}\n\ntype portLastAddressParser struct {\n\tap *addressParser\n}\n\nfunc (p portLastAddressParser) ReadAddressPort(buffer *buf.Buffer, input io.Reader) (net.Address, net.Port, error) {\n\tif buffer == nil {\n\t\tbuffer = buf.New()\n\t\tdefer buffer.Release()\n\t}\n\n\taddr, err := p.ap.readAddress(buffer, input)\n\tif err != nil {\n\t\treturn nil, 0, err\n\t}\n\n\tport, err := readPort(buffer, input)\n\tif err != nil {\n\t\treturn nil, 0, err\n\t}\n\n\treturn addr, port, nil\n}\n\nfunc (p portLastAddressParser) WriteAddressPort(writer io.Writer, addr net.Address, port net.Port) error {\n\tif err := p.ap.writeAddress(writer, addr); err != nil {\n\t\treturn err\n\t}\n\n\treturn writePort(writer, port)\n}\n\nfunc readPort(b *buf.Buffer, reader io.Reader) (net.Port, error) {\n\tif _, err := b.ReadFullFrom(reader, 2); err != nil {\n\t\treturn 0, err\n\t}\n\treturn net.PortFromBytes(b.BytesFrom(-2)), nil\n}\n\nfunc writePort(writer io.Writer, port net.Port) error {\n\treturn common.Error2(serial.WriteUint16(writer, port.Value()))\n}\n\nfunc maybeIPPrefix(b byte) bool {\n\treturn b == '[' || (b >= '0' && b <= '9')\n}\n\nfunc isValidDomain(d string) bool {\n\tfor _, c := range d {\n\t\tif !((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '-' || c == '.' || c == '_') {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\ntype addressParser struct {\n\taddrTypeMap [16]net.AddressFamily\n\taddrByteMap [16]byte\n\ttypeParser  AddressTypeParser\n}\n\nfunc (p *addressParser) readAddress(b *buf.Buffer, reader io.Reader) (net.Address, error) {\n\tif _, err := b.ReadFullFrom(reader, 1); err != nil {\n\t\treturn nil, err\n\t}\n\n\taddrType := b.Byte(b.Len() - 1)\n\tif p.typeParser != nil {\n\t\taddrType = p.typeParser(addrType)\n\t}\n\n\tif addrType >= 16 {\n\t\treturn nil, newError(\"unknown address type: \", addrType)\n\t}\n\n\taddrFamily := p.addrTypeMap[addrType]\n\tif addrFamily == net.AddressFamily(afInvalid) {\n\t\treturn nil, newError(\"unknown address type: \", addrType)\n\t}\n\n\tswitch addrFamily {\n\tcase net.AddressFamilyIPv4:\n\t\tif _, err := b.ReadFullFrom(reader, 4); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn net.IPAddress(b.BytesFrom(-4)), nil\n\tcase net.AddressFamilyIPv6:\n\t\tif _, err := b.ReadFullFrom(reader, 16); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn net.IPAddress(b.BytesFrom(-16)), nil\n\tcase net.AddressFamilyDomain:\n\t\tif _, err := b.ReadFullFrom(reader, 1); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tdomainLength := int32(b.Byte(b.Len() - 1))\n\t\tif _, err := b.ReadFullFrom(reader, domainLength); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tdomain := string(b.BytesFrom(-domainLength))\n\t\tif maybeIPPrefix(domain[0]) {\n\t\t\taddr := net.ParseAddress(domain)\n\t\t\tif addr.Family().IsIP() {\n\t\t\t\treturn addr, nil\n\t\t\t}\n\t\t}\n\t\tif !isValidDomain(domain) {\n\t\t\treturn nil, newError(\"invalid domain name: \", domain)\n\t\t}\n\t\treturn net.DomainAddress(domain), nil\n\tdefault:\n\t\tpanic(\"impossible case\")\n\t}\n}\n\nfunc (p *addressParser) writeAddress(writer io.Writer, address net.Address) error {\n\ttb := p.addrByteMap[address.Family()]\n\tif tb == afInvalid {\n\t\treturn newError(\"unknown address family\", address.Family())\n\t}\n\n\tswitch address.Family() {\n\tcase net.AddressFamilyIPv4, net.AddressFamilyIPv6:\n\t\tif _, err := writer.Write([]byte{tb}); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif _, err := writer.Write(address.IP()); err != nil {\n\t\t\treturn err\n\t\t}\n\tcase net.AddressFamilyDomain:\n\t\tdomain := address.Domain()\n\t\tif isDomainTooLong(domain) {\n\t\t\treturn newError(\"Super long domain is not supported: \", domain)\n\t\t}\n\n\t\tif _, err := writer.Write([]byte{tb, byte(len(domain))}); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif _, err := writer.Write([]byte(domain)); err != nil {\n\t\t\treturn err\n\t\t}\n\tdefault:\n\t\tpanic(\"Unknown family type.\")\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "common/protocol/address_test.go",
    "content": "package protocol_test\n\nimport (\n\t\"bytes\"\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/net\"\n\t. \"v2ray.com/core/common/protocol\"\n)\n\nfunc TestAddressReading(t *testing.T) {\n\tdata := []struct {\n\t\tOptions []AddressOption\n\t\tInput   []byte\n\t\tAddress net.Address\n\t\tPort    net.Port\n\t\tError   bool\n\t}{\n\t\t{\n\t\t\tOptions: []AddressOption{},\n\t\t\tInput:   []byte{},\n\t\t\tError:   true,\n\t\t},\n\t\t{\n\t\t\tOptions: []AddressOption{},\n\t\t\tInput:   []byte{0, 0, 0, 0, 0},\n\t\t\tError:   true,\n\t\t},\n\t\t{\n\t\t\tOptions: []AddressOption{AddressFamilyByte(0x01, net.AddressFamilyIPv4)},\n\t\t\tInput:   []byte{1, 0, 0, 0, 0, 0, 53},\n\t\t\tAddress: net.IPAddress([]byte{0, 0, 0, 0}),\n\t\t\tPort:    net.Port(53),\n\t\t},\n\t\t{\n\t\t\tOptions: []AddressOption{AddressFamilyByte(0x01, net.AddressFamilyIPv4), PortThenAddress()},\n\t\t\tInput:   []byte{0, 53, 1, 0, 0, 0, 0},\n\t\t\tAddress: net.IPAddress([]byte{0, 0, 0, 0}),\n\t\t\tPort:    net.Port(53),\n\t\t},\n\t\t{\n\t\t\tOptions: []AddressOption{AddressFamilyByte(0x01, net.AddressFamilyIPv4)},\n\t\t\tInput:   []byte{1, 0, 0, 0, 0},\n\t\t\tError:   true,\n\t\t},\n\t\t{\n\t\t\tOptions: []AddressOption{AddressFamilyByte(0x04, net.AddressFamilyIPv6)},\n\t\t\tInput:   []byte{4, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 0, 80},\n\t\t\tAddress: net.IPAddress([]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6}),\n\t\t\tPort:    net.Port(80),\n\t\t},\n\t\t{\n\t\t\tOptions: []AddressOption{AddressFamilyByte(0x03, net.AddressFamilyDomain)},\n\t\t\tInput:   []byte{3, 9, 118, 50, 114, 97, 121, 46, 99, 111, 109, 0, 80},\n\t\t\tAddress: net.DomainAddress(\"v2ray.com\"),\n\t\t\tPort:    net.Port(80),\n\t\t},\n\t\t{\n\t\t\tOptions: []AddressOption{AddressFamilyByte(0x03, net.AddressFamilyDomain)},\n\t\t\tInput:   []byte{3, 9, 118, 50, 114, 97, 121, 46, 99, 111, 109, 0},\n\t\t\tError:   true,\n\t\t},\n\t\t{\n\t\t\tOptions: []AddressOption{AddressFamilyByte(0x03, net.AddressFamilyDomain)},\n\t\t\tInput:   []byte{3, 7, 56, 46, 56, 46, 56, 46, 56, 0, 80},\n\t\t\tAddress: net.ParseAddress(\"8.8.8.8\"),\n\t\t\tPort:    net.Port(80),\n\t\t},\n\t\t{\n\t\t\tOptions: []AddressOption{AddressFamilyByte(0x03, net.AddressFamilyDomain)},\n\t\t\tInput:   []byte{3, 7, 10, 46, 56, 46, 56, 46, 56, 0, 80},\n\t\t\tError:   true,\n\t\t},\n\t\t{\n\t\t\tOptions: []AddressOption{AddressFamilyByte(0x03, net.AddressFamilyDomain)},\n\t\t\tInput:   append(append([]byte{3, 24}, []byte(\"2a00:1450:4007:816::200e\")...), 0, 80),\n\t\t\tAddress: net.ParseAddress(\"2a00:1450:4007:816::200e\"),\n\t\t\tPort:    net.Port(80),\n\t\t},\n\t}\n\n\tfor _, tc := range data {\n\t\tb := buf.New()\n\t\tparser := NewAddressParser(tc.Options...)\n\t\taddr, port, err := parser.ReadAddressPort(b, bytes.NewReader(tc.Input))\n\t\tb.Release()\n\t\tif tc.Error {\n\t\t\tif err == nil {\n\t\t\t\tt.Errorf(\"Expect error but not: %v\", tc)\n\t\t\t}\n\t\t} else {\n\t\t\tif err != nil {\n\t\t\t\tt.Errorf(\"Expect no error but: %s %v\", err.Error(), tc)\n\t\t\t}\n\n\t\t\tif addr != tc.Address {\n\t\t\t\tt.Error(\"Got address \", addr.String(), \" want \", tc.Address.String())\n\t\t\t}\n\n\t\t\tif tc.Port != port {\n\t\t\t\tt.Error(\"Got port \", port, \" want \", tc.Port)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc TestAddressWriting(t *testing.T) {\n\tdata := []struct {\n\t\tOptions []AddressOption\n\t\tAddress net.Address\n\t\tPort    net.Port\n\t\tBytes   []byte\n\t\tError   bool\n\t}{\n\t\t{\n\t\t\tOptions: []AddressOption{AddressFamilyByte(0x01, net.AddressFamilyIPv4)},\n\t\t\tAddress: net.LocalHostIP,\n\t\t\tPort:    net.Port(80),\n\t\t\tBytes:   []byte{1, 127, 0, 0, 1, 0, 80},\n\t\t},\n\t}\n\n\tfor _, tc := range data {\n\t\tparser := NewAddressParser(tc.Options...)\n\n\t\tb := buf.New()\n\t\terr := parser.WriteAddressPort(b, tc.Address, tc.Port)\n\t\tif tc.Error {\n\t\t\tif err == nil {\n\t\t\t\tt.Error(\"Expect error but nil\")\n\t\t\t}\n\t\t} else {\n\t\t\tcommon.Must(err)\n\t\t\tif diff := cmp.Diff(tc.Bytes, b.Bytes()); diff != \"\" {\n\t\t\t\tt.Error(err)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc BenchmarkAddressReadingIPv4(b *testing.B) {\n\tparser := NewAddressParser(AddressFamilyByte(0x01, net.AddressFamilyIPv4))\n\tcache := buf.New()\n\tdefer cache.Release()\n\n\tpayload := buf.New()\n\tdefer payload.Release()\n\n\traw := []byte{1, 0, 0, 0, 0, 0, 53}\n\tpayload.Write(raw)\n\n\tb.ResetTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\t_, _, err := parser.ReadAddressPort(cache, payload)\n\t\tcommon.Must(err)\n\t\tcache.Clear()\n\t\tpayload.Clear()\n\t\tpayload.Extend(int32(len(raw)))\n\t}\n}\n\nfunc BenchmarkAddressReadingIPv6(b *testing.B) {\n\tparser := NewAddressParser(AddressFamilyByte(0x04, net.AddressFamilyIPv6))\n\tcache := buf.New()\n\tdefer cache.Release()\n\n\tpayload := buf.New()\n\tdefer payload.Release()\n\n\traw := []byte{4, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 0, 80}\n\tpayload.Write(raw)\n\n\tb.ResetTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\t_, _, err := parser.ReadAddressPort(cache, payload)\n\t\tcommon.Must(err)\n\t\tcache.Clear()\n\t\tpayload.Clear()\n\t\tpayload.Extend(int32(len(raw)))\n\t}\n}\n\nfunc BenchmarkAddressReadingDomain(b *testing.B) {\n\tparser := NewAddressParser(AddressFamilyByte(0x03, net.AddressFamilyDomain))\n\tcache := buf.New()\n\tdefer cache.Release()\n\n\tpayload := buf.New()\n\tdefer payload.Release()\n\n\traw := []byte{3, 9, 118, 50, 114, 97, 121, 46, 99, 111, 109, 0, 80}\n\tpayload.Write(raw)\n\n\tb.ResetTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\t_, _, err := parser.ReadAddressPort(cache, payload)\n\t\tcommon.Must(err)\n\t\tcache.Clear()\n\t\tpayload.Clear()\n\t\tpayload.Extend(int32(len(raw)))\n\t}\n}\n\nfunc BenchmarkAddressWritingIPv4(b *testing.B) {\n\tparser := NewAddressParser(AddressFamilyByte(0x01, net.AddressFamilyIPv4))\n\twriter := buf.New()\n\tdefer writer.Release()\n\n\tb.ResetTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\tcommon.Must(parser.WriteAddressPort(writer, net.LocalHostIP, net.Port(80)))\n\t\twriter.Clear()\n\t}\n}\n\nfunc BenchmarkAddressWritingIPv6(b *testing.B) {\n\tparser := NewAddressParser(AddressFamilyByte(0x04, net.AddressFamilyIPv6))\n\twriter := buf.New()\n\tdefer writer.Release()\n\n\tb.ResetTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\tcommon.Must(parser.WriteAddressPort(writer, net.LocalHostIPv6, net.Port(80)))\n\t\twriter.Clear()\n\t}\n}\n\nfunc BenchmarkAddressWritingDomain(b *testing.B) {\n\tparser := NewAddressParser(AddressFamilyByte(0x02, net.AddressFamilyDomain))\n\twriter := buf.New()\n\tdefer writer.Release()\n\n\tb.ResetTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\tcommon.Must(parser.WriteAddressPort(writer, net.DomainAddress(\"www.v2ray.com\"), net.Port(80)))\n\t\twriter.Clear()\n\t}\n}\n"
  },
  {
    "path": "common/protocol/bittorrent/bittorrent.go",
    "content": "package bittorrent\n\nimport (\n\t\"errors\"\n\n\t\"v2ray.com/core/common\"\n)\n\ntype SniffHeader struct {\n}\n\nfunc (h *SniffHeader) Protocol() string {\n\treturn \"bittorrent\"\n}\n\nfunc (h *SniffHeader) Domain() string {\n\treturn \"\"\n}\n\nvar errNotBittorrent = errors.New(\"not bittorrent header\")\n\nfunc SniffBittorrent(b []byte) (*SniffHeader, error) {\n\tif len(b) < 20 {\n\t\treturn nil, common.ErrNoClue\n\t}\n\n\tif b[0] == 19 && string(b[1:20]) == \"BitTorrent protocol\" {\n\t\treturn &SniffHeader{}, nil\n\t}\n\n\treturn nil, errNotBittorrent\n}\n"
  },
  {
    "path": "common/protocol/context.go",
    "content": "package protocol\n\nimport (\n\t\"context\"\n)\n\ntype key int\n\nconst (\n\trequestKey key = iota\n)\n\nfunc ContextWithRequestHeader(ctx context.Context, request *RequestHeader) context.Context {\n\treturn context.WithValue(ctx, requestKey, request)\n}\n\nfunc RequestHeaderFromContext(ctx context.Context) *RequestHeader {\n\trequest := ctx.Value(requestKey)\n\tif request == nil {\n\t\treturn nil\n\t}\n\treturn request.(*RequestHeader)\n}\n"
  },
  {
    "path": "common/protocol/dns/errors.generated.go",
    "content": "package dns\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "common/protocol/dns/io.go",
    "content": "package dns\n\nimport (\n\t\"encoding/binary\"\n\t\"sync\"\n\n\t\"golang.org/x/net/dns/dnsmessage\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/serial\"\n)\n\nfunc PackMessage(msg *dnsmessage.Message) (*buf.Buffer, error) {\n\tbuffer := buf.New()\n\trawBytes := buffer.Extend(buf.Size)\n\tpacked, err := msg.AppendPack(rawBytes[:0])\n\tif err != nil {\n\t\tbuffer.Release()\n\t\treturn nil, err\n\t}\n\tbuffer.Resize(0, int32(len(packed)))\n\treturn buffer, nil\n}\n\ntype MessageReader interface {\n\tReadMessage() (*buf.Buffer, error)\n}\n\ntype UDPReader struct {\n\tbuf.Reader\n\n\taccess sync.Mutex\n\tcache  buf.MultiBuffer\n}\n\nfunc (r *UDPReader) readCache() *buf.Buffer {\n\tr.access.Lock()\n\tdefer r.access.Unlock()\n\n\tmb, b := buf.SplitFirst(r.cache)\n\tr.cache = mb\n\treturn b\n}\n\nfunc (r *UDPReader) refill() error {\n\tmb, err := r.Reader.ReadMultiBuffer()\n\tif err != nil {\n\t\treturn err\n\t}\n\tr.access.Lock()\n\tr.cache = mb\n\tr.access.Unlock()\n\treturn nil\n}\n\n// ReadMessage implements MessageReader.\nfunc (r *UDPReader) ReadMessage() (*buf.Buffer, error) {\n\tfor {\n\t\tb := r.readCache()\n\t\tif b != nil {\n\t\t\treturn b, nil\n\t\t}\n\t\tif err := r.refill(); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n}\n\n// Close implements common.Closable.\nfunc (r *UDPReader) Close() error {\n\tdefer func() {\n\t\tr.access.Lock()\n\t\tbuf.ReleaseMulti(r.cache)\n\t\tr.cache = nil\n\t\tr.access.Unlock()\n\t}()\n\n\treturn common.Close(r.Reader)\n}\n\ntype TCPReader struct {\n\treader *buf.BufferedReader\n}\n\nfunc NewTCPReader(reader buf.Reader) *TCPReader {\n\treturn &TCPReader{\n\t\treader: &buf.BufferedReader{\n\t\t\tReader: reader,\n\t\t},\n\t}\n}\n\nfunc (r *TCPReader) ReadMessage() (*buf.Buffer, error) {\n\tsize, err := serial.ReadUint16(r.reader)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif size > buf.Size {\n\t\treturn nil, newError(\"message size too large: \", size)\n\t}\n\tb := buf.New()\n\tif _, err := b.ReadFullFrom(r.reader, int32(size)); err != nil {\n\t\treturn nil, err\n\t}\n\treturn b, nil\n}\n\nfunc (r *TCPReader) Interrupt() {\n\tcommon.Interrupt(r.reader)\n}\n\nfunc (r *TCPReader) Close() error {\n\treturn common.Close(r.reader)\n}\n\ntype MessageWriter interface {\n\tWriteMessage(msg *buf.Buffer) error\n}\n\ntype UDPWriter struct {\n\tbuf.Writer\n}\n\nfunc (w *UDPWriter) WriteMessage(b *buf.Buffer) error {\n\treturn w.WriteMultiBuffer(buf.MultiBuffer{b})\n}\n\ntype TCPWriter struct {\n\tbuf.Writer\n}\n\nfunc (w *TCPWriter) WriteMessage(b *buf.Buffer) error {\n\tif b.IsEmpty() {\n\t\treturn nil\n\t}\n\n\tmb := make(buf.MultiBuffer, 0, 2)\n\n\tsize := buf.New()\n\tbinary.BigEndian.PutUint16(size.Extend(2), uint16(b.Len()))\n\tmb = append(mb, size, b)\n\treturn w.WriteMultiBuffer(mb)\n}\n"
  },
  {
    "path": "common/protocol/errors.generated.go",
    "content": "package protocol\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "common/protocol/headers.go",
    "content": "package protocol\n\nimport (\n\t\"runtime\"\n\n\t\"v2ray.com/core/common/bitmask\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/uuid\"\n)\n\n// RequestCommand is a custom command in a proxy request.\ntype RequestCommand byte\n\nconst (\n\tRequestCommandTCP = RequestCommand(0x01)\n\tRequestCommandUDP = RequestCommand(0x02)\n\tRequestCommandMux = RequestCommand(0x03)\n)\n\nfunc (c RequestCommand) TransferType() TransferType {\n\tswitch c {\n\tcase RequestCommandTCP, RequestCommandMux:\n\t\treturn TransferTypeStream\n\tcase RequestCommandUDP:\n\t\treturn TransferTypePacket\n\tdefault:\n\t\treturn TransferTypeStream\n\t}\n}\n\nconst (\n\t// RequestOptionChunkStream indicates request payload is chunked. Each chunk consists of length, authentication and payload.\n\tRequestOptionChunkStream bitmask.Byte = 0x01\n\n\t// RequestOptionConnectionReuse indicates client side expects to reuse the connection.\n\tRequestOptionConnectionReuse bitmask.Byte = 0x02\n\n\tRequestOptionChunkMasking bitmask.Byte = 0x04\n\n\tRequestOptionGlobalPadding bitmask.Byte = 0x08\n)\n\ntype RequestHeader struct {\n\tVersion  byte\n\tCommand  RequestCommand\n\tOption   bitmask.Byte\n\tSecurity SecurityType\n\tPort     net.Port\n\tAddress  net.Address\n\tUser     *MemoryUser\n}\n\nfunc (h *RequestHeader) Destination() net.Destination {\n\tif h.Command == RequestCommandUDP {\n\t\treturn net.UDPDestination(h.Address, h.Port)\n\t}\n\treturn net.TCPDestination(h.Address, h.Port)\n}\n\nconst (\n\tResponseOptionConnectionReuse bitmask.Byte = 0x01\n)\n\ntype ResponseCommand interface{}\n\ntype ResponseHeader struct {\n\tOption  bitmask.Byte\n\tCommand ResponseCommand\n}\n\ntype CommandSwitchAccount struct {\n\tHost     net.Address\n\tPort     net.Port\n\tID       uuid.UUID\n\tLevel    uint32\n\tAlterIds uint16\n\tValidMin byte\n}\n\nfunc (sc *SecurityConfig) GetSecurityType() SecurityType {\n\tif sc == nil || sc.Type == SecurityType_AUTO {\n\t\tif runtime.GOARCH == \"amd64\" || runtime.GOARCH == \"s390x\" || runtime.GOARCH == \"arm64\" {\n\t\t\treturn SecurityType_AES128_GCM\n\t\t}\n\t\treturn SecurityType_CHACHA20_POLY1305\n\t}\n\treturn sc.Type\n}\n\nfunc isDomainTooLong(domain string) bool {\n\treturn len(domain) > 256\n}\n"
  },
  {
    "path": "common/protocol/headers.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: common/protocol/headers.proto\n\npackage protocol\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype SecurityType int32\n\nconst (\n\tSecurityType_UNKNOWN           SecurityType = 0\n\tSecurityType_LEGACY            SecurityType = 1\n\tSecurityType_AUTO              SecurityType = 2\n\tSecurityType_AES128_GCM        SecurityType = 3\n\tSecurityType_CHACHA20_POLY1305 SecurityType = 4\n\tSecurityType_NONE              SecurityType = 5\n)\n\n// Enum value maps for SecurityType.\nvar (\n\tSecurityType_name = map[int32]string{\n\t\t0: \"UNKNOWN\",\n\t\t1: \"LEGACY\",\n\t\t2: \"AUTO\",\n\t\t3: \"AES128_GCM\",\n\t\t4: \"CHACHA20_POLY1305\",\n\t\t5: \"NONE\",\n\t}\n\tSecurityType_value = map[string]int32{\n\t\t\"UNKNOWN\":           0,\n\t\t\"LEGACY\":            1,\n\t\t\"AUTO\":              2,\n\t\t\"AES128_GCM\":        3,\n\t\t\"CHACHA20_POLY1305\": 4,\n\t\t\"NONE\":              5,\n\t}\n)\n\nfunc (x SecurityType) Enum() *SecurityType {\n\tp := new(SecurityType)\n\t*p = x\n\treturn p\n}\n\nfunc (x SecurityType) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (SecurityType) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_common_protocol_headers_proto_enumTypes[0].Descriptor()\n}\n\nfunc (SecurityType) Type() protoreflect.EnumType {\n\treturn &file_common_protocol_headers_proto_enumTypes[0]\n}\n\nfunc (x SecurityType) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use SecurityType.Descriptor instead.\nfunc (SecurityType) EnumDescriptor() ([]byte, []int) {\n\treturn file_common_protocol_headers_proto_rawDescGZIP(), []int{0}\n}\n\ntype SecurityConfig struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tType SecurityType `protobuf:\"varint,1,opt,name=type,proto3,enum=v2ray.core.common.protocol.SecurityType\" json:\"type,omitempty\"`\n}\n\nfunc (x *SecurityConfig) Reset() {\n\t*x = SecurityConfig{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_common_protocol_headers_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *SecurityConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SecurityConfig) ProtoMessage() {}\n\nfunc (x *SecurityConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_common_protocol_headers_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SecurityConfig.ProtoReflect.Descriptor instead.\nfunc (*SecurityConfig) Descriptor() ([]byte, []int) {\n\treturn file_common_protocol_headers_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *SecurityConfig) GetType() SecurityType {\n\tif x != nil {\n\t\treturn x.Type\n\t}\n\treturn SecurityType_UNKNOWN\n}\n\nvar File_common_protocol_headers_proto protoreflect.FileDescriptor\n\nvar file_common_protocol_headers_proto_rawDesc = []byte{\n\t0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,\n\t0x6c, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,\n\t0x1a, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,\n\t0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x22, 0x4e, 0x0a, 0x0e, 0x53,\n\t0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3c, 0x0a,\n\t0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x28, 0x2e, 0x76, 0x32,\n\t0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e,\n\t0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74,\n\t0x79, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x2a, 0x62, 0x0a, 0x0c, 0x53,\n\t0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55,\n\t0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x4c, 0x45, 0x47, 0x41,\n\t0x43, 0x59, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x41, 0x55, 0x54, 0x4f, 0x10, 0x02, 0x12, 0x0e,\n\t0x0a, 0x0a, 0x41, 0x45, 0x53, 0x31, 0x32, 0x38, 0x5f, 0x47, 0x43, 0x4d, 0x10, 0x03, 0x12, 0x15,\n\t0x0a, 0x11, 0x43, 0x48, 0x41, 0x43, 0x48, 0x41, 0x32, 0x30, 0x5f, 0x50, 0x4f, 0x4c, 0x59, 0x31,\n\t0x33, 0x30, 0x35, 0x10, 0x04, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x05, 0x42,\n\t0x5f, 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72,\n\t0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,\n\t0x6c, 0x50, 0x01, 0x5a, 0x1e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63,\n\t0x6f, 0x72, 0x65, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,\n\t0x63, 0x6f, 0x6c, 0xaa, 0x02, 0x1a, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65,\n\t0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c,\n\t0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_common_protocol_headers_proto_rawDescOnce sync.Once\n\tfile_common_protocol_headers_proto_rawDescData = file_common_protocol_headers_proto_rawDesc\n)\n\nfunc file_common_protocol_headers_proto_rawDescGZIP() []byte {\n\tfile_common_protocol_headers_proto_rawDescOnce.Do(func() {\n\t\tfile_common_protocol_headers_proto_rawDescData = protoimpl.X.CompressGZIP(file_common_protocol_headers_proto_rawDescData)\n\t})\n\treturn file_common_protocol_headers_proto_rawDescData\n}\n\nvar file_common_protocol_headers_proto_enumTypes = make([]protoimpl.EnumInfo, 1)\nvar file_common_protocol_headers_proto_msgTypes = make([]protoimpl.MessageInfo, 1)\nvar file_common_protocol_headers_proto_goTypes = []interface{}{\n\t(SecurityType)(0),      // 0: v2ray.core.common.protocol.SecurityType\n\t(*SecurityConfig)(nil), // 1: v2ray.core.common.protocol.SecurityConfig\n}\nvar file_common_protocol_headers_proto_depIdxs = []int32{\n\t0, // 0: v2ray.core.common.protocol.SecurityConfig.type:type_name -> v2ray.core.common.protocol.SecurityType\n\t1, // [1:1] is the sub-list for method output_type\n\t1, // [1:1] is the sub-list for method input_type\n\t1, // [1:1] is the sub-list for extension type_name\n\t1, // [1:1] is the sub-list for extension extendee\n\t0, // [0:1] is the sub-list for field type_name\n}\n\nfunc init() { file_common_protocol_headers_proto_init() }\nfunc file_common_protocol_headers_proto_init() {\n\tif File_common_protocol_headers_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_common_protocol_headers_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*SecurityConfig); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_common_protocol_headers_proto_rawDesc,\n\t\t\tNumEnums:      1,\n\t\t\tNumMessages:   1,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_common_protocol_headers_proto_goTypes,\n\t\tDependencyIndexes: file_common_protocol_headers_proto_depIdxs,\n\t\tEnumInfos:         file_common_protocol_headers_proto_enumTypes,\n\t\tMessageInfos:      file_common_protocol_headers_proto_msgTypes,\n\t}.Build()\n\tFile_common_protocol_headers_proto = out.File\n\tfile_common_protocol_headers_proto_rawDesc = nil\n\tfile_common_protocol_headers_proto_goTypes = nil\n\tfile_common_protocol_headers_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "common/protocol/headers.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.common.protocol;\noption csharp_namespace = \"V2Ray.Core.Common.Protocol\";\noption go_package = \"v2ray.com/core/common/protocol\";\noption java_package = \"com.v2ray.core.common.protocol\";\noption java_multiple_files = true;\n\nenum SecurityType {\n  UNKNOWN = 0;\n  LEGACY = 1;\n  AUTO = 2;\n  AES128_GCM = 3;\n  CHACHA20_POLY1305 = 4;\n  NONE = 5;\n}\n\nmessage SecurityConfig {\n  SecurityType type = 1;\n}\n"
  },
  {
    "path": "common/protocol/http/headers.go",
    "content": "package http\n\nimport (\n\t\"net/http\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"v2ray.com/core/common/net\"\n)\n\n// ParseXForwardedFor parses X-Forwarded-For header in http headers, and return the IP list in it.\nfunc ParseXForwardedFor(header http.Header) []net.Address {\n\txff := header.Get(\"X-Forwarded-For\")\n\tif xff == \"\" {\n\t\treturn nil\n\t}\n\tlist := strings.Split(xff, \",\")\n\taddrs := make([]net.Address, 0, len(list))\n\tfor _, proxy := range list {\n\t\taddrs = append(addrs, net.ParseAddress(proxy))\n\t}\n\treturn addrs\n}\n\n// RemoveHopByHopHeaders remove hop by hop headers in http header list.\nfunc RemoveHopByHopHeaders(header http.Header) {\n\t// Strip hop-by-hop header based on RFC:\n\t// http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.5.1\n\t// https://www.mnot.net/blog/2011/07/11/what_proxies_must_do\n\n\theader.Del(\"Proxy-Connection\")\n\theader.Del(\"Proxy-Authenticate\")\n\theader.Del(\"Proxy-Authorization\")\n\theader.Del(\"TE\")\n\theader.Del(\"Trailers\")\n\theader.Del(\"Transfer-Encoding\")\n\theader.Del(\"Upgrade\")\n\n\tconnections := header.Get(\"Connection\")\n\theader.Del(\"Connection\")\n\tif connections == \"\" {\n\t\treturn\n\t}\n\tfor _, h := range strings.Split(connections, \",\") {\n\t\theader.Del(strings.TrimSpace(h))\n\t}\n}\n\n// ParseHost splits host and port from a raw string. Default port is used when raw string doesn't contain port.\nfunc ParseHost(rawHost string, defaultPort net.Port) (net.Destination, error) {\n\tport := defaultPort\n\thost, rawPort, err := net.SplitHostPort(rawHost)\n\tif err != nil {\n\t\tif addrError, ok := err.(*net.AddrError); ok && strings.Contains(addrError.Err, \"missing port\") {\n\t\t\thost = rawHost\n\t\t} else {\n\t\t\treturn net.Destination{}, err\n\t\t}\n\t} else if len(rawPort) > 0 {\n\t\tintPort, err := strconv.Atoi(rawPort)\n\t\tif err != nil {\n\t\t\treturn net.Destination{}, err\n\t\t}\n\t\tport = net.Port(intPort)\n\t}\n\n\treturn net.TCPDestination(net.ParseAddress(host), port), nil\n}\n"
  },
  {
    "path": "common/protocol/http/headers_test.go",
    "content": "package http_test\n\nimport (\n\t\"bufio\"\n\t\"net/http\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/net\"\n\t. \"v2ray.com/core/common/protocol/http\"\n)\n\nfunc TestParseXForwardedFor(t *testing.T) {\n\theader := http.Header{}\n\theader.Add(\"X-Forwarded-For\", \"129.78.138.66, 129.78.64.103\")\n\taddrs := ParseXForwardedFor(header)\n\tif r := cmp.Diff(addrs, []net.Address{net.ParseAddress(\"129.78.138.66\"), net.ParseAddress(\"129.78.64.103\")}); r != \"\" {\n\t\tt.Error(r)\n\t}\n}\n\nfunc TestHopByHopHeadersRemoving(t *testing.T) {\n\trawRequest := `GET /pkg/net/http/ HTTP/1.1\nHost: golang.org\nConnection: keep-alive,Foo, Bar\nFoo: foo\nBar: bar\nProxy-Connection: keep-alive\nProxy-Authenticate: abc\nAccept-Encoding: gzip\nAccept-Charset: ISO-8859-1,UTF-8;q=0.7,*;q=0.7\nCache-Control: no-cache\nAccept-Language: de,en;q=0.7,en-us;q=0.3\n\n`\n\tb := bufio.NewReader(strings.NewReader(rawRequest))\n\treq, err := http.ReadRequest(b)\n\tcommon.Must(err)\n\theaders := []struct {\n\t\tKey   string\n\t\tValue string\n\t}{\n\t\t{\n\t\t\tKey:   \"Foo\",\n\t\t\tValue: \"foo\",\n\t\t},\n\t\t{\n\t\t\tKey:   \"Bar\",\n\t\t\tValue: \"bar\",\n\t\t},\n\t\t{\n\t\t\tKey:   \"Connection\",\n\t\t\tValue: \"keep-alive,Foo, Bar\",\n\t\t},\n\t\t{\n\t\t\tKey:   \"Proxy-Connection\",\n\t\t\tValue: \"keep-alive\",\n\t\t},\n\t\t{\n\t\t\tKey:   \"Proxy-Authenticate\",\n\t\t\tValue: \"abc\",\n\t\t},\n\t}\n\tfor _, header := range headers {\n\t\tif v := req.Header.Get(header.Key); v != header.Value {\n\t\t\tt.Error(\"header \", header.Key, \" = \", v, \" want \", header.Value)\n\t\t}\n\t}\n\n\tRemoveHopByHopHeaders(req.Header)\n\n\tfor _, header := range []string{\"Connection\", \"Foo\", \"Bar\", \"Proxy-Connection\", \"Proxy-Authenticate\"} {\n\t\tif v := req.Header.Get(header); v != \"\" {\n\t\t\tt.Error(\"header \", header, \" = \", v)\n\t\t}\n\t}\n}\n\nfunc TestParseHost(t *testing.T) {\n\ttestCases := []struct {\n\t\tRawHost     string\n\t\tDefaultPort net.Port\n\t\tDestination net.Destination\n\t\tError       bool\n\t}{\n\t\t{\n\t\t\tRawHost:     \"v2ray.com:80\",\n\t\t\tDefaultPort: 443,\n\t\t\tDestination: net.TCPDestination(net.DomainAddress(\"v2ray.com\"), 80),\n\t\t},\n\t\t{\n\t\t\tRawHost:     \"tls.v2ray.com\",\n\t\t\tDefaultPort: 443,\n\t\t\tDestination: net.TCPDestination(net.DomainAddress(\"tls.v2ray.com\"), 443),\n\t\t},\n\t\t{\n\t\t\tRawHost:     \"[2401:1bc0:51f0:ec08::1]:80\",\n\t\t\tDefaultPort: 443,\n\t\t\tDestination: net.TCPDestination(net.ParseAddress(\"[2401:1bc0:51f0:ec08::1]\"), 80),\n\t\t},\n\t}\n\n\tfor _, testCase := range testCases {\n\t\tdest, err := ParseHost(testCase.RawHost, testCase.DefaultPort)\n\t\tif testCase.Error {\n\t\t\tif err == nil {\n\t\t\t\tt.Error(\"for test case: \", testCase.RawHost, \" expected error, but actually nil\")\n\t\t\t}\n\t\t} else {\n\t\t\tif dest != testCase.Destination {\n\t\t\t\tt.Error(\"for test case: \", testCase.RawHost, \" expected host: \", testCase.Destination.String(), \" but got \", dest.String())\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "common/protocol/http/sniff.go",
    "content": "package http\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"strings\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/net\"\n)\n\ntype version byte\n\nconst (\n\tHTTP1 version = iota\n\tHTTP2\n)\n\ntype SniffHeader struct {\n\tversion version\n\thost    string\n}\n\nfunc (h *SniffHeader) Protocol() string {\n\tswitch h.version {\n\tcase HTTP1:\n\t\treturn \"http1\"\n\tcase HTTP2:\n\t\treturn \"http2\"\n\tdefault:\n\t\treturn \"unknown\"\n\t}\n}\n\nfunc (h *SniffHeader) Domain() string {\n\treturn h.host\n}\n\nvar (\n\tmethods = [...]string{\"get\", \"post\", \"head\", \"put\", \"delete\", \"options\", \"connect\"}\n\n\terrNotHTTPMethod = errors.New(\"not an HTTP method\")\n)\n\nfunc beginWithHTTPMethod(b []byte) error {\n\tfor _, m := range &methods {\n\t\tif len(b) >= len(m) && strings.EqualFold(string(b[:len(m)]), m) {\n\t\t\treturn nil\n\t\t}\n\n\t\tif len(b) < len(m) {\n\t\t\treturn common.ErrNoClue\n\t\t}\n\t}\n\n\treturn errNotHTTPMethod\n}\n\nfunc SniffHTTP(b []byte) (*SniffHeader, error) {\n\tif err := beginWithHTTPMethod(b); err != nil {\n\t\treturn nil, err\n\t}\n\n\tsh := &SniffHeader{\n\t\tversion: HTTP1,\n\t}\n\n\theaders := bytes.Split(b, []byte{'\\n'})\n\tfor i := 1; i < len(headers); i++ {\n\t\theader := headers[i]\n\t\tif len(header) == 0 {\n\t\t\tbreak\n\t\t}\n\t\tparts := bytes.SplitN(header, []byte{':'}, 2)\n\t\tif len(parts) != 2 {\n\t\t\tcontinue\n\t\t}\n\t\tkey := strings.ToLower(string(parts[0]))\n\t\tif key == \"host\" {\n\t\t\trawHost := strings.ToLower(string(bytes.TrimSpace(parts[1])))\n\t\t\tdest, err := ParseHost(rawHost, net.Port(80))\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tsh.host = dest.Address.String()\n\t\t}\n\t}\n\n\tif len(sh.host) > 0 {\n\t\treturn sh, nil\n\t}\n\n\treturn nil, common.ErrNoClue\n}\n"
  },
  {
    "path": "common/protocol/http/sniff_test.go",
    "content": "package http_test\n\nimport (\n\t\"testing\"\n\n\t. \"v2ray.com/core/common/protocol/http\"\n)\n\nfunc TestHTTPHeaders(t *testing.T) {\n\tcases := []struct {\n\t\tinput  string\n\t\tdomain string\n\t\terr    bool\n\t}{\n\t\t{\n\t\t\tinput: `GET /tutorials/other/top-20-mysql-best-practices/ HTTP/1.1\nHost: net.tutsplus.com\nUser-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\nAccept-Language: en-us,en;q=0.5\nAccept-Encoding: gzip,deflate\nAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\nKeep-Alive: 300\nConnection: keep-alive\nCookie: PHPSESSID=r2t5uvjq435r4q7ib3vtdjq120\nPragma: no-cache\nCache-Control: no-cache`,\n\t\t\tdomain: \"net.tutsplus.com\",\n\t\t},\n\t\t{\n\t\t\tinput: `POST /foo.php HTTP/1.1\nHost: localhost\nUser-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\nAccept-Language: en-us,en;q=0.5\nAccept-Encoding: gzip,deflate\nAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\nKeep-Alive: 300\nConnection: keep-alive\nReferer: http://localhost/test.php\nContent-Type: application/x-www-form-urlencoded\nContent-Length: 43\n \nfirst_name=John&last_name=Doe&action=Submit`,\n\t\t\tdomain: \"localhost\",\n\t\t},\n\t\t{\n\t\t\tinput: `X /foo.php HTTP/1.1\nHost: localhost\nUser-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\nAccept-Language: en-us,en;q=0.5\nAccept-Encoding: gzip,deflate\nAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\nKeep-Alive: 300\nConnection: keep-alive\nReferer: http://localhost/test.php\nContent-Type: application/x-www-form-urlencoded\nContent-Length: 43\n \nfirst_name=John&last_name=Doe&action=Submit`,\n\t\t\tdomain: \"\",\n\t\t\terr:    true,\n\t\t},\n\t\t{\n\t\t\tinput: `GET /foo.php HTTP/1.1\nUser-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\nAccept-Language: en-us,en;q=0.5\nAccept-Encoding: gzip,deflate\nAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\nKeep-Alive: 300\nConnection: keep-alive\nReferer: http://localhost/test.php\nContent-Type: application/x-www-form-urlencoded\nContent-Length: 43\n\nHost: localhost\nfirst_name=John&last_name=Doe&action=Submit`,\n\t\t\tdomain: \"\",\n\t\t\terr:    true,\n\t\t},\n\t\t{\n\t\t\tinput:  `GET /tutorials/other/top-20-mysql-best-practices/ HTTP/1.1`,\n\t\t\tdomain: \"\",\n\t\t\terr:    true,\n\t\t},\n\t}\n\n\tfor _, test := range cases {\n\t\theader, err := SniffHTTP([]byte(test.input))\n\t\tif test.err {\n\t\t\tif err == nil {\n\t\t\t\tt.Errorf(\"Expect error but nil, in test: %v\", test)\n\t\t\t}\n\t\t} else {\n\t\t\tif err != nil {\n\t\t\t\tt.Errorf(\"Expect no error but actually %s in test %v\", err.Error(), test)\n\t\t\t}\n\t\t\tif header.Domain() != test.domain {\n\t\t\t\tt.Error(\"expected domain \", test.domain, \" but got \", header.Domain())\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "common/protocol/id.go",
    "content": "package protocol\n\nimport (\n\t\"crypto/hmac\"\n\t\"crypto/md5\"\n\t\"hash\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/uuid\"\n)\n\nconst (\n\tIDBytesLen = 16\n)\n\ntype IDHash func(key []byte) hash.Hash\n\nfunc DefaultIDHash(key []byte) hash.Hash {\n\treturn hmac.New(md5.New, key)\n}\n\n// The ID of en entity, in the form of a UUID.\ntype ID struct {\n\tuuid   uuid.UUID\n\tcmdKey [IDBytesLen]byte\n}\n\n// Equals returns true if this ID equals to the other one.\nfunc (id *ID) Equals(another *ID) bool {\n\treturn id.uuid.Equals(&(another.uuid))\n}\n\nfunc (id *ID) Bytes() []byte {\n\treturn id.uuid.Bytes()\n}\n\nfunc (id *ID) String() string {\n\treturn id.uuid.String()\n}\n\nfunc (id *ID) UUID() uuid.UUID {\n\treturn id.uuid\n}\n\nfunc (id ID) CmdKey() []byte {\n\treturn id.cmdKey[:]\n}\n\n// NewID returns an ID with given UUID.\nfunc NewID(uuid uuid.UUID) *ID {\n\tid := &ID{uuid: uuid}\n\tmd5hash := md5.New()\n\tcommon.Must2(md5hash.Write(uuid.Bytes()))\n\tcommon.Must2(md5hash.Write([]byte(\"c48619fe-8f02-49e0-b9e9-edf763e17e21\")))\n\tmd5hash.Sum(id.cmdKey[:0])\n\treturn id\n}\n\nfunc nextID(u *uuid.UUID) uuid.UUID {\n\tmd5hash := md5.New()\n\tcommon.Must2(md5hash.Write(u.Bytes()))\n\tcommon.Must2(md5hash.Write([]byte(\"16167dc8-16b6-4e6d-b8bb-65dd68113a81\")))\n\tvar newid uuid.UUID\n\tfor {\n\t\tmd5hash.Sum(newid[:0])\n\t\tif !newid.Equals(u) {\n\t\t\treturn newid\n\t\t}\n\t\tcommon.Must2(md5hash.Write([]byte(\"533eff8a-4113-4b10-b5ce-0f5d76b98cd2\")))\n\t}\n}\n\nfunc NewAlterIDs(primary *ID, alterIDCount uint16) []*ID {\n\talterIDs := make([]*ID, alterIDCount)\n\tprevID := primary.UUID()\n\tfor idx := range alterIDs {\n\t\tnewid := nextID(&prevID)\n\t\talterIDs[idx] = NewID(newid)\n\t\tprevID = newid\n\t}\n\treturn alterIDs\n}\n"
  },
  {
    "path": "common/protocol/id_test.go",
    "content": "package protocol_test\n\nimport (\n\t\"testing\"\n\n\t. \"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/uuid\"\n)\n\nfunc TestIdEquals(t *testing.T) {\n\tid1 := NewID(uuid.New())\n\tid2 := NewID(id1.UUID())\n\n\tif !id1.Equals(id2) {\n\t\tt.Error(\"expected id1 to equal id2, but actually not\")\n\t}\n\n\tif id1.String() != id2.String() {\n\t\tt.Error(id1.String(), \" != \", id2.String())\n\t}\n}\n"
  },
  {
    "path": "common/protocol/payload.go",
    "content": "package protocol\n\ntype TransferType byte\n\nconst (\n\tTransferTypeStream TransferType = 0\n\tTransferTypePacket TransferType = 1\n)\n\ntype AddressType byte\n\nconst (\n\tAddressTypeIPv4   AddressType = 1\n\tAddressTypeDomain AddressType = 2\n\tAddressTypeIPv6   AddressType = 3\n)\n"
  },
  {
    "path": "common/protocol/protocol.go",
    "content": "package protocol // import \"v2ray.com/core/common/protocol\"\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n"
  },
  {
    "path": "common/protocol/server_picker.go",
    "content": "package protocol\n\nimport (\n\t\"sync\"\n)\n\ntype ServerList struct {\n\tsync.RWMutex\n\tservers []*ServerSpec\n}\n\nfunc NewServerList() *ServerList {\n\treturn &ServerList{}\n}\n\nfunc (sl *ServerList) AddServer(server *ServerSpec) {\n\tsl.Lock()\n\tdefer sl.Unlock()\n\n\tsl.servers = append(sl.servers, server)\n}\n\nfunc (sl *ServerList) Size() uint32 {\n\tsl.RLock()\n\tdefer sl.RUnlock()\n\n\treturn uint32(len(sl.servers))\n}\n\nfunc (sl *ServerList) GetServer(idx uint32) *ServerSpec {\n\tsl.Lock()\n\tdefer sl.Unlock()\n\n\tfor {\n\t\tif idx >= uint32(len(sl.servers)) {\n\t\t\treturn nil\n\t\t}\n\n\t\tserver := sl.servers[idx]\n\t\tif !server.IsValid() {\n\t\t\tsl.removeServer(idx)\n\t\t\tcontinue\n\t\t}\n\n\t\treturn server\n\t}\n}\n\nfunc (sl *ServerList) removeServer(idx uint32) {\n\tn := len(sl.servers)\n\tsl.servers[idx] = sl.servers[n-1]\n\tsl.servers = sl.servers[:n-1]\n}\n\ntype ServerPicker interface {\n\tPickServer() *ServerSpec\n}\n\ntype RoundRobinServerPicker struct {\n\tsync.Mutex\n\tserverlist *ServerList\n\tnextIndex  uint32\n}\n\nfunc NewRoundRobinServerPicker(serverlist *ServerList) *RoundRobinServerPicker {\n\treturn &RoundRobinServerPicker{\n\t\tserverlist: serverlist,\n\t\tnextIndex:  0,\n\t}\n}\n\nfunc (p *RoundRobinServerPicker) PickServer() *ServerSpec {\n\tp.Lock()\n\tdefer p.Unlock()\n\n\tnext := p.nextIndex\n\tserver := p.serverlist.GetServer(next)\n\tif server == nil {\n\t\tnext = 0\n\t\tserver = p.serverlist.GetServer(0)\n\t}\n\tnext++\n\tif next >= p.serverlist.Size() {\n\t\tnext = 0\n\t}\n\tp.nextIndex = next\n\n\treturn server\n}\n"
  },
  {
    "path": "common/protocol/server_picker_test.go",
    "content": "package protocol_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"v2ray.com/core/common/net\"\n\t. \"v2ray.com/core/common/protocol\"\n)\n\nfunc TestServerList(t *testing.T) {\n\tlist := NewServerList()\n\tlist.AddServer(NewServerSpec(net.TCPDestination(net.LocalHostIP, net.Port(1)), AlwaysValid()))\n\tif list.Size() != 1 {\n\t\tt.Error(\"list size: \", list.Size())\n\t}\n\tlist.AddServer(NewServerSpec(net.TCPDestination(net.LocalHostIP, net.Port(2)), BeforeTime(time.Now().Add(time.Second))))\n\tif list.Size() != 2 {\n\t\tt.Error(\"list.size: \", list.Size())\n\t}\n\n\tserver := list.GetServer(1)\n\tif server.Destination().Port != 2 {\n\t\tt.Error(\"server: \", server.Destination())\n\t}\n\ttime.Sleep(2 * time.Second)\n\tserver = list.GetServer(1)\n\tif server != nil {\n\t\tt.Error(\"server: \", server)\n\t}\n\n\tserver = list.GetServer(0)\n\tif server.Destination().Port != 1 {\n\t\tt.Error(\"server: \", server.Destination())\n\t}\n}\n\nfunc TestServerPicker(t *testing.T) {\n\tlist := NewServerList()\n\tlist.AddServer(NewServerSpec(net.TCPDestination(net.LocalHostIP, net.Port(1)), AlwaysValid()))\n\tlist.AddServer(NewServerSpec(net.TCPDestination(net.LocalHostIP, net.Port(2)), BeforeTime(time.Now().Add(time.Second))))\n\tlist.AddServer(NewServerSpec(net.TCPDestination(net.LocalHostIP, net.Port(3)), BeforeTime(time.Now().Add(time.Second))))\n\n\tpicker := NewRoundRobinServerPicker(list)\n\tserver := picker.PickServer()\n\tif server.Destination().Port != 1 {\n\t\tt.Error(\"server: \", server.Destination())\n\t}\n\tserver = picker.PickServer()\n\tif server.Destination().Port != 2 {\n\t\tt.Error(\"server: \", server.Destination())\n\t}\n\tserver = picker.PickServer()\n\tif server.Destination().Port != 3 {\n\t\tt.Error(\"server: \", server.Destination())\n\t}\n\tserver = picker.PickServer()\n\tif server.Destination().Port != 1 {\n\t\tt.Error(\"server: \", server.Destination())\n\t}\n\n\ttime.Sleep(2 * time.Second)\n\tserver = picker.PickServer()\n\tif server.Destination().Port != 1 {\n\t\tt.Error(\"server: \", server.Destination())\n\t}\n\tserver = picker.PickServer()\n\tif server.Destination().Port != 1 {\n\t\tt.Error(\"server: \", server.Destination())\n\t}\n}\n"
  },
  {
    "path": "common/protocol/server_spec.go",
    "content": "package protocol\n\nimport (\n\t\"sync\"\n\t\"time\"\n\n\t\"v2ray.com/core/common/dice\"\n\t\"v2ray.com/core/common/net\"\n)\n\ntype ValidationStrategy interface {\n\tIsValid() bool\n\tInvalidate()\n}\n\ntype alwaysValidStrategy struct{}\n\nfunc AlwaysValid() ValidationStrategy {\n\treturn alwaysValidStrategy{}\n}\n\nfunc (alwaysValidStrategy) IsValid() bool {\n\treturn true\n}\n\nfunc (alwaysValidStrategy) Invalidate() {}\n\ntype timeoutValidStrategy struct {\n\tuntil time.Time\n}\n\nfunc BeforeTime(t time.Time) ValidationStrategy {\n\treturn &timeoutValidStrategy{\n\t\tuntil: t,\n\t}\n}\n\nfunc (s *timeoutValidStrategy) IsValid() bool {\n\treturn s.until.After(time.Now())\n}\n\nfunc (s *timeoutValidStrategy) Invalidate() {\n\ts.until = time.Time{}\n}\n\ntype ServerSpec struct {\n\tsync.RWMutex\n\tdest  net.Destination\n\tusers []*MemoryUser\n\tvalid ValidationStrategy\n}\n\nfunc NewServerSpec(dest net.Destination, valid ValidationStrategy, users ...*MemoryUser) *ServerSpec {\n\treturn &ServerSpec{\n\t\tdest:  dest,\n\t\tusers: users,\n\t\tvalid: valid,\n\t}\n}\n\nfunc NewServerSpecFromPB(spec *ServerEndpoint) (*ServerSpec, error) {\n\tdest := net.TCPDestination(spec.Address.AsAddress(), net.Port(spec.Port))\n\tmUsers := make([]*MemoryUser, len(spec.User))\n\tfor idx, u := range spec.User {\n\t\tmUser, err := u.ToMemoryUser()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tmUsers[idx] = mUser\n\t}\n\treturn NewServerSpec(dest, AlwaysValid(), mUsers...), nil\n}\n\nfunc (s *ServerSpec) Destination() net.Destination {\n\treturn s.dest\n}\n\nfunc (s *ServerSpec) HasUser(user *MemoryUser) bool {\n\ts.RLock()\n\tdefer s.RUnlock()\n\n\tfor _, u := range s.users {\n\t\tif u.Account.Equals(user.Account) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc (s *ServerSpec) AddUser(user *MemoryUser) {\n\tif s.HasUser(user) {\n\t\treturn\n\t}\n\n\ts.Lock()\n\tdefer s.Unlock()\n\n\ts.users = append(s.users, user)\n}\n\nfunc (s *ServerSpec) PickUser() *MemoryUser {\n\ts.RLock()\n\tdefer s.RUnlock()\n\n\tuserCount := len(s.users)\n\tswitch userCount {\n\tcase 0:\n\t\treturn nil\n\tcase 1:\n\t\treturn s.users[0]\n\tdefault:\n\t\treturn s.users[dice.Roll(userCount)]\n\t}\n}\n\nfunc (s *ServerSpec) IsValid() bool {\n\treturn s.valid.IsValid()\n}\n\nfunc (s *ServerSpec) Invalidate() {\n\ts.valid.Invalidate()\n}\n"
  },
  {
    "path": "common/protocol/server_spec.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: common/protocol/server_spec.proto\n\npackage protocol\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n\tnet \"v2ray.com/core/common/net\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype ServerEndpoint struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tAddress *net.IPOrDomain `protobuf:\"bytes,1,opt,name=address,proto3\" json:\"address,omitempty\"`\n\tPort    uint32          `protobuf:\"varint,2,opt,name=port,proto3\" json:\"port,omitempty\"`\n\tUser    []*User         `protobuf:\"bytes,3,rep,name=user,proto3\" json:\"user,omitempty\"`\n}\n\nfunc (x *ServerEndpoint) Reset() {\n\t*x = ServerEndpoint{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_common_protocol_server_spec_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *ServerEndpoint) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ServerEndpoint) ProtoMessage() {}\n\nfunc (x *ServerEndpoint) ProtoReflect() protoreflect.Message {\n\tmi := &file_common_protocol_server_spec_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ServerEndpoint.ProtoReflect.Descriptor instead.\nfunc (*ServerEndpoint) Descriptor() ([]byte, []int) {\n\treturn file_common_protocol_server_spec_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *ServerEndpoint) GetAddress() *net.IPOrDomain {\n\tif x != nil {\n\t\treturn x.Address\n\t}\n\treturn nil\n}\n\nfunc (x *ServerEndpoint) GetPort() uint32 {\n\tif x != nil {\n\t\treturn x.Port\n\t}\n\treturn 0\n}\n\nfunc (x *ServerEndpoint) GetUser() []*User {\n\tif x != nil {\n\t\treturn x.User\n\t}\n\treturn nil\n}\n\nvar File_common_protocol_server_spec_proto protoreflect.FileDescriptor\n\nvar file_common_protocol_server_spec_proto_rawDesc = []byte{\n\t0x0a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,\n\t0x6c, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x2e, 0x70, 0x72,\n\t0x6f, 0x74, 0x6f, 0x12, 0x1a, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,\n\t0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x1a,\n\t0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x61, 0x64, 0x64, 0x72,\n\t0x65, 0x73, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1a, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,\n\t0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2e,\n\t0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x97, 0x01, 0x0a, 0x0e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72,\n\t0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x3b, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72,\n\t0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x76, 0x32, 0x72, 0x61,\n\t0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65,\n\t0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x07, 0x61, 0x64,\n\t0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20,\n\t0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x34, 0x0a, 0x04, 0x75, 0x73, 0x65,\n\t0x72, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,\n\t0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74,\n\t0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x42,\n\t0x5f, 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72,\n\t0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,\n\t0x6c, 0x50, 0x01, 0x5a, 0x1e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63,\n\t0x6f, 0x72, 0x65, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,\n\t0x63, 0x6f, 0x6c, 0xaa, 0x02, 0x1a, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65,\n\t0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c,\n\t0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_common_protocol_server_spec_proto_rawDescOnce sync.Once\n\tfile_common_protocol_server_spec_proto_rawDescData = file_common_protocol_server_spec_proto_rawDesc\n)\n\nfunc file_common_protocol_server_spec_proto_rawDescGZIP() []byte {\n\tfile_common_protocol_server_spec_proto_rawDescOnce.Do(func() {\n\t\tfile_common_protocol_server_spec_proto_rawDescData = protoimpl.X.CompressGZIP(file_common_protocol_server_spec_proto_rawDescData)\n\t})\n\treturn file_common_protocol_server_spec_proto_rawDescData\n}\n\nvar file_common_protocol_server_spec_proto_msgTypes = make([]protoimpl.MessageInfo, 1)\nvar file_common_protocol_server_spec_proto_goTypes = []interface{}{\n\t(*ServerEndpoint)(nil), // 0: v2ray.core.common.protocol.ServerEndpoint\n\t(*net.IPOrDomain)(nil), // 1: v2ray.core.common.net.IPOrDomain\n\t(*User)(nil),           // 2: v2ray.core.common.protocol.User\n}\nvar file_common_protocol_server_spec_proto_depIdxs = []int32{\n\t1, // 0: v2ray.core.common.protocol.ServerEndpoint.address:type_name -> v2ray.core.common.net.IPOrDomain\n\t2, // 1: v2ray.core.common.protocol.ServerEndpoint.user:type_name -> v2ray.core.common.protocol.User\n\t2, // [2:2] is the sub-list for method output_type\n\t2, // [2:2] is the sub-list for method input_type\n\t2, // [2:2] is the sub-list for extension type_name\n\t2, // [2:2] is the sub-list for extension extendee\n\t0, // [0:2] is the sub-list for field type_name\n}\n\nfunc init() { file_common_protocol_server_spec_proto_init() }\nfunc file_common_protocol_server_spec_proto_init() {\n\tif File_common_protocol_server_spec_proto != nil {\n\t\treturn\n\t}\n\tfile_common_protocol_user_proto_init()\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_common_protocol_server_spec_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*ServerEndpoint); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_common_protocol_server_spec_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   1,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_common_protocol_server_spec_proto_goTypes,\n\t\tDependencyIndexes: file_common_protocol_server_spec_proto_depIdxs,\n\t\tMessageInfos:      file_common_protocol_server_spec_proto_msgTypes,\n\t}.Build()\n\tFile_common_protocol_server_spec_proto = out.File\n\tfile_common_protocol_server_spec_proto_rawDesc = nil\n\tfile_common_protocol_server_spec_proto_goTypes = nil\n\tfile_common_protocol_server_spec_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "common/protocol/server_spec.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.common.protocol;\noption csharp_namespace = \"V2Ray.Core.Common.Protocol\";\noption go_package = \"v2ray.com/core/common/protocol\";\noption java_package = \"com.v2ray.core.common.protocol\";\noption java_multiple_files = true;\n\nimport \"common/net/address.proto\";\nimport \"common/protocol/user.proto\";\n\nmessage ServerEndpoint {\n  v2ray.core.common.net.IPOrDomain address = 1;\n  uint32 port = 2;\n  repeated v2ray.core.common.protocol.User user = 3;\n}\n"
  },
  {
    "path": "common/protocol/server_spec_test.go",
    "content": "package protocol_test\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/net\"\n\t. \"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/uuid\"\n\t\"v2ray.com/core/proxy/vmess\"\n)\n\nfunc TestAlwaysValidStrategy(t *testing.T) {\n\tstrategy := AlwaysValid()\n\tif !strategy.IsValid() {\n\t\tt.Error(\"strategy not valid\")\n\t}\n\tstrategy.Invalidate()\n\tif !strategy.IsValid() {\n\t\tt.Error(\"strategy not valid\")\n\t}\n}\n\nfunc TestTimeoutValidStrategy(t *testing.T) {\n\tstrategy := BeforeTime(time.Now().Add(2 * time.Second))\n\tif !strategy.IsValid() {\n\t\tt.Error(\"strategy not valid\")\n\t}\n\ttime.Sleep(3 * time.Second)\n\tif strategy.IsValid() {\n\t\tt.Error(\"strategy is valid\")\n\t}\n\n\tstrategy = BeforeTime(time.Now().Add(2 * time.Second))\n\tstrategy.Invalidate()\n\tif strategy.IsValid() {\n\t\tt.Error(\"strategy is valid\")\n\t}\n}\n\nfunc TestUserInServerSpec(t *testing.T) {\n\tuuid1 := uuid.New()\n\tuuid2 := uuid.New()\n\n\ttoAccount := func(a *vmess.Account) Account {\n\t\taccount, err := a.AsAccount()\n\t\tcommon.Must(err)\n\t\treturn account\n\t}\n\n\tspec := NewServerSpec(net.Destination{}, AlwaysValid(), &MemoryUser{\n\t\tEmail:   \"test1@v2ray.com\",\n\t\tAccount: toAccount(&vmess.Account{Id: uuid1.String()}),\n\t})\n\tif spec.HasUser(&MemoryUser{\n\t\tEmail:   \"test1@v2ray.com\",\n\t\tAccount: toAccount(&vmess.Account{Id: uuid2.String()}),\n\t}) {\n\t\tt.Error(\"has user: \", uuid2)\n\t}\n\n\tspec.AddUser(&MemoryUser{Email: \"test2@v2ray.com\"})\n\tif !spec.HasUser(&MemoryUser{\n\t\tEmail:   \"test1@v2ray.com\",\n\t\tAccount: toAccount(&vmess.Account{Id: uuid1.String()}),\n\t}) {\n\t\tt.Error(\"not having user: \", uuid1)\n\t}\n}\n\nfunc TestPickUser(t *testing.T) {\n\tspec := NewServerSpec(net.Destination{}, AlwaysValid(), &MemoryUser{Email: \"test1@v2ray.com\"}, &MemoryUser{Email: \"test2@v2ray.com\"}, &MemoryUser{Email: \"test3@v2ray.com\"})\n\tuser := spec.PickUser()\n\tif !strings.HasSuffix(user.Email, \"@v2ray.com\") {\n\t\tt.Error(\"user: \", user.Email)\n\t}\n}\n"
  },
  {
    "path": "common/protocol/time.go",
    "content": "package protocol\n\nimport (\n\t\"time\"\n\n\t\"v2ray.com/core/common/dice\"\n)\n\ntype Timestamp int64\n\ntype TimestampGenerator func() Timestamp\n\nfunc NowTime() Timestamp {\n\treturn Timestamp(time.Now().Unix())\n}\n\nfunc NewTimestampGenerator(base Timestamp, delta int) TimestampGenerator {\n\treturn func() Timestamp {\n\t\trangeInDelta := dice.Roll(delta*2) - delta\n\t\treturn base + Timestamp(rangeInDelta)\n\t}\n}\n"
  },
  {
    "path": "common/protocol/time_test.go",
    "content": "package protocol_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t. \"v2ray.com/core/common/protocol\"\n)\n\nfunc TestGenerateRandomInt64InRange(t *testing.T) {\n\tbase := time.Now().Unix()\n\tdelta := 100\n\tgenerator := NewTimestampGenerator(Timestamp(base), delta)\n\n\tfor i := 0; i < 100; i++ {\n\t\tval := int64(generator())\n\t\tif val > base+int64(delta) || val < base-int64(delta) {\n\t\t\tt.Error(val, \" not between \", base-int64(delta), \" and \", base+int64(delta))\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "common/protocol/tls/cert/.gitignore",
    "content": "*.pem"
  },
  {
    "path": "common/protocol/tls/cert/cert.go",
    "content": "package cert\n\nimport (\n\t\"crypto/ecdsa\"\n\t\"crypto/ed25519\"\n\t\"crypto/elliptic\"\n\t\"crypto/rand\"\n\t\"crypto/rsa\"\n\t\"crypto/x509\"\n\t\"encoding/asn1\"\n\t\"encoding/pem\"\n\t\"math/big\"\n\t\"time\"\n\n\t\"v2ray.com/core/common\"\n)\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n\ntype Certificate struct {\n\t// Cerificate in ASN.1 DER format\n\tCertificate []byte\n\t// Private key in ASN.1 DER format\n\tPrivateKey []byte\n}\n\nfunc ParseCertificate(certPEM []byte, keyPEM []byte) (*Certificate, error) {\n\tcertBlock, _ := pem.Decode(certPEM)\n\tif certBlock == nil {\n\t\treturn nil, newError(\"failed to decode certificate\")\n\t}\n\tkeyBlock, _ := pem.Decode(keyPEM)\n\tif keyBlock == nil {\n\t\treturn nil, newError(\"failed to decode key\")\n\t}\n\treturn &Certificate{\n\t\tCertificate: certBlock.Bytes,\n\t\tPrivateKey:  keyBlock.Bytes,\n\t}, nil\n}\n\nfunc (c *Certificate) ToPEM() ([]byte, []byte) {\n\treturn pem.EncodeToMemory(&pem.Block{Type: \"CERTIFICATE\", Bytes: c.Certificate}),\n\t\tpem.EncodeToMemory(&pem.Block{Type: \"RSA PRIVATE KEY\", Bytes: c.PrivateKey})\n}\n\ntype Option func(*x509.Certificate)\n\nfunc Authority(isCA bool) Option {\n\treturn func(cert *x509.Certificate) {\n\t\tcert.IsCA = isCA\n\t}\n}\n\nfunc NotBefore(t time.Time) Option {\n\treturn func(c *x509.Certificate) {\n\t\tc.NotBefore = t\n\t}\n}\n\nfunc NotAfter(t time.Time) Option {\n\treturn func(c *x509.Certificate) {\n\t\tc.NotAfter = t\n\t}\n}\n\nfunc DNSNames(names ...string) Option {\n\treturn func(c *x509.Certificate) {\n\t\tc.DNSNames = names\n\t}\n}\n\nfunc CommonName(name string) Option {\n\treturn func(c *x509.Certificate) {\n\t\tc.Subject.CommonName = name\n\t}\n}\n\nfunc KeyUsage(usage x509.KeyUsage) Option {\n\treturn func(c *x509.Certificate) {\n\t\tc.KeyUsage = usage\n\t}\n}\n\nfunc Organization(org string) Option {\n\treturn func(c *x509.Certificate) {\n\t\tc.Subject.Organization = []string{org}\n\t}\n}\n\nfunc MustGenerate(parent *Certificate, opts ...Option) *Certificate {\n\tcert, err := Generate(parent, opts...)\n\tcommon.Must(err)\n\treturn cert\n}\n\nfunc publicKey(priv interface{}) interface{} {\n\tswitch k := priv.(type) {\n\tcase *rsa.PrivateKey:\n\t\treturn &k.PublicKey\n\tcase *ecdsa.PrivateKey:\n\t\treturn &k.PublicKey\n\tcase ed25519.PrivateKey:\n\t\treturn k.Public().(ed25519.PublicKey)\n\tdefault:\n\t\treturn nil\n\t}\n}\n\nfunc Generate(parent *Certificate, opts ...Option) (*Certificate, error) {\n\tvar (\n\t\tpKey      interface{}\n\t\tparentKey interface{}\n\t\terr       error\n\t)\n\t// higher signing performance than RSA2048\n\tselfKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)\n\tif err != nil {\n\t\treturn nil, newError(\"failed to generate self private key\").Base(err)\n\t}\n\tparentKey = selfKey\n\tif parent != nil {\n\t\tif _, e := asn1.Unmarshal(parent.PrivateKey, &ecPrivateKey{}); e == nil {\n\t\t\tpKey, err = x509.ParseECPrivateKey(parent.PrivateKey)\n\t\t} else if _, e := asn1.Unmarshal(parent.PrivateKey, &pkcs8{}); e == nil {\n\t\t\tpKey, err = x509.ParsePKCS8PrivateKey(parent.PrivateKey)\n\t\t} else if _, e := asn1.Unmarshal(parent.PrivateKey, &pkcs1PrivateKey{}); e == nil {\n\t\t\tpKey, err = x509.ParsePKCS1PrivateKey(parent.PrivateKey)\n\t\t}\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"failed to parse parent private key\").Base(err)\n\t\t}\n\t\tparentKey = pKey\n\t}\n\n\tserialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)\n\tserialNumber, err := rand.Int(rand.Reader, serialNumberLimit)\n\tif err != nil {\n\t\treturn nil, newError(\"failed to generate serial number\").Base(err)\n\t}\n\n\ttemplate := &x509.Certificate{\n\t\tSerialNumber:          serialNumber,\n\t\tNotBefore:             time.Now().Add(time.Hour * -1),\n\t\tNotAfter:              time.Now().Add(time.Hour),\n\t\tKeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,\n\t\tExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},\n\t\tBasicConstraintsValid: true,\n\t}\n\n\tfor _, opt := range opts {\n\t\topt(template)\n\t}\n\n\tparentCert := template\n\tif parent != nil {\n\t\tpCert, err := x509.ParseCertificate(parent.Certificate)\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"failed to parse parent certificate\").Base(err)\n\t\t}\n\t\tparentCert = pCert\n\t}\n\n\tderBytes, err := x509.CreateCertificate(rand.Reader, template, parentCert, publicKey(selfKey), parentKey)\n\tif err != nil {\n\t\treturn nil, newError(\"failed to create certificate\").Base(err)\n\t}\n\n\tprivateKey, err := x509.MarshalPKCS8PrivateKey(selfKey)\n\tif err != nil {\n\t\treturn nil, newError(\"Unable to marshal private key\").Base(err)\n\t}\n\n\treturn &Certificate{\n\t\tCertificate: derBytes,\n\t\tPrivateKey:  privateKey,\n\t}, nil\n}\n"
  },
  {
    "path": "common/protocol/tls/cert/cert_test.go",
    "content": "package cert\n\nimport (\n\t\"context\"\n\t\"crypto/x509\"\n\t\"encoding/json\"\n\t\"os\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/task\"\n)\n\nfunc TestGenerate(t *testing.T) {\n\terr := generate(nil, true, true, \"ca\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n}\n\nfunc generate(domainNames []string, isCA bool, jsonOutput bool, fileOutput string) error {\n\tcommonName := \"V2Ray Root CA\"\n\torganization := \"V2Ray Inc\"\n\n\texpire := time.Hour * 3\n\n\tvar opts []Option\n\tif isCA {\n\t\topts = append(opts, Authority(isCA))\n\t\topts = append(opts, KeyUsage(x509.KeyUsageCertSign|x509.KeyUsageKeyEncipherment|x509.KeyUsageDigitalSignature))\n\t}\n\n\topts = append(opts, NotAfter(time.Now().Add(expire)))\n\topts = append(opts, CommonName(commonName))\n\tif len(domainNames) > 0 {\n\t\topts = append(opts, DNSNames(domainNames...))\n\t}\n\topts = append(opts, Organization(organization))\n\n\tcert, err := Generate(nil, opts...)\n\tif err != nil {\n\t\treturn newError(\"failed to generate TLS certificate\").Base(err)\n\t}\n\n\tif jsonOutput {\n\t\tprintJSON(cert)\n\t}\n\n\tif len(fileOutput) > 0 {\n\t\tif err := printFile(cert, fileOutput); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\ntype jsonCert struct {\n\tCertificate []string `json:\"certificate\"`\n\tKey         []string `json:\"key\"`\n}\n\nfunc printJSON(certificate *Certificate) {\n\tcertPEM, keyPEM := certificate.ToPEM()\n\tjCert := &jsonCert{\n\t\tCertificate: strings.Split(strings.TrimSpace(string(certPEM)), \"\\n\"),\n\t\tKey:         strings.Split(strings.TrimSpace(string(keyPEM)), \"\\n\"),\n\t}\n\tcontent, err := json.MarshalIndent(jCert, \"\", \"  \")\n\tcommon.Must(err)\n\tos.Stdout.Write(content)\n\tos.Stdout.WriteString(\"\\n\")\n}\nfunc printFile(certificate *Certificate, name string) error {\n\tcertPEM, keyPEM := certificate.ToPEM()\n\treturn task.Run(context.Background(), func() error {\n\t\treturn writeFile(certPEM, name+\"_cert.pem\")\n\t}, func() error {\n\t\treturn writeFile(keyPEM, name+\"_key.pem\")\n\t})\n}\nfunc writeFile(content []byte, name string) error {\n\tf, err := os.Create(name)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer f.Close()\n\n\treturn common.Error2(f.Write(content))\n}\n"
  },
  {
    "path": "common/protocol/tls/cert/errors.generated.go",
    "content": "package cert\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "common/protocol/tls/cert/privateKey.go",
    "content": "package cert\n\nimport (\n\t\"crypto/x509/pkix\"\n\t\"encoding/asn1\"\n\t\"math/big\"\n)\n\ntype ecPrivateKey struct {\n\tVersion       int\n\tPrivateKey    []byte\n\tNamedCurveOID asn1.ObjectIdentifier `asn1:\"optional,explicit,tag:0\"`\n\tPublicKey     asn1.BitString        `asn1:\"optional,explicit,tag:1\"`\n}\n\ntype pkcs8 struct {\n\tVersion    int\n\tAlgo       pkix.AlgorithmIdentifier\n\tPrivateKey []byte\n\t// optional attributes omitted.\n}\n\ntype pkcs1AdditionalRSAPrime struct {\n\tPrime *big.Int\n\n\t// We ignore these values because rsa will calculate them.\n\tExp   *big.Int\n\tCoeff *big.Int\n}\n\ntype pkcs1PrivateKey struct {\n\tVersion int\n\tN       *big.Int\n\tE       int\n\tD       *big.Int\n\tP       *big.Int\n\tQ       *big.Int\n\t// We ignore these values, if present, because rsa will calculate them.\n\tDp   *big.Int `asn1:\"optional\"`\n\tDq   *big.Int `asn1:\"optional\"`\n\tQinv *big.Int `asn1:\"optional\"`\n\n\tAdditionalPrimes []pkcs1AdditionalRSAPrime `asn1:\"optional,omitempty\"`\n}\n"
  },
  {
    "path": "common/protocol/tls/sniff.go",
    "content": "package tls\n\nimport (\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"strings\"\n\n\t\"v2ray.com/core/common\"\n)\n\ntype SniffHeader struct {\n\tdomain string\n}\n\nfunc (h *SniffHeader) Protocol() string {\n\treturn \"tls\"\n}\n\nfunc (h *SniffHeader) Domain() string {\n\treturn h.domain\n}\n\nvar errNotTLS = errors.New(\"not TLS header\")\nvar errNotClientHello = errors.New(\"not client hello\")\n\nfunc IsValidTLSVersion(major, minor byte) bool {\n\treturn major == 3\n}\n\n// ReadClientHello returns server name (if any) from TLS client hello message.\n// https://github.com/golang/go/blob/master/src/crypto/tls/handshake_messages.go#L300\nfunc ReadClientHello(data []byte, h *SniffHeader) error {\n\tif len(data) < 42 {\n\t\treturn common.ErrNoClue\n\t}\n\tsessionIDLen := int(data[38])\n\tif sessionIDLen > 32 || len(data) < 39+sessionIDLen {\n\t\treturn common.ErrNoClue\n\t}\n\tdata = data[39+sessionIDLen:]\n\tif len(data) < 2 {\n\t\treturn common.ErrNoClue\n\t}\n\t// cipherSuiteLen is the number of bytes of cipher suite numbers. Since\n\t// they are uint16s, the number must be even.\n\tcipherSuiteLen := int(data[0])<<8 | int(data[1])\n\tif cipherSuiteLen%2 == 1 || len(data) < 2+cipherSuiteLen {\n\t\treturn errNotClientHello\n\t}\n\tdata = data[2+cipherSuiteLen:]\n\tif len(data) < 1 {\n\t\treturn common.ErrNoClue\n\t}\n\tcompressionMethodsLen := int(data[0])\n\tif len(data) < 1+compressionMethodsLen {\n\t\treturn common.ErrNoClue\n\t}\n\tdata = data[1+compressionMethodsLen:]\n\n\tif len(data) == 0 {\n\t\treturn errNotClientHello\n\t}\n\tif len(data) < 2 {\n\t\treturn errNotClientHello\n\t}\n\n\textensionsLength := int(data[0])<<8 | int(data[1])\n\tdata = data[2:]\n\tif extensionsLength != len(data) {\n\t\treturn errNotClientHello\n\t}\n\n\tfor len(data) != 0 {\n\t\tif len(data) < 4 {\n\t\t\treturn errNotClientHello\n\t\t}\n\t\textension := uint16(data[0])<<8 | uint16(data[1])\n\t\tlength := int(data[2])<<8 | int(data[3])\n\t\tdata = data[4:]\n\t\tif len(data) < length {\n\t\t\treturn errNotClientHello\n\t\t}\n\n\t\tif extension == 0x00 { /* extensionServerName */\n\t\t\td := data[:length]\n\t\t\tif len(d) < 2 {\n\t\t\t\treturn errNotClientHello\n\t\t\t}\n\t\t\tnamesLen := int(d[0])<<8 | int(d[1])\n\t\t\td = d[2:]\n\t\t\tif len(d) != namesLen {\n\t\t\t\treturn errNotClientHello\n\t\t\t}\n\t\t\tfor len(d) > 0 {\n\t\t\t\tif len(d) < 3 {\n\t\t\t\t\treturn errNotClientHello\n\t\t\t\t}\n\t\t\t\tnameType := d[0]\n\t\t\t\tnameLen := int(d[1])<<8 | int(d[2])\n\t\t\t\td = d[3:]\n\t\t\t\tif len(d) < nameLen {\n\t\t\t\t\treturn errNotClientHello\n\t\t\t\t}\n\t\t\t\tif nameType == 0 {\n\t\t\t\t\tserverName := string(d[:nameLen])\n\t\t\t\t\t// An SNI value may not include a\n\t\t\t\t\t// trailing dot. See\n\t\t\t\t\t// https://tools.ietf.org/html/rfc6066#section-3.\n\t\t\t\t\tif strings.HasSuffix(serverName, \".\") {\n\t\t\t\t\t\treturn errNotClientHello\n\t\t\t\t\t}\n\t\t\t\t\th.domain = serverName\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t\td = d[nameLen:]\n\t\t\t}\n\t\t}\n\t\tdata = data[length:]\n\t}\n\n\treturn errNotTLS\n}\n\nfunc SniffTLS(b []byte) (*SniffHeader, error) {\n\tif len(b) < 5 {\n\t\treturn nil, common.ErrNoClue\n\t}\n\n\tif b[0] != 0x16 /* TLS Handshake */ {\n\t\treturn nil, errNotTLS\n\t}\n\tif !IsValidTLSVersion(b[1], b[2]) {\n\t\treturn nil, errNotTLS\n\t}\n\theaderLen := int(binary.BigEndian.Uint16(b[3:5]))\n\tif 5+headerLen > len(b) {\n\t\treturn nil, common.ErrNoClue\n\t}\n\n\th := &SniffHeader{}\n\terr := ReadClientHello(b[5:5+headerLen], h)\n\tif err == nil {\n\t\treturn h, nil\n\t}\n\treturn nil, err\n}\n"
  },
  {
    "path": "common/protocol/tls/sniff_test.go",
    "content": "package tls_test\n\nimport (\n\t\"testing\"\n\n\t. \"v2ray.com/core/common/protocol/tls\"\n)\n\nfunc TestTLSHeaders(t *testing.T) {\n\tcases := []struct {\n\t\tinput  []byte\n\t\tdomain string\n\t\terr    bool\n\t}{\n\t\t{\n\t\t\tinput: []byte{\n\t\t\t\t0x16, 0x03, 0x01, 0x00, 0xc8, 0x01, 0x00, 0x00,\n\t\t\t\t0xc4, 0x03, 0x03, 0x1a, 0xac, 0xb2, 0xa8, 0xfe,\n\t\t\t\t0xb4, 0x96, 0x04, 0x5b, 0xca, 0xf7, 0xc1, 0xf4,\n\t\t\t\t0x2e, 0x53, 0x24, 0x6e, 0x34, 0x0c, 0x58, 0x36,\n\t\t\t\t0x71, 0x97, 0x59, 0xe9, 0x41, 0x66, 0xe2, 0x43,\n\t\t\t\t0xa0, 0x13, 0xb6, 0x00, 0x00, 0x20, 0x1a, 0x1a,\n\t\t\t\t0xc0, 0x2b, 0xc0, 0x2f, 0xc0, 0x2c, 0xc0, 0x30,\n\t\t\t\t0xcc, 0xa9, 0xcc, 0xa8, 0xcc, 0x14, 0xcc, 0x13,\n\t\t\t\t0xc0, 0x13, 0xc0, 0x14, 0x00, 0x9c, 0x00, 0x9d,\n\t\t\t\t0x00, 0x2f, 0x00, 0x35, 0x00, 0x0a, 0x01, 0x00,\n\t\t\t\t0x00, 0x7b, 0xba, 0xba, 0x00, 0x00, 0xff, 0x01,\n\t\t\t\t0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00,\n\t\t\t\t0x14, 0x00, 0x00, 0x11, 0x63, 0x2e, 0x73, 0x2d,\n\t\t\t\t0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66,\n\t\t\t\t0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x17, 0x00,\n\t\t\t\t0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x0d, 0x00,\n\t\t\t\t0x14, 0x00, 0x12, 0x04, 0x03, 0x08, 0x04, 0x04,\n\t\t\t\t0x01, 0x05, 0x03, 0x08, 0x05, 0x05, 0x01, 0x08,\n\t\t\t\t0x06, 0x06, 0x01, 0x02, 0x01, 0x00, 0x05, 0x00,\n\t\t\t\t0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12,\n\t\t\t\t0x00, 0x00, 0x00, 0x10, 0x00, 0x0e, 0x00, 0x0c,\n\t\t\t\t0x02, 0x68, 0x32, 0x08, 0x68, 0x74, 0x74, 0x70,\n\t\t\t\t0x2f, 0x31, 0x2e, 0x31, 0x00, 0x0b, 0x00, 0x02,\n\t\t\t\t0x01, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x08,\n\t\t\t\t0xaa, 0xaa, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18,\n\t\t\t\t0xaa, 0xaa, 0x00, 0x01, 0x00,\n\t\t\t},\n\t\t\tdomain: \"c.s-microsoft.com\",\n\t\t\terr:    false,\n\t\t},\n\t\t{\n\t\t\tinput: []byte{\n\t\t\t\t0x16, 0x03, 0x01, 0x00, 0xee, 0x01, 0x00, 0x00,\n\t\t\t\t0xea, 0x03, 0x03, 0xe7, 0x91, 0x9e, 0x93, 0xca,\n\t\t\t\t0x78, 0x1b, 0x3c, 0xe0, 0x65, 0x25, 0x58, 0xb5,\n\t\t\t\t0x93, 0xe1, 0x0f, 0x85, 0xec, 0x9a, 0x66, 0x8e,\n\t\t\t\t0x61, 0x82, 0x88, 0xc8, 0xfc, 0xae, 0x1e, 0xca,\n\t\t\t\t0xd7, 0xa5, 0x63, 0x20, 0xbd, 0x1c, 0x00, 0x00,\n\t\t\t\t0x8b, 0xee, 0x09, 0xe3, 0x47, 0x6a, 0x0e, 0x74,\n\t\t\t\t0xb0, 0xbc, 0xa3, 0x02, 0xa7, 0x35, 0xe8, 0x85,\n\t\t\t\t0x70, 0x7c, 0x7a, 0xf0, 0x00, 0xdf, 0x4a, 0xea,\n\t\t\t\t0x87, 0x01, 0x14, 0x91, 0x00, 0x20, 0xea, 0xea,\n\t\t\t\t0xc0, 0x2b, 0xc0, 0x2f, 0xc0, 0x2c, 0xc0, 0x30,\n\t\t\t\t0xcc, 0xa9, 0xcc, 0xa8, 0xcc, 0x14, 0xcc, 0x13,\n\t\t\t\t0xc0, 0x13, 0xc0, 0x14, 0x00, 0x9c, 0x00, 0x9d,\n\t\t\t\t0x00, 0x2f, 0x00, 0x35, 0x00, 0x0a, 0x01, 0x00,\n\t\t\t\t0x00, 0x81, 0x9a, 0x9a, 0x00, 0x00, 0xff, 0x01,\n\t\t\t\t0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00,\n\t\t\t\t0x16, 0x00, 0x00, 0x13, 0x77, 0x77, 0x77, 0x30,\n\t\t\t\t0x37, 0x2e, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x74,\n\t\t\t\t0x61, 0x6c, 0x65, 0x2e, 0x6e, 0x65, 0x74, 0x00,\n\t\t\t\t0x17, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,\n\t\t\t\t0x0d, 0x00, 0x14, 0x00, 0x12, 0x04, 0x03, 0x08,\n\t\t\t\t0x04, 0x04, 0x01, 0x05, 0x03, 0x08, 0x05, 0x05,\n\t\t\t\t0x01, 0x08, 0x06, 0x06, 0x01, 0x02, 0x01, 0x00,\n\t\t\t\t0x05, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00,\n\t\t\t\t0x00, 0x12, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0e,\n\t\t\t\t0x00, 0x0c, 0x02, 0x68, 0x32, 0x08, 0x68, 0x74,\n\t\t\t\t0x74, 0x70, 0x2f, 0x31, 0x2e, 0x31, 0x75, 0x50,\n\t\t\t\t0x00, 0x00, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00,\n\t\t\t\t0x00, 0x0a, 0x00, 0x0a, 0x00, 0x08, 0x9a, 0x9a,\n\t\t\t\t0x00, 0x1d, 0x00, 0x17, 0x00, 0x18, 0x8a, 0x8a,\n\t\t\t\t0x00, 0x01, 0x00,\n\t\t\t},\n\t\t\tdomain: \"www07.clicktale.net\",\n\t\t\terr:    false,\n\t\t},\n\t\t{\n\t\t\tinput: []byte{\n\t\t\t\t0x16, 0x03, 0x01, 0x00, 0xe6, 0x01, 0x00, 0x00, 0xe2, 0x03, 0x03, 0x81, 0x47, 0xc1,\n\t\t\t\t0x66, 0xd5, 0x1b, 0xfa, 0x4b, 0xb5, 0xe0, 0x2a, 0xe1, 0xa7, 0x87, 0x13, 0x1d, 0x11, 0xaa, 0xc6,\n\t\t\t\t0xce, 0xfc, 0x7f, 0xab, 0x94, 0xc8, 0x62, 0xad, 0xc8, 0xab, 0x0c, 0xdd, 0xcb, 0x20, 0x6f, 0x9d,\n\t\t\t\t0x07, 0xf1, 0x95, 0x3e, 0x99, 0xd8, 0xf3, 0x6d, 0x97, 0xee, 0x19, 0x0b, 0x06, 0x1b, 0xf4, 0x84,\n\t\t\t\t0x0b, 0xb6, 0x8f, 0xcc, 0xde, 0xe2, 0xd0, 0x2d, 0x6b, 0x0c, 0x1f, 0x52, 0x53, 0x13, 0x00, 0x08,\n\t\t\t\t0x13, 0x02, 0x13, 0x03, 0x13, 0x01, 0x00, 0xff, 0x01, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x0c,\n\t\t\t\t0x00, 0x0a, 0x00, 0x00, 0x07, 0x64, 0x6f, 0x67, 0x66, 0x69, 0x73, 0x68, 0x00, 0x0b, 0x00, 0x04,\n\t\t\t\t0x03, 0x00, 0x01, 0x02, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x0a, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x1e,\n\t\t\t\t0x00, 0x19, 0x00, 0x18, 0x00, 0x23, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00,\n\t\t\t\t0x00, 0x0d, 0x00, 0x1e, 0x00, 0x1c, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x08, 0x07, 0x08, 0x08,\n\t\t\t\t0x08, 0x09, 0x08, 0x0a, 0x08, 0x0b, 0x08, 0x04, 0x08, 0x05, 0x08, 0x06, 0x04, 0x01, 0x05, 0x01,\n\t\t\t\t0x06, 0x01, 0x00, 0x2b, 0x00, 0x07, 0x06, 0x7f, 0x1c, 0x7f, 0x1b, 0x7f, 0x1a, 0x00, 0x2d, 0x00,\n\t\t\t\t0x02, 0x01, 0x01, 0x00, 0x33, 0x00, 0x26, 0x00, 0x24, 0x00, 0x1d, 0x00, 0x20, 0x2f, 0x35, 0x0c,\n\t\t\t\t0xb6, 0x90, 0x0a, 0xb7, 0xd5, 0xc4, 0x1b, 0x2f, 0x60, 0xaa, 0x56, 0x7b, 0x3f, 0x71, 0xc8, 0x01,\n\t\t\t\t0x7e, 0x86, 0xd3, 0xb7, 0x0c, 0x29, 0x1a, 0x9e, 0x5b, 0x38, 0x3f, 0x01, 0x72,\n\t\t\t},\n\t\t\tdomain: \"dogfish\",\n\t\t\terr:    false,\n\t\t},\n\t\t{\n\t\t\tinput: []byte{\n\t\t\t\t0x16, 0x03, 0x01, 0x01, 0x03, 0x01, 0x00, 0x00,\n\t\t\t\t0xff, 0x03, 0x03, 0x3d, 0x89, 0x52, 0x9e, 0xee,\n\t\t\t\t0xbe, 0x17, 0x63, 0x75, 0xef, 0x29, 0xbd, 0x14,\n\t\t\t\t0x6a, 0x49, 0xe0, 0x2c, 0x37, 0x57, 0x71, 0x62,\n\t\t\t\t0x82, 0x44, 0x94, 0x8f, 0x6e, 0x94, 0x08, 0x45,\n\t\t\t\t0x7f, 0xdb, 0xc1, 0x00, 0x00, 0x3e, 0xc0, 0x2c,\n\t\t\t\t0xc0, 0x30, 0x00, 0x9f, 0xcc, 0xa9, 0xcc, 0xa8,\n\t\t\t\t0xcc, 0xaa, 0xc0, 0x2b, 0xc0, 0x2f, 0x00, 0x9e,\n\t\t\t\t0xc0, 0x24, 0xc0, 0x28, 0x00, 0x6b, 0xc0, 0x23,\n\t\t\t\t0xc0, 0x27, 0x00, 0x67, 0xc0, 0x0a, 0xc0, 0x14,\n\t\t\t\t0x00, 0x39, 0xc0, 0x09, 0xc0, 0x13, 0x00, 0x33,\n\t\t\t\t0x00, 0x9d, 0x00, 0x9c, 0x13, 0x02, 0x13, 0x03,\n\t\t\t\t0x13, 0x01, 0x00, 0x3d, 0x00, 0x3c, 0x00, 0x35,\n\t\t\t\t0x00, 0x2f, 0x00, 0xff, 0x01, 0x00, 0x00, 0x98,\n\t\t\t\t0x00, 0x00, 0x00, 0x10, 0x00, 0x0e, 0x00, 0x00,\n\t\t\t\t0x0b, 0x31, 0x30, 0x2e, 0x34, 0x32, 0x2e, 0x30,\n\t\t\t\t0x2e, 0x32, 0x34, 0x33, 0x00, 0x0b, 0x00, 0x04,\n\t\t\t\t0x03, 0x00, 0x01, 0x02, 0x00, 0x0a, 0x00, 0x0a,\n\t\t\t\t0x00, 0x08, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x19,\n\t\t\t\t0x00, 0x18, 0x00, 0x23, 0x00, 0x00, 0x00, 0x0d,\n\t\t\t\t0x00, 0x20, 0x00, 0x1e, 0x04, 0x03, 0x05, 0x03,\n\t\t\t\t0x06, 0x03, 0x08, 0x04, 0x08, 0x05, 0x08, 0x06,\n\t\t\t\t0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x02, 0x03,\n\t\t\t\t0x02, 0x01, 0x02, 0x02, 0x04, 0x02, 0x05, 0x02,\n\t\t\t\t0x06, 0x02, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17,\n\t\t\t\t0x00, 0x00, 0x00, 0x2b, 0x00, 0x09, 0x08, 0x7f,\n\t\t\t\t0x14, 0x03, 0x03, 0x03, 0x02, 0x03, 0x01, 0x00,\n\t\t\t\t0x2d, 0x00, 0x03, 0x02, 0x01, 0x00, 0x00, 0x28,\n\t\t\t\t0x00, 0x26, 0x00, 0x24, 0x00, 0x1d, 0x00, 0x20,\n\t\t\t\t0x13, 0x7c, 0x6e, 0x97, 0xc4, 0xfd, 0x09, 0x2e,\n\t\t\t\t0x70, 0x2f, 0x73, 0x5a, 0x9b, 0x57, 0x4d, 0x5f,\n\t\t\t\t0x2b, 0x73, 0x2c, 0xa5, 0x4a, 0x98, 0x40, 0x3d,\n\t\t\t\t0x75, 0x6e, 0xb4, 0x76, 0xf9, 0x48, 0x8f, 0x36,\n\t\t\t},\n\t\t\tdomain: \"10.42.0.243\",\n\t\t\terr:    false,\n\t\t},\n\t}\n\n\tfor _, test := range cases {\n\t\theader, err := SniffTLS(test.input)\n\t\tif test.err {\n\t\t\tif err == nil {\n\t\t\t\tt.Errorf(\"Exepct error but nil in test %v\", test)\n\t\t\t}\n\t\t} else {\n\t\t\tif err != nil {\n\t\t\t\tt.Errorf(\"Expect no error but actually %s in test %v\", err.Error(), test)\n\t\t\t}\n\t\t\tif header.Domain() != test.domain {\n\t\t\t\tt.Error(\"expect domain \", test.domain, \" but got \", header.Domain())\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "common/protocol/udp/packet.go",
    "content": "package udp\n\nimport (\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/net\"\n)\n\n// Packet is a UDP packet together with its source and destination address.\ntype Packet struct {\n\tPayload *buf.Buffer\n\tSource  net.Destination\n\tTarget  net.Destination\n}\n"
  },
  {
    "path": "common/protocol/udp/udp.go",
    "content": "package udp\n"
  },
  {
    "path": "common/protocol/user.go",
    "content": "package protocol\n\nfunc (u *User) GetTypedAccount() (Account, error) {\n\tif u.GetAccount() == nil {\n\t\treturn nil, newError(\"Account missing\").AtWarning()\n\t}\n\n\trawAccount, err := u.Account.GetInstance()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif asAccount, ok := rawAccount.(AsAccount); ok {\n\t\treturn asAccount.AsAccount()\n\t}\n\tif account, ok := rawAccount.(Account); ok {\n\t\treturn account, nil\n\t}\n\treturn nil, newError(\"Unknown account type: \", u.Account.Type)\n}\n\nfunc (u *User) ToMemoryUser() (*MemoryUser, error) {\n\taccount, err := u.GetTypedAccount()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &MemoryUser{\n\t\tAccount: account,\n\t\tEmail:   u.Email,\n\t\tLevel:   u.Level,\n\t}, nil\n}\n\n// MemoryUser is a parsed form of User, to reduce number of parsing of Account proto.\ntype MemoryUser struct {\n\t// Account is the parsed account of the protocol.\n\tAccount Account\n\tEmail   string\n\tLevel   uint32\n}\n"
  },
  {
    "path": "common/protocol/user.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: common/protocol/user.proto\n\npackage protocol\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n\tserial \"v2ray.com/core/common/serial\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\n// User is a generic user for all procotols.\ntype User struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tLevel uint32 `protobuf:\"varint,1,opt,name=level,proto3\" json:\"level,omitempty\"`\n\tEmail string `protobuf:\"bytes,2,opt,name=email,proto3\" json:\"email,omitempty\"`\n\t// Protocol specific account information. Must be the account proto in one of\n\t// the proxies.\n\tAccount *serial.TypedMessage `protobuf:\"bytes,3,opt,name=account,proto3\" json:\"account,omitempty\"`\n}\n\nfunc (x *User) Reset() {\n\t*x = User{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_common_protocol_user_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *User) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*User) ProtoMessage() {}\n\nfunc (x *User) ProtoReflect() protoreflect.Message {\n\tmi := &file_common_protocol_user_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use User.ProtoReflect.Descriptor instead.\nfunc (*User) Descriptor() ([]byte, []int) {\n\treturn file_common_protocol_user_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *User) GetLevel() uint32 {\n\tif x != nil {\n\t\treturn x.Level\n\t}\n\treturn 0\n}\n\nfunc (x *User) GetEmail() string {\n\tif x != nil {\n\t\treturn x.Email\n\t}\n\treturn \"\"\n}\n\nfunc (x *User) GetAccount() *serial.TypedMessage {\n\tif x != nil {\n\t\treturn x.Account\n\t}\n\treturn nil\n}\n\nvar File_common_protocol_user_proto protoreflect.FileDescriptor\n\nvar file_common_protocol_user_proto_rawDesc = []byte{\n\t0x0a, 0x1a, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,\n\t0x6c, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1a, 0x76, 0x32,\n\t0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e,\n\t0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,\n\t0x2f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x6d, 0x65,\n\t0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x74, 0x0a, 0x04, 0x55,\n\t0x73, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01,\n\t0x28, 0x0d, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61,\n\t0x69, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12,\n\t0x40, 0x0a, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b,\n\t0x32, 0x26, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f,\n\t0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65,\n\t0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e,\n\t0x74, 0x42, 0x5f, 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,\n\t0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,\n\t0x63, 0x6f, 0x6c, 0x50, 0x01, 0x5a, 0x1e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d,\n\t0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f,\n\t0x74, 0x6f, 0x63, 0x6f, 0x6c, 0xaa, 0x02, 0x1a, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f,\n\t0x72, 0x65, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63,\n\t0x6f, 0x6c, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_common_protocol_user_proto_rawDescOnce sync.Once\n\tfile_common_protocol_user_proto_rawDescData = file_common_protocol_user_proto_rawDesc\n)\n\nfunc file_common_protocol_user_proto_rawDescGZIP() []byte {\n\tfile_common_protocol_user_proto_rawDescOnce.Do(func() {\n\t\tfile_common_protocol_user_proto_rawDescData = protoimpl.X.CompressGZIP(file_common_protocol_user_proto_rawDescData)\n\t})\n\treturn file_common_protocol_user_proto_rawDescData\n}\n\nvar file_common_protocol_user_proto_msgTypes = make([]protoimpl.MessageInfo, 1)\nvar file_common_protocol_user_proto_goTypes = []interface{}{\n\t(*User)(nil),                // 0: v2ray.core.common.protocol.User\n\t(*serial.TypedMessage)(nil), // 1: v2ray.core.common.serial.TypedMessage\n}\nvar file_common_protocol_user_proto_depIdxs = []int32{\n\t1, // 0: v2ray.core.common.protocol.User.account:type_name -> v2ray.core.common.serial.TypedMessage\n\t1, // [1:1] is the sub-list for method output_type\n\t1, // [1:1] is the sub-list for method input_type\n\t1, // [1:1] is the sub-list for extension type_name\n\t1, // [1:1] is the sub-list for extension extendee\n\t0, // [0:1] is the sub-list for field type_name\n}\n\nfunc init() { file_common_protocol_user_proto_init() }\nfunc file_common_protocol_user_proto_init() {\n\tif File_common_protocol_user_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_common_protocol_user_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*User); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_common_protocol_user_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   1,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_common_protocol_user_proto_goTypes,\n\t\tDependencyIndexes: file_common_protocol_user_proto_depIdxs,\n\t\tMessageInfos:      file_common_protocol_user_proto_msgTypes,\n\t}.Build()\n\tFile_common_protocol_user_proto = out.File\n\tfile_common_protocol_user_proto_rawDesc = nil\n\tfile_common_protocol_user_proto_goTypes = nil\n\tfile_common_protocol_user_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "common/protocol/user.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.common.protocol;\noption csharp_namespace = \"V2Ray.Core.Common.Protocol\";\noption go_package = \"v2ray.com/core/common/protocol\";\noption java_package = \"com.v2ray.core.common.protocol\";\noption java_multiple_files = true;\n\nimport \"common/serial/typed_message.proto\";\n\n// User is a generic user for all procotols.\nmessage User {\n  uint32 level = 1;\n  string email = 2;\n\n  // Protocol specific account information. Must be the account proto in one of\n  // the proxies.\n  v2ray.core.common.serial.TypedMessage account = 3;\n}\n"
  },
  {
    "path": "common/retry/errors.generated.go",
    "content": "package retry\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "common/retry/retry.go",
    "content": "package retry // import \"v2ray.com/core/common/retry\"\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n\nimport (\n\t\"time\"\n)\n\nvar (\n\tErrRetryFailed = newError(\"all retry attempts failed\")\n)\n\n// Strategy is a way to retry on a specific function.\ntype Strategy interface {\n\t// On performs a retry on a specific function, until it doesn't return any error.\n\tOn(func() error) error\n}\n\ntype retryer struct {\n\ttotalAttempt int\n\tnextDelay    func() uint32\n}\n\n// On implements Strategy.On.\nfunc (r *retryer) On(method func() error) error {\n\tattempt := 0\n\taccumulatedError := make([]error, 0, r.totalAttempt)\n\tfor attempt < r.totalAttempt {\n\t\terr := method()\n\t\tif err == nil {\n\t\t\treturn nil\n\t\t}\n\t\tnumErrors := len(accumulatedError)\n\t\tif numErrors == 0 || err.Error() != accumulatedError[numErrors-1].Error() {\n\t\t\taccumulatedError = append(accumulatedError, err)\n\t\t}\n\t\tdelay := r.nextDelay()\n\t\ttime.Sleep(time.Duration(delay) * time.Millisecond)\n\t\tattempt++\n\t}\n\treturn newError(accumulatedError).Base(ErrRetryFailed)\n}\n\n// Timed returns a retry strategy with fixed interval.\nfunc Timed(attempts int, delay uint32) Strategy {\n\treturn &retryer{\n\t\ttotalAttempt: attempts,\n\t\tnextDelay: func() uint32 {\n\t\t\treturn delay\n\t\t},\n\t}\n}\n\nfunc ExponentialBackoff(attempts int, delay uint32) Strategy {\n\tnextDelay := uint32(0)\n\treturn &retryer{\n\t\ttotalAttempt: attempts,\n\t\tnextDelay: func() uint32 {\n\t\t\tr := nextDelay\n\t\t\tnextDelay += delay\n\t\t\treturn r\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "common/retry/retry_test.go",
    "content": "package retry_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/errors\"\n\t. \"v2ray.com/core/common/retry\"\n)\n\nvar (\n\terrorTestOnly = errors.New(\"This is a fake error.\")\n)\n\nfunc TestNoRetry(t *testing.T) {\n\tstartTime := time.Now().Unix()\n\terr := Timed(10, 100000).On(func() error {\n\t\treturn nil\n\t})\n\tendTime := time.Now().Unix()\n\n\tcommon.Must(err)\n\tif endTime < startTime {\n\t\tt.Error(\"endTime < startTime: \", startTime, \" -> \", endTime)\n\t}\n}\n\nfunc TestRetryOnce(t *testing.T) {\n\tstartTime := time.Now()\n\tcalled := 0\n\terr := Timed(10, 1000).On(func() error {\n\t\tif called == 0 {\n\t\t\tcalled++\n\t\t\treturn errorTestOnly\n\t\t}\n\t\treturn nil\n\t})\n\tduration := time.Since(startTime)\n\n\tcommon.Must(err)\n\tif v := int64(duration / time.Millisecond); v < 900 {\n\t\tt.Error(\"duration: \", v)\n\t}\n}\n\nfunc TestRetryMultiple(t *testing.T) {\n\tstartTime := time.Now()\n\tcalled := 0\n\terr := Timed(10, 1000).On(func() error {\n\t\tif called < 5 {\n\t\t\tcalled++\n\t\t\treturn errorTestOnly\n\t\t}\n\t\treturn nil\n\t})\n\tduration := time.Since(startTime)\n\n\tcommon.Must(err)\n\tif v := int64(duration / time.Millisecond); v < 4900 {\n\t\tt.Error(\"duration: \", v)\n\t}\n}\n\nfunc TestRetryExhausted(t *testing.T) {\n\tstartTime := time.Now()\n\tcalled := 0\n\terr := Timed(2, 1000).On(func() error {\n\t\tcalled++\n\t\treturn errorTestOnly\n\t})\n\tduration := time.Since(startTime)\n\n\tif errors.Cause(err) != ErrRetryFailed {\n\t\tt.Error(\"cause: \", err)\n\t}\n\n\tif v := int64(duration / time.Millisecond); v < 1900 {\n\t\tt.Error(\"duration: \", v)\n\t}\n}\n\nfunc TestExponentialBackoff(t *testing.T) {\n\tstartTime := time.Now()\n\tcalled := 0\n\terr := ExponentialBackoff(10, 100).On(func() error {\n\t\tcalled++\n\t\treturn errorTestOnly\n\t})\n\tduration := time.Since(startTime)\n\n\tif errors.Cause(err) != ErrRetryFailed {\n\t\tt.Error(\"cause: \", err)\n\t}\n\tif v := int64(duration / time.Millisecond); v < 4000 {\n\t\tt.Error(\"duration: \", v)\n\t}\n}\n"
  },
  {
    "path": "common/serial/serial.go",
    "content": "package serial\n\nimport (\n\t\"encoding/binary\"\n\t\"io\"\n)\n\n// ReadUint16 reads first two bytes from the reader, and then coverts them to an uint16 value.\nfunc ReadUint16(reader io.Reader) (uint16, error) {\n\tvar b [2]byte\n\tif _, err := io.ReadFull(reader, b[:]); err != nil {\n\t\treturn 0, err\n\t}\n\treturn binary.BigEndian.Uint16(b[:]), nil\n}\n\n// WriteUint16 writes an uint16 value into writer.\nfunc WriteUint16(writer io.Writer, value uint16) (int, error) {\n\tvar b [2]byte\n\tbinary.BigEndian.PutUint16(b[:], value)\n\treturn writer.Write(b[:])\n}\n\n// WriteUint64 writes an uint64 value into writer.\nfunc WriteUint64(writer io.Writer, value uint64) (int, error) {\n\tvar b [8]byte\n\tbinary.BigEndian.PutUint64(b[:], value)\n\treturn writer.Write(b[:])\n}\n"
  },
  {
    "path": "common/serial/serial_test.go",
    "content": "package serial_test\n\nimport (\n\t\"bytes\"\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/serial\"\n)\n\nfunc TestUint16Serial(t *testing.T) {\n\tb := buf.New()\n\tdefer b.Release()\n\n\tn, err := serial.WriteUint16(b, 10)\n\tcommon.Must(err)\n\tif n != 2 {\n\t\tt.Error(\"expect 2 bytes writtng, but actually \", n)\n\t}\n\tif diff := cmp.Diff(b.Bytes(), []byte{0, 10}); diff != \"\" {\n\t\tt.Error(diff)\n\t}\n}\n\nfunc TestUint64Serial(t *testing.T) {\n\tb := buf.New()\n\tdefer b.Release()\n\n\tn, err := serial.WriteUint64(b, 10)\n\tcommon.Must(err)\n\tif n != 8 {\n\t\tt.Error(\"expect 8 bytes writtng, but actually \", n)\n\t}\n\tif diff := cmp.Diff(b.Bytes(), []byte{0, 0, 0, 0, 0, 0, 0, 10}); diff != \"\" {\n\t\tt.Error(diff)\n\t}\n}\n\nfunc TestReadUint16(t *testing.T) {\n\ttestCases := []struct {\n\t\tInput  []byte\n\t\tOutput uint16\n\t}{\n\t\t{\n\t\t\tInput:  []byte{0, 1},\n\t\t\tOutput: 1,\n\t\t},\n\t}\n\n\tfor _, testCase := range testCases {\n\t\tv, err := serial.ReadUint16(bytes.NewReader(testCase.Input))\n\t\tcommon.Must(err)\n\t\tif v != testCase.Output {\n\t\t\tt.Error(\"for input \", testCase.Input, \" expect output \", testCase.Output, \" but got \", v)\n\t\t}\n\t}\n}\n\nfunc BenchmarkReadUint16(b *testing.B) {\n\treader := buf.New()\n\tdefer reader.Release()\n\n\tcommon.Must2(reader.Write([]byte{0, 1}))\n\tb.ResetTimer()\n\n\tfor i := 0; i < b.N; i++ {\n\t\t_, err := serial.ReadUint16(reader)\n\t\tcommon.Must(err)\n\t\treader.Clear()\n\t\treader.Extend(2)\n\t}\n}\n\nfunc BenchmarkWriteUint64(b *testing.B) {\n\twriter := buf.New()\n\tdefer writer.Release()\n\n\tb.ResetTimer()\n\n\tfor i := 0; i < b.N; i++ {\n\t\t_, err := serial.WriteUint64(writer, 8)\n\t\tcommon.Must(err)\n\t\twriter.Clear()\n\t}\n}\n"
  },
  {
    "path": "common/serial/string.go",
    "content": "package serial\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\n// ToString serialize an arbitrary value into string.\nfunc ToString(v interface{}) string {\n\tif v == nil {\n\t\treturn \" \"\n\t}\n\n\tswitch value := v.(type) {\n\tcase string:\n\t\treturn value\n\tcase *string:\n\t\treturn *value\n\tcase fmt.Stringer:\n\t\treturn value.String()\n\tcase error:\n\t\treturn value.Error()\n\tdefault:\n\t\treturn fmt.Sprintf(\"%+v\", value)\n\t}\n}\n\n// Concat concatenates all input into a single string.\nfunc Concat(v ...interface{}) string {\n\tbuilder := strings.Builder{}\n\tfor _, value := range v {\n\t\tbuilder.WriteString(ToString(value))\n\t}\n\treturn builder.String()\n}\n"
  },
  {
    "path": "common/serial/string_test.go",
    "content": "package serial_test\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\n\t. \"v2ray.com/core/common/serial\"\n)\n\nfunc TestToString(t *testing.T) {\n\ts := \"a\"\n\tdata := []struct {\n\t\tValue  interface{}\n\t\tString string\n\t}{\n\t\t{Value: s, String: s},\n\t\t{Value: &s, String: s},\n\t\t{Value: errors.New(\"t\"), String: \"t\"},\n\t\t{Value: []byte{'b', 'c'}, String: \"[98 99]\"},\n\t}\n\n\tfor _, c := range data {\n\t\tif r := cmp.Diff(ToString(c.Value), c.String); r != \"\" {\n\t\t\tt.Error(r)\n\t\t}\n\t}\n}\n\nfunc TestConcat(t *testing.T) {\n\ttestCases := []struct {\n\t\tInput  []interface{}\n\t\tOutput string\n\t}{\n\t\t{\n\t\t\tInput: []interface{}{\n\t\t\t\t\"a\", \"b\",\n\t\t\t},\n\t\t\tOutput: \"ab\",\n\t\t},\n\t}\n\n\tfor _, testCase := range testCases {\n\t\tactual := Concat(testCase.Input...)\n\t\tif actual != testCase.Output {\n\t\t\tt.Error(\"Unexpected output: \", actual, \" but want: \", testCase.Output)\n\t\t}\n\t}\n}\n\nfunc BenchmarkConcat(b *testing.B) {\n\tinput := []interface{}{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\", \"i\", \"j\", \"k\"}\n\n\tb.ReportAllocs()\n\tfor i := 0; i < b.N; i++ {\n\t\t_ = Concat(input...)\n\t}\n}\n"
  },
  {
    "path": "common/serial/typed_message.go",
    "content": "package serial\n\nimport (\n\t\"errors\"\n\t\"reflect\"\n\n\t\"github.com/golang/protobuf/proto\"\n)\n\n// ToTypedMessage converts a proto Message into TypedMessage.\nfunc ToTypedMessage(message proto.Message) *TypedMessage {\n\tif message == nil {\n\t\treturn nil\n\t}\n\tsettings, _ := proto.Marshal(message)\n\treturn &TypedMessage{\n\t\tType:  GetMessageType(message),\n\t\tValue: settings,\n\t}\n}\n\n// GetMessageType returns the name of this proto Message.\nfunc GetMessageType(message proto.Message) string {\n\treturn proto.MessageName(message)\n}\n\n// GetInstance creates a new instance of the message with messageType.\nfunc GetInstance(messageType string) (interface{}, error) {\n\tmType := proto.MessageType(messageType)\n\tif mType == nil || mType.Elem() == nil {\n\t\treturn nil, errors.New(\"Serial: Unknown type: \" + messageType)\n\t}\n\treturn reflect.New(mType.Elem()).Interface(), nil\n}\n\n// GetInstance converts current TypedMessage into a proto Message.\nfunc (v *TypedMessage) GetInstance() (proto.Message, error) {\n\tinstance, err := GetInstance(v.Type)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tprotoMessage := instance.(proto.Message)\n\tif err := proto.Unmarshal(v.Value, protoMessage); err != nil {\n\t\treturn nil, err\n\t}\n\treturn protoMessage, nil\n}\n"
  },
  {
    "path": "common/serial/typed_message.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: common/serial/typed_message.proto\n\npackage serial\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\n// TypedMessage is a serialized proto message along with its type name.\ntype TypedMessage struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// The name of the message type, retrieved from protobuf API.\n\tType string `protobuf:\"bytes,1,opt,name=type,proto3\" json:\"type,omitempty\"`\n\t// Serialized proto message.\n\tValue []byte `protobuf:\"bytes,2,opt,name=value,proto3\" json:\"value,omitempty\"`\n}\n\nfunc (x *TypedMessage) Reset() {\n\t*x = TypedMessage{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_common_serial_typed_message_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *TypedMessage) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*TypedMessage) ProtoMessage() {}\n\nfunc (x *TypedMessage) ProtoReflect() protoreflect.Message {\n\tmi := &file_common_serial_typed_message_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use TypedMessage.ProtoReflect.Descriptor instead.\nfunc (*TypedMessage) Descriptor() ([]byte, []int) {\n\treturn file_common_serial_typed_message_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *TypedMessage) GetType() string {\n\tif x != nil {\n\t\treturn x.Type\n\t}\n\treturn \"\"\n}\n\nfunc (x *TypedMessage) GetValue() []byte {\n\tif x != nil {\n\t\treturn x.Value\n\t}\n\treturn nil\n}\n\nvar File_common_serial_typed_message_proto protoreflect.FileDescriptor\n\nvar file_common_serial_typed_message_proto_rawDesc = []byte{\n\t0x0a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2f,\n\t0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72,\n\t0x6f, 0x74, 0x6f, 0x12, 0x18, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,\n\t0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x22, 0x38, 0x0a,\n\t0x0c, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a,\n\t0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70,\n\t0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c,\n\t0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x59, 0x0a, 0x1c, 0x63, 0x6f, 0x6d, 0x2e, 0x76,\n\t0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,\n\t0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x50, 0x01, 0x5a, 0x1c, 0x76, 0x32, 0x72, 0x61, 0x79,\n\t0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,\n\t0x2f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0xaa, 0x02, 0x18, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e,\n\t0x43, 0x6f, 0x72, 0x65, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x72, 0x69,\n\t0x61, 0x6c, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_common_serial_typed_message_proto_rawDescOnce sync.Once\n\tfile_common_serial_typed_message_proto_rawDescData = file_common_serial_typed_message_proto_rawDesc\n)\n\nfunc file_common_serial_typed_message_proto_rawDescGZIP() []byte {\n\tfile_common_serial_typed_message_proto_rawDescOnce.Do(func() {\n\t\tfile_common_serial_typed_message_proto_rawDescData = protoimpl.X.CompressGZIP(file_common_serial_typed_message_proto_rawDescData)\n\t})\n\treturn file_common_serial_typed_message_proto_rawDescData\n}\n\nvar file_common_serial_typed_message_proto_msgTypes = make([]protoimpl.MessageInfo, 1)\nvar file_common_serial_typed_message_proto_goTypes = []interface{}{\n\t(*TypedMessage)(nil), // 0: v2ray.core.common.serial.TypedMessage\n}\nvar file_common_serial_typed_message_proto_depIdxs = []int32{\n\t0, // [0:0] is the sub-list for method output_type\n\t0, // [0:0] is the sub-list for method input_type\n\t0, // [0:0] is the sub-list for extension type_name\n\t0, // [0:0] is the sub-list for extension extendee\n\t0, // [0:0] is the sub-list for field type_name\n}\n\nfunc init() { file_common_serial_typed_message_proto_init() }\nfunc file_common_serial_typed_message_proto_init() {\n\tif File_common_serial_typed_message_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_common_serial_typed_message_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*TypedMessage); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_common_serial_typed_message_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   1,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_common_serial_typed_message_proto_goTypes,\n\t\tDependencyIndexes: file_common_serial_typed_message_proto_depIdxs,\n\t\tMessageInfos:      file_common_serial_typed_message_proto_msgTypes,\n\t}.Build()\n\tFile_common_serial_typed_message_proto = out.File\n\tfile_common_serial_typed_message_proto_rawDesc = nil\n\tfile_common_serial_typed_message_proto_goTypes = nil\n\tfile_common_serial_typed_message_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "common/serial/typed_message.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.common.serial;\noption csharp_namespace = \"V2Ray.Core.Common.Serial\";\noption go_package = \"v2ray.com/core/common/serial\";\noption java_package = \"com.v2ray.core.common.serial\";\noption java_multiple_files = true;\n\n// TypedMessage is a serialized proto message along with its type name.\nmessage TypedMessage {\n  // The name of the message type, retrieved from protobuf API.\n  string type = 1;\n  // Serialized proto message.\n  bytes value = 2;\n}\n"
  },
  {
    "path": "common/serial/typed_message_test.go",
    "content": "package serial_test\n\nimport (\n\t\"testing\"\n\n\t. \"v2ray.com/core/common/serial\"\n)\n\nfunc TestGetInstance(t *testing.T) {\n\tp, err := GetInstance(\"\")\n\tif p != nil {\n\t\tt.Error(\"expected nil instance, but got \", p)\n\t}\n\tif err == nil {\n\t\tt.Error(\"expect non-nil error, but got nil\")\n\t}\n}\n\nfunc TestConvertingNilMessage(t *testing.T) {\n\tx := ToTypedMessage(nil)\n\tif x != nil {\n\t\tt.Error(\"expect nil, but actually not\")\n\t}\n}\n"
  },
  {
    "path": "common/session/context.go",
    "content": "package session\n\nimport \"context\"\n\ntype sessionKey int\n\nconst (\n\tidSessionKey sessionKey = iota\n\tinboundSessionKey\n\toutboundSessionKey\n\tcontentSessionKey\n\tmuxPreferedSessionKey\n\tsockoptSessionKey\n)\n\n// ContextWithID returns a new context with the given ID.\nfunc ContextWithID(ctx context.Context, id ID) context.Context {\n\treturn context.WithValue(ctx, idSessionKey, id)\n}\n\n// IDFromContext returns ID in this context, or 0 if not contained.\nfunc IDFromContext(ctx context.Context) ID {\n\tif id, ok := ctx.Value(idSessionKey).(ID); ok {\n\t\treturn id\n\t}\n\treturn 0\n}\n\nfunc ContextWithInbound(ctx context.Context, inbound *Inbound) context.Context {\n\treturn context.WithValue(ctx, inboundSessionKey, inbound)\n}\n\nfunc InboundFromContext(ctx context.Context) *Inbound {\n\tif inbound, ok := ctx.Value(inboundSessionKey).(*Inbound); ok {\n\t\treturn inbound\n\t}\n\treturn nil\n}\n\nfunc ContextWithOutbound(ctx context.Context, outbound *Outbound) context.Context {\n\treturn context.WithValue(ctx, outboundSessionKey, outbound)\n}\n\nfunc OutboundFromContext(ctx context.Context) *Outbound {\n\tif outbound, ok := ctx.Value(outboundSessionKey).(*Outbound); ok {\n\t\treturn outbound\n\t}\n\treturn nil\n}\n\nfunc ContextWithContent(ctx context.Context, content *Content) context.Context {\n\treturn context.WithValue(ctx, contentSessionKey, content)\n}\n\nfunc ContentFromContext(ctx context.Context) *Content {\n\tif content, ok := ctx.Value(contentSessionKey).(*Content); ok {\n\t\treturn content\n\t}\n\treturn nil\n}\n\n// ContextWithMuxPrefered returns a new context with the given bool\nfunc ContextWithMuxPrefered(ctx context.Context, forced bool) context.Context {\n\treturn context.WithValue(ctx, muxPreferedSessionKey, forced)\n}\n\n// MuxPreferedFromContext returns value in this context, or false if not contained.\nfunc MuxPreferedFromContext(ctx context.Context) bool {\n\tif val, ok := ctx.Value(muxPreferedSessionKey).(bool); ok {\n\t\treturn val\n\t}\n\treturn false\n}\n\n// ContextWithSockopt returns a new context with Socket configs included\nfunc ContextWithSockopt(ctx context.Context, s *Sockopt) context.Context {\n\treturn context.WithValue(ctx, sockoptSessionKey, s)\n}\n\n// SockoptFromContext returns Socket configs in this context, or nil if not contained.\nfunc SockoptFromContext(ctx context.Context) *Sockopt {\n\tif sockopt, ok := ctx.Value(sockoptSessionKey).(*Sockopt); ok {\n\t\treturn sockopt\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "common/session/session.go",
    "content": "// Package session provides functions for sessions of incoming requests.\npackage session // import \"v2ray.com/core/common/session\"\n\nimport (\n\t\"context\"\n\t\"math/rand\"\n\n\t\"v2ray.com/core/common/errors\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n)\n\n// ID of a session.\ntype ID uint32\n\n// NewID generates a new ID. The generated ID is high likely to be unique, but not cryptographically secure.\n// The generated ID will never be 0.\nfunc NewID() ID {\n\tfor {\n\t\tid := ID(rand.Uint32())\n\t\tif id != 0 {\n\t\t\treturn id\n\t\t}\n\t}\n}\n\n// ExportIDToError transfers session.ID into an error object, for logging purpose.\n// This can be used with error.WriteToLog().\nfunc ExportIDToError(ctx context.Context) errors.ExportOption {\n\tid := IDFromContext(ctx)\n\treturn func(h *errors.ExportOptionHolder) {\n\t\th.SessionID = uint32(id)\n\t}\n}\n\n// Inbound is the metadata of an inbound connection.\ntype Inbound struct {\n\t// Source address of the inbound connection.\n\tSource net.Destination\n\t// Getaway address\n\tGateway net.Destination\n\t// Tag of the inbound proxy that handles the connection.\n\tTag string\n\t// User is the user that authencates for the inbound. May be nil if the protocol allows anounymous traffic.\n\tUser *protocol.MemoryUser\n}\n\n// Outbound is the metadata of an outbound connection.\ntype Outbound struct {\n\t// Target address of the outbound connection.\n\tTarget net.Destination\n\t// Gateway address\n\tGateway net.Address\n}\n\n// SniffingRequest controls the behavior of content sniffing.\ntype SniffingRequest struct {\n\tOverrideDestinationForProtocol []string\n\tEnabled                        bool\n}\n\n// Content is the metadata of the connection content.\ntype Content struct {\n\t// Protocol of current content.\n\tProtocol string\n\n\tSniffingRequest SniffingRequest\n\n\tAttributes map[string]string\n\n\tSkipRoutePick bool\n}\n\n// Sockopt is the settings for socket connection.\ntype Sockopt struct {\n\t// Mark of the socket connection.\n\tMark int32\n}\n\n// SetAttribute attachs additional string attributes to content.\nfunc (c *Content) SetAttribute(name string, value string) {\n\tif c.Attributes == nil {\n\t\tc.Attributes = make(map[string]string)\n\t}\n\tc.Attributes[name] = value\n}\n\n// Attribute retrieves additional string attributes from content.\nfunc (c *Content) Attribute(name string) string {\n\tif c.Attributes == nil {\n\t\treturn \"\"\n\t}\n\treturn c.Attributes[name]\n}\n"
  },
  {
    "path": "common/signal/done/done.go",
    "content": "package done\n\nimport (\n\t\"sync\"\n)\n\n// Instance is a utility for notifications of something being done.\ntype Instance struct {\n\taccess sync.Mutex\n\tc      chan struct{}\n\tclosed bool\n}\n\n// New returns a new Done.\nfunc New() *Instance {\n\treturn &Instance{\n\t\tc: make(chan struct{}),\n\t}\n}\n\n// Done returns true if Close() is called.\nfunc (d *Instance) Done() bool {\n\tselect {\n\tcase <-d.Wait():\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\n\n// Wait returns a channel for waiting for done.\nfunc (d *Instance) Wait() <-chan struct{} {\n\treturn d.c\n}\n\n// Close marks this Done 'done'. This method may be called multiple times. All calls after first call will have no effect on its status.\nfunc (d *Instance) Close() error {\n\td.access.Lock()\n\tdefer d.access.Unlock()\n\n\tif d.closed {\n\t\treturn nil\n\t}\n\n\td.closed = true\n\tclose(d.c)\n\n\treturn nil\n}\n"
  },
  {
    "path": "common/signal/notifier.go",
    "content": "package signal\n\n// Notifier is a utility for notifying changes. The change producer may notify changes multiple time, and the consumer may get notified asynchronously.\ntype Notifier struct {\n\tc chan struct{}\n}\n\n// NewNotifier creates a new Notifier.\nfunc NewNotifier() *Notifier {\n\treturn &Notifier{\n\t\tc: make(chan struct{}, 1),\n\t}\n}\n\n// Signal signals a change, usually by producer. This method never blocks.\nfunc (n *Notifier) Signal() {\n\tselect {\n\tcase n.c <- struct{}{}:\n\tdefault:\n\t}\n}\n\n// Wait returns a channel for waiting for changes. The returned channel never gets closed.\nfunc (n *Notifier) Wait() <-chan struct{} {\n\treturn n.c\n}\n"
  },
  {
    "path": "common/signal/notifier_test.go",
    "content": "package signal_test\n\nimport (\n\t\"testing\"\n\n\t. \"v2ray.com/core/common/signal\"\n)\n\nfunc TestNotifierSignal(t *testing.T) {\n\tn := NewNotifier()\n\n\tw := n.Wait()\n\tn.Signal()\n\n\tselect {\n\tcase <-w:\n\tdefault:\n\t\tt.Fail()\n\t}\n}\n"
  },
  {
    "path": "common/signal/pubsub/pubsub.go",
    "content": "package pubsub\n\nimport (\n\t\"errors\"\n\t\"sync\"\n\t\"time\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/signal/done\"\n\t\"v2ray.com/core/common/task\"\n)\n\ntype Subscriber struct {\n\tbuffer chan interface{}\n\tdone   *done.Instance\n}\n\nfunc (s *Subscriber) push(msg interface{}) {\n\tselect {\n\tcase s.buffer <- msg:\n\tdefault:\n\t}\n}\n\nfunc (s *Subscriber) Wait() <-chan interface{} {\n\treturn s.buffer\n}\n\nfunc (s *Subscriber) Close() error {\n\treturn s.done.Close()\n}\n\nfunc (s *Subscriber) IsClosed() bool {\n\treturn s.done.Done()\n}\n\ntype Service struct {\n\tsync.RWMutex\n\tsubs  map[string][]*Subscriber\n\tctask *task.Periodic\n}\n\nfunc NewService() *Service {\n\ts := &Service{\n\t\tsubs: make(map[string][]*Subscriber),\n\t}\n\ts.ctask = &task.Periodic{\n\t\tExecute:  s.Cleanup,\n\t\tInterval: time.Second * 30,\n\t}\n\treturn s\n}\n\n// Cleanup cleans up internal caches of subscribers.\n// Visible for testing only.\nfunc (s *Service) Cleanup() error {\n\ts.Lock()\n\tdefer s.Unlock()\n\n\tif len(s.subs) == 0 {\n\t\treturn errors.New(\"nothing to do\")\n\t}\n\n\tfor name, subs := range s.subs {\n\t\tnewSub := make([]*Subscriber, 0, len(s.subs))\n\t\tfor _, sub := range subs {\n\t\t\tif !sub.IsClosed() {\n\t\t\t\tnewSub = append(newSub, sub)\n\t\t\t}\n\t\t}\n\t\tif len(newSub) == 0 {\n\t\t\tdelete(s.subs, name)\n\t\t} else {\n\t\t\ts.subs[name] = newSub\n\t\t}\n\t}\n\n\tif len(s.subs) == 0 {\n\t\ts.subs = make(map[string][]*Subscriber)\n\t}\n\treturn nil\n}\n\nfunc (s *Service) Subscribe(name string) *Subscriber {\n\tsub := &Subscriber{\n\t\tbuffer: make(chan interface{}, 16),\n\t\tdone:   done.New(),\n\t}\n\ts.Lock()\n\tsubs := append(s.subs[name], sub)\n\ts.subs[name] = subs\n\ts.Unlock()\n\tcommon.Must(s.ctask.Start())\n\treturn sub\n}\n\nfunc (s *Service) Publish(name string, message interface{}) {\n\ts.RLock()\n\tdefer s.RUnlock()\n\n\tfor _, sub := range s.subs[name] {\n\t\tif !sub.IsClosed() {\n\t\t\tsub.push(message)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "common/signal/pubsub/pubsub_test.go",
    "content": "package pubsub_test\n\nimport (\n\t\"testing\"\n\n\t. \"v2ray.com/core/common/signal/pubsub\"\n)\n\nfunc TestPubsub(t *testing.T) {\n\tservice := NewService()\n\n\tsub := service.Subscribe(\"a\")\n\tservice.Publish(\"a\", 1)\n\n\tselect {\n\tcase v := <-sub.Wait():\n\t\tif v != 1 {\n\t\t\tt.Error(\"expected subscribed value 1, but got \", v)\n\t\t}\n\tdefault:\n\t\tt.Fail()\n\t}\n\n\tsub.Close()\n\tservice.Publish(\"a\", 2)\n\n\tselect {\n\tcase <-sub.Wait():\n\t\tt.Fail()\n\tdefault:\n\t}\n\n\tservice.Cleanup()\n}\n"
  },
  {
    "path": "common/signal/semaphore/semaphore.go",
    "content": "package semaphore\n\n// Instance is an implementation of semaphore.\ntype Instance struct {\n\ttoken chan struct{}\n}\n\n// New create a new Semaphore with n permits.\nfunc New(n int) *Instance {\n\ts := &Instance{\n\t\ttoken: make(chan struct{}, n),\n\t}\n\tfor i := 0; i < n; i++ {\n\t\ts.token <- struct{}{}\n\t}\n\treturn s\n}\n\n// Wait returns a channel for acquiring a permit.\nfunc (s *Instance) Wait() <-chan struct{} {\n\treturn s.token\n}\n\n// Signal releases a permit into the semaphore.\nfunc (s *Instance) Signal() {\n\ts.token <- struct{}{}\n}\n"
  },
  {
    "path": "common/signal/timer.go",
    "content": "package signal\n\nimport (\n\t\"context\"\n\t\"sync\"\n\t\"time\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/task\"\n)\n\ntype ActivityUpdater interface {\n\tUpdate()\n}\n\ntype ActivityTimer struct {\n\tsync.RWMutex\n\tupdated   chan struct{}\n\tcheckTask *task.Periodic\n\tonTimeout func()\n}\n\nfunc (t *ActivityTimer) Update() {\n\tselect {\n\tcase t.updated <- struct{}{}:\n\tdefault:\n\t}\n}\n\nfunc (t *ActivityTimer) check() error {\n\tselect {\n\tcase <-t.updated:\n\tdefault:\n\t\tt.finish()\n\t}\n\treturn nil\n}\n\nfunc (t *ActivityTimer) finish() {\n\tt.Lock()\n\tdefer t.Unlock()\n\n\tif t.onTimeout != nil {\n\t\tt.onTimeout()\n\t\tt.onTimeout = nil\n\t}\n\tif t.checkTask != nil {\n\t\tt.checkTask.Close() // nolint: errcheck\n\t\tt.checkTask = nil\n\t}\n}\n\nfunc (t *ActivityTimer) SetTimeout(timeout time.Duration) {\n\tif timeout == 0 {\n\t\tt.finish()\n\t\treturn\n\t}\n\n\tcheckTask := &task.Periodic{\n\t\tInterval: timeout,\n\t\tExecute:  t.check,\n\t}\n\n\tt.Lock()\n\n\tif t.checkTask != nil {\n\t\tt.checkTask.Close() // nolint: errcheck\n\t}\n\tt.checkTask = checkTask\n\tt.Unlock()\n\tt.Update()\n\tcommon.Must(checkTask.Start())\n}\n\nfunc CancelAfterInactivity(ctx context.Context, cancel context.CancelFunc, timeout time.Duration) *ActivityTimer {\n\ttimer := &ActivityTimer{\n\t\tupdated:   make(chan struct{}, 1),\n\t\tonTimeout: cancel,\n\t}\n\ttimer.SetTimeout(timeout)\n\treturn timer\n}\n"
  },
  {
    "path": "common/signal/timer_test.go",
    "content": "package signal_test\n\nimport (\n\t\"context\"\n\t\"runtime\"\n\t\"testing\"\n\t\"time\"\n\n\t. \"v2ray.com/core/common/signal\"\n)\n\nfunc TestActivityTimer(t *testing.T) {\n\tctx, cancel := context.WithCancel(context.Background())\n\ttimer := CancelAfterInactivity(ctx, cancel, time.Second*4)\n\ttime.Sleep(time.Second * 6)\n\tif ctx.Err() == nil {\n\t\tt.Error(\"expected some error, but got nil\")\n\t}\n\truntime.KeepAlive(timer)\n}\n\nfunc TestActivityTimerUpdate(t *testing.T) {\n\tctx, cancel := context.WithCancel(context.Background())\n\ttimer := CancelAfterInactivity(ctx, cancel, time.Second*10)\n\ttime.Sleep(time.Second * 3)\n\tif ctx.Err() != nil {\n\t\tt.Error(\"expected nil, but got \", ctx.Err().Error())\n\t}\n\ttimer.SetTimeout(time.Second * 1)\n\ttime.Sleep(time.Second * 2)\n\tif ctx.Err() == nil {\n\t\tt.Error(\"expcted some error, but got nil\")\n\t}\n\truntime.KeepAlive(timer)\n}\n\nfunc TestActivityTimerNonBlocking(t *testing.T) {\n\tctx, cancel := context.WithCancel(context.Background())\n\ttimer := CancelAfterInactivity(ctx, cancel, 0)\n\ttime.Sleep(time.Second * 1)\n\tselect {\n\tcase <-ctx.Done():\n\tdefault:\n\t\tt.Error(\"context not done\")\n\t}\n\ttimer.SetTimeout(0)\n\ttimer.SetTimeout(1)\n\ttimer.SetTimeout(2)\n}\n\nfunc TestActivityTimerZeroTimeout(t *testing.T) {\n\tctx, cancel := context.WithCancel(context.Background())\n\ttimer := CancelAfterInactivity(ctx, cancel, 0)\n\tselect {\n\tcase <-ctx.Done():\n\tdefault:\n\t\tt.Error(\"context not done\")\n\t}\n\truntime.KeepAlive(timer)\n}\n"
  },
  {
    "path": "common/stack/bytes.go",
    "content": "package stack\n\n// TwoBytes is a [2]byte which is always allocated on stack.\n//\n//go:notinheap\ntype TwoBytes [2]byte\n\n// EightBytes is a [8]byte which is always allocated on stack.\n//\n//go:notinheap\ntype EightBytes [8]byte\n"
  },
  {
    "path": "common/strmatcher/benchmark_test.go",
    "content": "package strmatcher_test\n\nimport (\n\t\"strconv\"\n\t\"testing\"\n\n\t\"v2ray.com/core/common\"\n\t. \"v2ray.com/core/common/strmatcher\"\n)\n\nfunc BenchmarkDomainMatcherGroup(b *testing.B) {\n\tg := new(DomainMatcherGroup)\n\n\tfor i := 1; i <= 1024; i++ {\n\t\tg.Add(strconv.Itoa(i)+\".v2ray.com\", uint32(i))\n\t}\n\n\tb.ResetTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\t_ = g.Match(\"0.v2ray.com\")\n\t}\n}\n\nfunc BenchmarkFullMatcherGroup(b *testing.B) {\n\tg := new(FullMatcherGroup)\n\n\tfor i := 1; i <= 1024; i++ {\n\t\tg.Add(strconv.Itoa(i)+\".v2ray.com\", uint32(i))\n\t}\n\n\tb.ResetTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\t_ = g.Match(\"0.v2ray.com\")\n\t}\n}\n\nfunc BenchmarkMarchGroup(b *testing.B) {\n\tg := new(MatcherGroup)\n\tfor i := 1; i <= 1024; i++ {\n\t\tm, err := Domain.New(strconv.Itoa(i) + \".v2ray.com\")\n\t\tcommon.Must(err)\n\t\tg.Add(m)\n\t}\n\n\tb.ResetTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\t_ = g.Match(\"0.v2ray.com\")\n\t}\n}\n"
  },
  {
    "path": "common/strmatcher/domain_matcher.go",
    "content": "package strmatcher\n\nimport \"strings\"\n\nfunc breakDomain(domain string) []string {\n\treturn strings.Split(domain, \".\")\n}\n\ntype node struct {\n\tvalues []uint32\n\tsub    map[string]*node\n}\n\n// DomainMatcherGroup is a IndexMatcher for a large set of Domain matchers.\n// Visible for testing only.\ntype DomainMatcherGroup struct {\n\troot *node\n}\n\nfunc (g *DomainMatcherGroup) Add(domain string, value uint32) {\n\tif g.root == nil {\n\t\tg.root = new(node)\n\t}\n\n\tcurrent := g.root\n\tparts := breakDomain(domain)\n\tfor i := len(parts) - 1; i >= 0; i-- {\n\t\tpart := parts[i]\n\t\tif current.sub == nil {\n\t\t\tcurrent.sub = make(map[string]*node)\n\t\t}\n\t\tnext := current.sub[part]\n\t\tif next == nil {\n\t\t\tnext = new(node)\n\t\t\tcurrent.sub[part] = next\n\t\t}\n\t\tcurrent = next\n\t}\n\n\tcurrent.values = append(current.values, value)\n}\n\nfunc (g *DomainMatcherGroup) addMatcher(m domainMatcher, value uint32) {\n\tg.Add(string(m), value)\n}\n\nfunc (g *DomainMatcherGroup) Match(domain string) []uint32 {\n\tif domain == \"\" {\n\t\treturn nil\n\t}\n\n\tcurrent := g.root\n\tif current == nil {\n\t\treturn nil\n\t}\n\n\tnextPart := func(idx int) int {\n\t\tfor i := idx - 1; i >= 0; i-- {\n\t\t\tif domain[i] == '.' {\n\t\t\t\treturn i\n\t\t\t}\n\t\t}\n\t\treturn -1\n\t}\n\n\tmatches := [][]uint32{}\n\tidx := len(domain)\n\tfor {\n\t\tif idx == -1 || current.sub == nil {\n\t\t\tbreak\n\t\t}\n\n\t\tnidx := nextPart(idx)\n\t\tpart := domain[nidx+1 : idx]\n\t\tnext := current.sub[part]\n\t\tif next == nil {\n\t\t\tbreak\n\t\t}\n\t\tcurrent = next\n\t\tidx = nidx\n\t\tif len(current.values) > 0 {\n\t\t\tmatches = append(matches, current.values)\n\t\t}\n\t}\n\tswitch len(matches) {\n\tcase 0:\n\t\treturn nil\n\tcase 1:\n\t\treturn matches[0]\n\tdefault:\n\t\tresult := []uint32{}\n\t\tfor idx := range matches {\n\t\t\t// Insert reversely, the subdomain that matches further ranks higher\n\t\t\tresult = append(result, matches[len(matches)-1-idx]...)\n\t\t}\n\t\treturn result\n\t}\n}\n"
  },
  {
    "path": "common/strmatcher/domain_matcher_test.go",
    "content": "package strmatcher_test\n\nimport (\n\t\"reflect\"\n\t\"testing\"\n\n\t. \"v2ray.com/core/common/strmatcher\"\n)\n\nfunc TestDomainMatcherGroup(t *testing.T) {\n\tg := new(DomainMatcherGroup)\n\tg.Add(\"v2ray.com\", 1)\n\tg.Add(\"google.com\", 2)\n\tg.Add(\"x.a.com\", 3)\n\tg.Add(\"a.b.com\", 4)\n\tg.Add(\"c.a.b.com\", 5)\n\tg.Add(\"x.y.com\", 4)\n\tg.Add(\"x.y.com\", 6)\n\n\ttestCases := []struct {\n\t\tDomain string\n\t\tResult []uint32\n\t}{\n\t\t{\n\t\t\tDomain: \"x.v2ray.com\",\n\t\t\tResult: []uint32{1},\n\t\t},\n\t\t{\n\t\t\tDomain: \"y.com\",\n\t\t\tResult: nil,\n\t\t},\n\t\t{\n\t\t\tDomain: \"a.b.com\",\n\t\t\tResult: []uint32{4},\n\t\t},\n\t\t{ // Matches [c.a.b.com, a.b.com]\n\t\t\tDomain: \"c.a.b.com\",\n\t\t\tResult: []uint32{5, 4},\n\t\t},\n\t\t{\n\t\t\tDomain: \"c.a..b.com\",\n\t\t\tResult: nil,\n\t\t},\n\t\t{\n\t\t\tDomain: \".com\",\n\t\t\tResult: nil,\n\t\t},\n\t\t{\n\t\t\tDomain: \"com\",\n\t\t\tResult: nil,\n\t\t},\n\t\t{\n\t\t\tDomain: \"\",\n\t\t\tResult: nil,\n\t\t},\n\t\t{\n\t\t\tDomain: \"x.y.com\",\n\t\t\tResult: []uint32{4, 6},\n\t\t},\n\t}\n\n\tfor _, testCase := range testCases {\n\t\tr := g.Match(testCase.Domain)\n\t\tif !reflect.DeepEqual(r, testCase.Result) {\n\t\t\tt.Error(\"Failed to match domain: \", testCase.Domain, \", expect \", testCase.Result, \", but got \", r)\n\t\t}\n\t}\n}\n\nfunc TestEmptyDomainMatcherGroup(t *testing.T) {\n\tg := new(DomainMatcherGroup)\n\tr := g.Match(\"v2ray.com\")\n\tif len(r) != 0 {\n\t\tt.Error(\"Expect [], but \", r)\n\t}\n}\n"
  },
  {
    "path": "common/strmatcher/full_matcher.go",
    "content": "package strmatcher\n\ntype FullMatcherGroup struct {\n\tmatchers map[string][]uint32\n}\n\nfunc (g *FullMatcherGroup) Add(domain string, value uint32) {\n\tif g.matchers == nil {\n\t\tg.matchers = make(map[string][]uint32)\n\t}\n\n\tg.matchers[domain] = append(g.matchers[domain], value)\n}\n\nfunc (g *FullMatcherGroup) addMatcher(m fullMatcher, value uint32) {\n\tg.Add(string(m), value)\n}\n\nfunc (g *FullMatcherGroup) Match(str string) []uint32 {\n\tif g.matchers == nil {\n\t\treturn nil\n\t}\n\n\treturn g.matchers[str]\n}\n"
  },
  {
    "path": "common/strmatcher/full_matcher_test.go",
    "content": "package strmatcher_test\n\nimport (\n\t\"reflect\"\n\t\"testing\"\n\n\t. \"v2ray.com/core/common/strmatcher\"\n)\n\nfunc TestFullMatcherGroup(t *testing.T) {\n\tg := new(FullMatcherGroup)\n\tg.Add(\"v2ray.com\", 1)\n\tg.Add(\"google.com\", 2)\n\tg.Add(\"x.a.com\", 3)\n\tg.Add(\"x.y.com\", 4)\n\tg.Add(\"x.y.com\", 6)\n\n\ttestCases := []struct {\n\t\tDomain string\n\t\tResult []uint32\n\t}{\n\t\t{\n\t\t\tDomain: \"v2ray.com\",\n\t\t\tResult: []uint32{1},\n\t\t},\n\t\t{\n\t\t\tDomain: \"y.com\",\n\t\t\tResult: nil,\n\t\t},\n\t\t{\n\t\t\tDomain: \"x.y.com\",\n\t\t\tResult: []uint32{4, 6},\n\t\t},\n\t}\n\n\tfor _, testCase := range testCases {\n\t\tr := g.Match(testCase.Domain)\n\t\tif !reflect.DeepEqual(r, testCase.Result) {\n\t\t\tt.Error(\"Failed to match domain: \", testCase.Domain, \", expect \", testCase.Result, \", but got \", r)\n\t\t}\n\t}\n}\n\nfunc TestEmptyFullMatcherGroup(t *testing.T) {\n\tg := new(FullMatcherGroup)\n\tr := g.Match(\"v2ray.com\")\n\tif len(r) != 0 {\n\t\tt.Error(\"Expect [], but \", r)\n\t}\n}\n"
  },
  {
    "path": "common/strmatcher/matchers.go",
    "content": "package strmatcher\n\nimport (\n\t\"regexp\"\n\t\"strings\"\n)\n\ntype fullMatcher string\n\nfunc (m fullMatcher) Match(s string) bool {\n\treturn string(m) == s\n}\n\nfunc (m fullMatcher) String() string {\n\treturn \"full:\" + string(m)\n}\n\ntype substrMatcher string\n\nfunc (m substrMatcher) Match(s string) bool {\n\treturn strings.Contains(s, string(m))\n}\n\nfunc (m substrMatcher) String() string {\n\treturn \"keyword:\" + string(m)\n}\n\ntype domainMatcher string\n\nfunc (m domainMatcher) Match(s string) bool {\n\tpattern := string(m)\n\tif !strings.HasSuffix(s, pattern) {\n\t\treturn false\n\t}\n\treturn len(s) == len(pattern) || s[len(s)-len(pattern)-1] == '.'\n}\n\nfunc (m domainMatcher) String() string {\n\treturn \"domain:\" + string(m)\n}\n\ntype regexMatcher struct {\n\tpattern *regexp.Regexp\n}\n\nfunc (m *regexMatcher) Match(s string) bool {\n\treturn m.pattern.MatchString(s)\n}\n\nfunc (m *regexMatcher) String() string {\n\treturn \"regexp:\" + m.pattern.String()\n}\n"
  },
  {
    "path": "common/strmatcher/matchers_test.go",
    "content": "package strmatcher_test\n\nimport (\n\t\"testing\"\n\n\t\"v2ray.com/core/common\"\n\t. \"v2ray.com/core/common/strmatcher\"\n)\n\nfunc TestMatcher(t *testing.T) {\n\tcases := []struct {\n\t\tpattern string\n\t\tmType   Type\n\t\tinput   string\n\t\toutput  bool\n\t}{\n\t\t{\n\t\t\tpattern: \"v2ray.com\",\n\t\t\tmType:   Domain,\n\t\t\tinput:   \"www.v2ray.com\",\n\t\t\toutput:  true,\n\t\t},\n\t\t{\n\t\t\tpattern: \"v2ray.com\",\n\t\t\tmType:   Domain,\n\t\t\tinput:   \"v2ray.com\",\n\t\t\toutput:  true,\n\t\t},\n\t\t{\n\t\t\tpattern: \"v2ray.com\",\n\t\t\tmType:   Domain,\n\t\t\tinput:   \"www.v3ray.com\",\n\t\t\toutput:  false,\n\t\t},\n\t\t{\n\t\t\tpattern: \"v2ray.com\",\n\t\t\tmType:   Domain,\n\t\t\tinput:   \"2ray.com\",\n\t\t\toutput:  false,\n\t\t},\n\t\t{\n\t\t\tpattern: \"v2ray.com\",\n\t\t\tmType:   Domain,\n\t\t\tinput:   \"xv2ray.com\",\n\t\t\toutput:  false,\n\t\t},\n\t\t{\n\t\t\tpattern: \"v2ray.com\",\n\t\t\tmType:   Full,\n\t\t\tinput:   \"v2ray.com\",\n\t\t\toutput:  true,\n\t\t},\n\t\t{\n\t\t\tpattern: \"v2ray.com\",\n\t\t\tmType:   Full,\n\t\t\tinput:   \"xv2ray.com\",\n\t\t\toutput:  false,\n\t\t},\n\t\t{\n\t\t\tpattern: \"v2ray.com\",\n\t\t\tmType:   Regex,\n\t\t\tinput:   \"v2rayxcom\",\n\t\t\toutput:  true,\n\t\t},\n\t}\n\tfor _, test := range cases {\n\t\tmatcher, err := test.mType.New(test.pattern)\n\t\tcommon.Must(err)\n\t\tif m := matcher.Match(test.input); m != test.output {\n\t\t\tt.Error(\"unexpected output: \", m, \" for test case \", test)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "common/strmatcher/strmatcher.go",
    "content": "package strmatcher\n\nimport (\n\t\"regexp\"\n)\n\n// Matcher is the interface to determine a string matches a pattern.\ntype Matcher interface {\n\t// Match returns true if the given string matches a predefined pattern.\n\tMatch(string) bool\n\tString() string\n}\n\n// Type is the type of the matcher.\ntype Type byte\n\nconst (\n\t// Full is the type of matcher that the input string must exactly equal to the pattern.\n\tFull Type = iota\n\t// Substr is the type of matcher that the input string must contain the pattern as a sub-string.\n\tSubstr\n\t// Domain is the type of matcher that the input string must be a sub-domain or itself of the pattern.\n\tDomain\n\t// Regex is the type of matcher that the input string must matches the regular-expression pattern.\n\tRegex\n)\n\n// New creates a new Matcher based on the given pattern.\nfunc (t Type) New(pattern string) (Matcher, error) {\n\tswitch t {\n\tcase Full:\n\t\treturn fullMatcher(pattern), nil\n\tcase Substr:\n\t\treturn substrMatcher(pattern), nil\n\tcase Domain:\n\t\treturn domainMatcher(pattern), nil\n\tcase Regex:\n\t\tr, err := regexp.Compile(pattern)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn &regexMatcher{\n\t\t\tpattern: r,\n\t\t}, nil\n\tdefault:\n\t\tpanic(\"Unknown type\")\n\t}\n}\n\n// IndexMatcher is the interface for matching with a group of matchers.\ntype IndexMatcher interface {\n\t// Match returns the index of a matcher that matches the input. It returns empty array if no such matcher exists.\n\tMatch(input string) []uint32\n}\n\ntype matcherEntry struct {\n\tm  Matcher\n\tid uint32\n}\n\n// MatcherGroup is an implementation of IndexMatcher.\n// Empty initialization works.\ntype MatcherGroup struct {\n\tcount         uint32\n\tfullMatcher   FullMatcherGroup\n\tdomainMatcher DomainMatcherGroup\n\totherMatchers []matcherEntry\n}\n\n// Add adds a new Matcher into the MatcherGroup, and returns its index. The index will never be 0.\nfunc (g *MatcherGroup) Add(m Matcher) uint32 {\n\tg.count++\n\tc := g.count\n\n\tswitch tm := m.(type) {\n\tcase fullMatcher:\n\t\tg.fullMatcher.addMatcher(tm, c)\n\tcase domainMatcher:\n\t\tg.domainMatcher.addMatcher(tm, c)\n\tdefault:\n\t\tg.otherMatchers = append(g.otherMatchers, matcherEntry{\n\t\t\tm:  m,\n\t\t\tid: c,\n\t\t})\n\t}\n\n\treturn c\n}\n\n// Match implements IndexMatcher.Match.\nfunc (g *MatcherGroup) Match(pattern string) []uint32 {\n\tresult := []uint32{}\n\tresult = append(result, g.fullMatcher.Match(pattern)...)\n\tresult = append(result, g.domainMatcher.Match(pattern)...)\n\tfor _, e := range g.otherMatchers {\n\t\tif e.m.Match(pattern) {\n\t\t\tresult = append(result, e.id)\n\t\t}\n\t}\n\treturn result\n}\n\n// Size returns the number of matchers in the MatcherGroup.\nfunc (g *MatcherGroup) Size() uint32 {\n\treturn g.count\n}\n"
  },
  {
    "path": "common/strmatcher/strmatcher_test.go",
    "content": "package strmatcher_test\n\nimport (\n\t\"reflect\"\n\t\"testing\"\n\n\t\"v2ray.com/core/common\"\n\t. \"v2ray.com/core/common/strmatcher\"\n)\n\n// See https://github.com/v2fly/v2ray-core/issues/92#issuecomment-673238489\nfunc TestMatcherGroup(t *testing.T) {\n\trules := []struct {\n\t\tType   Type\n\t\tDomain string\n\t}{\n\t\t{\n\t\t\tType:   Regex,\n\t\t\tDomain: \"apis\\\\.us$\",\n\t\t},\n\t\t{\n\t\t\tType:   Substr,\n\t\t\tDomain: \"apis\",\n\t\t},\n\t\t{\n\t\t\tType:   Domain,\n\t\t\tDomain: \"googleapis.com\",\n\t\t},\n\t\t{\n\t\t\tType:   Domain,\n\t\t\tDomain: \"com\",\n\t\t},\n\t\t{\n\t\t\tType:   Full,\n\t\t\tDomain: \"www.baidu.com\",\n\t\t},\n\t\t{\n\t\t\tType:   Substr,\n\t\t\tDomain: \"apis\",\n\t\t},\n\t\t{\n\t\t\tType:   Domain,\n\t\t\tDomain: \"googleapis.com\",\n\t\t},\n\t\t{\n\t\t\tType:   Full,\n\t\t\tDomain: \"fonts.googleapis.com\",\n\t\t},\n\t\t{\n\t\t\tType:   Full,\n\t\t\tDomain: \"www.baidu.com\",\n\t\t},\n\t\t{\n\t\t\tType:   Domain,\n\t\t\tDomain: \"example.com\",\n\t\t},\n\t}\n\tcases := []struct {\n\t\tInput  string\n\t\tOutput []uint32\n\t}{\n\t\t{\n\t\t\tInput:  \"www.baidu.com\",\n\t\t\tOutput: []uint32{5, 9, 4},\n\t\t},\n\t\t{\n\t\t\tInput:  \"fonts.googleapis.com\",\n\t\t\tOutput: []uint32{8, 3, 7, 4, 2, 6},\n\t\t},\n\t\t{\n\t\t\tInput:  \"example.googleapis.com\",\n\t\t\tOutput: []uint32{3, 7, 4, 2, 6},\n\t\t},\n\t\t{\n\t\t\tInput:  \"testapis.us\",\n\t\t\tOutput: []uint32{1, 2, 6},\n\t\t},\n\t\t{\n\t\t\tInput:  \"example.com\",\n\t\t\tOutput: []uint32{10, 4},\n\t\t},\n\t}\n\tmatcherGroup := &MatcherGroup{}\n\tfor _, rule := range rules {\n\t\tmatcher, err := rule.Type.New(rule.Domain)\n\t\tcommon.Must(err)\n\t\tmatcherGroup.Add(matcher)\n\t}\n\tfor _, test := range cases {\n\t\tif m := matcherGroup.Match(test.Input); !reflect.DeepEqual(m, test.Output) {\n\t\t\tt.Error(\"unexpected output: \", m, \" for test case \", test)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "common/task/common.go",
    "content": "package task\n\nimport \"v2ray.com/core/common\"\n\n// Close returns a func() that closes v.\nfunc Close(v interface{}) func() error {\n\treturn func() error {\n\t\treturn common.Close(v)\n\t}\n}\n"
  },
  {
    "path": "common/task/periodic.go",
    "content": "package task\n\nimport (\n\t\"sync\"\n\t\"time\"\n)\n\n// Periodic is a task that runs periodically.\ntype Periodic struct {\n\t// Interval of the task being run\n\tInterval time.Duration\n\t// Execute is the task function\n\tExecute func() error\n\n\taccess  sync.Mutex\n\ttimer   *time.Timer\n\trunning bool\n}\n\nfunc (t *Periodic) hasClosed() bool {\n\tt.access.Lock()\n\tdefer t.access.Unlock()\n\n\treturn !t.running\n}\n\nfunc (t *Periodic) checkedExecute() error {\n\tif t.hasClosed() {\n\t\treturn nil\n\t}\n\n\tif err := t.Execute(); err != nil {\n\t\tt.access.Lock()\n\t\tt.running = false\n\t\tt.access.Unlock()\n\t\treturn err\n\t}\n\n\tt.access.Lock()\n\tdefer t.access.Unlock()\n\n\tif !t.running {\n\t\treturn nil\n\t}\n\n\tt.timer = time.AfterFunc(t.Interval, func() {\n\t\tt.checkedExecute() // nolint: errcheck\n\t})\n\n\treturn nil\n}\n\n// Start implements common.Runnable.\nfunc (t *Periodic) Start() error {\n\tt.access.Lock()\n\tif t.running {\n\t\tt.access.Unlock()\n\t\treturn nil\n\t}\n\tt.running = true\n\tt.access.Unlock()\n\n\tif err := t.checkedExecute(); err != nil {\n\t\tt.access.Lock()\n\t\tt.running = false\n\t\tt.access.Unlock()\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// Close implements common.Closable.\nfunc (t *Periodic) Close() error {\n\tt.access.Lock()\n\tdefer t.access.Unlock()\n\n\tt.running = false\n\tif t.timer != nil {\n\t\tt.timer.Stop()\n\t\tt.timer = nil\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "common/task/periodic_test.go",
    "content": "package task_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"v2ray.com/core/common\"\n\t. \"v2ray.com/core/common/task\"\n)\n\nfunc TestPeriodicTaskStop(t *testing.T) {\n\tvalue := 0\n\ttask := &Periodic{\n\t\tInterval: time.Second * 2,\n\t\tExecute: func() error {\n\t\t\tvalue++\n\t\t\treturn nil\n\t\t},\n\t}\n\tcommon.Must(task.Start())\n\ttime.Sleep(time.Second * 5)\n\tcommon.Must(task.Close())\n\tif value != 3 {\n\t\tt.Fatal(\"expected 3, but got \", value)\n\t}\n\ttime.Sleep(time.Second * 4)\n\tif value != 3 {\n\t\tt.Fatal(\"expected 3, but got \", value)\n\t}\n\tcommon.Must(task.Start())\n\ttime.Sleep(time.Second * 3)\n\tif value != 5 {\n\t\tt.Fatal(\"Expected 5, but \", value)\n\t}\n\tcommon.Must(task.Close())\n}\n"
  },
  {
    "path": "common/task/task.go",
    "content": "package task\n\nimport (\n\t\"context\"\n\n\t\"v2ray.com/core/common/signal/semaphore\"\n)\n\n// OnSuccess executes g() after f() returns nil.\nfunc OnSuccess(f func() error, g func() error) func() error {\n\treturn func() error {\n\t\tif err := f(); err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn g()\n\t}\n}\n\n// Run executes a list of tasks in parallel, returns the first error encountered or nil if all tasks pass.\nfunc Run(ctx context.Context, tasks ...func() error) error {\n\tn := len(tasks)\n\ts := semaphore.New(n)\n\tdone := make(chan error, 1)\n\n\tfor _, task := range tasks {\n\t\t<-s.Wait()\n\t\tgo func(f func() error) {\n\t\t\terr := f()\n\t\t\tif err == nil {\n\t\t\t\ts.Signal()\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tselect {\n\t\t\tcase done <- err:\n\t\t\tdefault:\n\t\t\t}\n\t\t}(task)\n\t}\n\n\tfor i := 0; i < n; i++ {\n\t\tselect {\n\t\tcase err := <-done:\n\t\t\treturn err\n\t\tcase <-ctx.Done():\n\t\t\treturn ctx.Err()\n\t\tcase <-s.Wait():\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "common/task/task_test.go",
    "content": "package task_test\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\n\t\"v2ray.com/core/common\"\n\t. \"v2ray.com/core/common/task\"\n)\n\nfunc TestExecuteParallel(t *testing.T) {\n\terr := Run(context.Background(),\n\t\tfunc() error {\n\t\t\ttime.Sleep(time.Millisecond * 200)\n\t\t\treturn errors.New(\"test\")\n\t\t}, func() error {\n\t\t\ttime.Sleep(time.Millisecond * 500)\n\t\t\treturn errors.New(\"test2\")\n\t\t})\n\n\tif r := cmp.Diff(err.Error(), \"test\"); r != \"\" {\n\t\tt.Error(r)\n\t}\n}\n\nfunc TestExecuteParallelContextCancel(t *testing.T) {\n\tctx, cancel := context.WithCancel(context.Background())\n\terr := Run(ctx, func() error {\n\t\ttime.Sleep(time.Millisecond * 2000)\n\t\treturn errors.New(\"test\")\n\t}, func() error {\n\t\ttime.Sleep(time.Millisecond * 5000)\n\t\treturn errors.New(\"test2\")\n\t}, func() error {\n\t\tcancel()\n\t\treturn nil\n\t})\n\n\terrStr := err.Error()\n\tif !strings.Contains(errStr, \"canceled\") {\n\t\tt.Error(\"expected error string to contain 'canceled', but actually not: \", errStr)\n\t}\n}\n\nfunc BenchmarkExecuteOne(b *testing.B) {\n\tnoop := func() error {\n\t\treturn nil\n\t}\n\tfor i := 0; i < b.N; i++ {\n\t\tcommon.Must(Run(context.Background(), noop))\n\t}\n}\n\nfunc BenchmarkExecuteTwo(b *testing.B) {\n\tnoop := func() error {\n\t\treturn nil\n\t}\n\tfor i := 0; i < b.N; i++ {\n\t\tcommon.Must(Run(context.Background(), noop, noop))\n\t}\n}\n"
  },
  {
    "path": "common/type.go",
    "content": "package common\n\nimport (\n\t\"context\"\n\t\"reflect\"\n)\n\n// ConfigCreator is a function to create an object by a config.\ntype ConfigCreator func(ctx context.Context, config interface{}) (interface{}, error)\n\nvar (\n\ttypeCreatorRegistry = make(map[reflect.Type]ConfigCreator)\n)\n\n// RegisterConfig registers a global config creator. The config can be nil but must have a type.\nfunc RegisterConfig(config interface{}, configCreator ConfigCreator) error {\n\tconfigType := reflect.TypeOf(config)\n\tif _, found := typeCreatorRegistry[configType]; found {\n\t\treturn newError(configType.Name() + \" is already registered\").AtError()\n\t}\n\ttypeCreatorRegistry[configType] = configCreator\n\treturn nil\n}\n\n// CreateObject creates an object by its config. The config type must be registered through RegisterConfig().\nfunc CreateObject(ctx context.Context, config interface{}) (interface{}, error) {\n\tconfigType := reflect.TypeOf(config)\n\tcreator, found := typeCreatorRegistry[configType]\n\tif !found {\n\t\treturn nil, newError(configType.String() + \" is not registered\").AtError()\n\t}\n\treturn creator(ctx, config)\n}\n"
  },
  {
    "path": "common/type_test.go",
    "content": "package common_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t. \"v2ray.com/core/common\"\n)\n\ntype TConfig struct {\n\tvalue int\n}\n\ntype YConfig struct {\n\tvalue string\n}\n\nfunc TestObjectCreation(t *testing.T) {\n\tvar f = func(ctx context.Context, t interface{}) (interface{}, error) {\n\t\treturn func() int {\n\t\t\treturn t.(*TConfig).value\n\t\t}, nil\n\t}\n\n\tMust(RegisterConfig((*TConfig)(nil), f))\n\terr := RegisterConfig((*TConfig)(nil), f)\n\tif err == nil {\n\t\tt.Error(\"expect non-nil error, but got nil\")\n\t}\n\n\tg, err := CreateObject(context.Background(), &TConfig{value: 2})\n\tMust(err)\n\tif v := g.(func() int)(); v != 2 {\n\t\tt.Error(\"expect return value 2, but got \", v)\n\t}\n\n\t_, err = CreateObject(context.Background(), &YConfig{value: \"T\"})\n\tif err == nil {\n\t\tt.Error(\"expect non-nil error, but got nil\")\n\t}\n}\n"
  },
  {
    "path": "common/uuid/uuid.go",
    "content": "package uuid // import \"v2ray.com/core/common/uuid\"\n\nimport (\n\t\"bytes\"\n\t\"crypto/rand\"\n\t\"encoding/hex\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/errors\"\n)\n\nvar (\n\tbyteGroups = []int{8, 4, 4, 4, 12}\n)\n\ntype UUID [16]byte\n\n// String returns the string representation of this UUID.\nfunc (u *UUID) String() string {\n\tbytes := u.Bytes()\n\tresult := hex.EncodeToString(bytes[0 : byteGroups[0]/2])\n\tstart := byteGroups[0] / 2\n\tfor i := 1; i < len(byteGroups); i++ {\n\t\tnBytes := byteGroups[i] / 2\n\t\tresult += \"-\"\n\t\tresult += hex.EncodeToString(bytes[start : start+nBytes])\n\t\tstart += nBytes\n\t}\n\treturn result\n}\n\n// Bytes returns the bytes representation of this UUID.\nfunc (u *UUID) Bytes() []byte {\n\treturn u[:]\n}\n\n// Equals returns true if this UUID equals another UUID by value.\nfunc (u *UUID) Equals(another *UUID) bool {\n\tif u == nil && another == nil {\n\t\treturn true\n\t}\n\tif u == nil || another == nil {\n\t\treturn false\n\t}\n\treturn bytes.Equal(u.Bytes(), another.Bytes())\n}\n\n// New creates a UUID with random value.\nfunc New() UUID {\n\tvar uuid UUID\n\tcommon.Must2(rand.Read(uuid.Bytes()))\n\treturn uuid\n}\n\n// ParseBytes converts a UUID in byte form to object.\nfunc ParseBytes(b []byte) (UUID, error) {\n\tvar uuid UUID\n\tif len(b) != 16 {\n\t\treturn uuid, errors.New(\"invalid UUID: \", b)\n\t}\n\tcopy(uuid[:], b)\n\treturn uuid, nil\n}\n\n// ParseString converts a UUID in string form to object.\nfunc ParseString(str string) (UUID, error) {\n\tvar uuid UUID\n\n\ttext := []byte(str)\n\tif len(text) < 32 {\n\t\treturn uuid, errors.New(\"invalid UUID: \", str)\n\t}\n\n\tb := uuid.Bytes()\n\n\tfor _, byteGroup := range byteGroups {\n\t\tif text[0] == '-' {\n\t\t\ttext = text[1:]\n\t\t}\n\n\t\tif _, err := hex.Decode(b[:byteGroup/2], text[:byteGroup]); err != nil {\n\t\t\treturn uuid, err\n\t\t}\n\n\t\ttext = text[byteGroup:]\n\t\tb = b[byteGroup/2:]\n\t}\n\n\treturn uuid, nil\n}\n"
  },
  {
    "path": "common/uuid/uuid_test.go",
    "content": "package uuid_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\n\t\"v2ray.com/core/common\"\n\t. \"v2ray.com/core/common/uuid\"\n)\n\nfunc TestParseBytes(t *testing.T) {\n\tstr := \"2418d087-648d-4990-86e8-19dca1d006d3\"\n\tbytes := []byte{0x24, 0x18, 0xd0, 0x87, 0x64, 0x8d, 0x49, 0x90, 0x86, 0xe8, 0x19, 0xdc, 0xa1, 0xd0, 0x06, 0xd3}\n\n\tuuid, err := ParseBytes(bytes)\n\tcommon.Must(err)\n\tif diff := cmp.Diff(uuid.String(), str); diff != \"\" {\n\t\tt.Error(diff)\n\t}\n\n\t_, err = ParseBytes([]byte{1, 3, 2, 4})\n\tif err == nil {\n\t\tt.Fatal(\"Expect error but nil\")\n\t}\n}\n\nfunc TestParseString(t *testing.T) {\n\tstr := \"2418d087-648d-4990-86e8-19dca1d006d3\"\n\texpectedBytes := []byte{0x24, 0x18, 0xd0, 0x87, 0x64, 0x8d, 0x49, 0x90, 0x86, 0xe8, 0x19, 0xdc, 0xa1, 0xd0, 0x06, 0xd3}\n\n\tuuid, err := ParseString(str)\n\tcommon.Must(err)\n\tif r := cmp.Diff(expectedBytes, uuid.Bytes()); r != \"\" {\n\t\tt.Fatal(r)\n\t}\n\n\t_, err = ParseString(\"2418d087\")\n\tif err == nil {\n\t\tt.Fatal(\"Expect error but nil\")\n\t}\n\n\t_, err = ParseString(\"2418d087-648k-4990-86e8-19dca1d006d3\")\n\tif err == nil {\n\t\tt.Fatal(\"Expect error but nil\")\n\t}\n}\n\nfunc TestNewUUID(t *testing.T) {\n\tuuid := New()\n\tuuid2, err := ParseString(uuid.String())\n\n\tcommon.Must(err)\n\tif uuid.String() != uuid2.String() {\n\t\tt.Error(\"uuid string: \", uuid.String(), \" != \", uuid2.String())\n\t}\n\tif r := cmp.Diff(uuid.Bytes(), uuid2.Bytes()); r != \"\" {\n\t\tt.Error(r)\n\t}\n}\n\nfunc TestRandom(t *testing.T) {\n\tuuid := New()\n\tuuid2 := New()\n\n\tif uuid.String() == uuid2.String() {\n\t\tt.Error(\"duplicated uuid\")\n\t}\n}\n\nfunc TestEquals(t *testing.T) {\n\tvar uuid *UUID\n\tvar uuid2 *UUID\n\tif !uuid.Equals(uuid2) {\n\t\tt.Error(\"empty uuid should equal\")\n\t}\n\n\tuuid3 := New()\n\tif uuid.Equals(&uuid3) {\n\t\tt.Error(\"nil uuid equals non-nil uuid\")\n\t}\n}\n"
  },
  {
    "path": "config.go",
    "content": "// +build !confonly\n\npackage core\n\nimport (\n\t\"io\"\n\t\"strings\"\n\n\t\"github.com/golang/protobuf/proto\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/cmdarg\"\n\t\"v2ray.com/core/main/confloader\"\n)\n\n// ConfigFormat is a configurable format of V2Ray config file.\ntype ConfigFormat struct {\n\tName      string\n\tExtension []string\n\tLoader    ConfigLoader\n}\n\n// ConfigLoader is a utility to load V2Ray config from external source.\ntype ConfigLoader func(input interface{}) (*Config, error)\n\nvar (\n\tconfigLoaderByName = make(map[string]*ConfigFormat)\n\tconfigLoaderByExt  = make(map[string]*ConfigFormat)\n)\n\n// RegisterConfigLoader add a new ConfigLoader.\nfunc RegisterConfigLoader(format *ConfigFormat) error {\n\tname := strings.ToLower(format.Name)\n\tif _, found := configLoaderByName[name]; found {\n\t\treturn newError(format.Name, \" already registered.\")\n\t}\n\tconfigLoaderByName[name] = format\n\n\tfor _, ext := range format.Extension {\n\t\tlext := strings.ToLower(ext)\n\t\tif f, found := configLoaderByExt[lext]; found {\n\t\t\treturn newError(ext, \" already registered to \", f.Name)\n\t\t}\n\t\tconfigLoaderByExt[lext] = format\n\t}\n\n\treturn nil\n}\n\nfunc getExtension(filename string) string {\n\tidx := strings.LastIndexByte(filename, '.')\n\tif idx == -1 {\n\t\treturn \"\"\n\t}\n\treturn filename[idx+1:]\n}\n\n// LoadConfig loads config with given format from given source.\n// input accepts 2 different types:\n// * []string slice of multiple filename/url(s) to open to read\n// * io.Reader that reads a config content (the original way)\nfunc LoadConfig(formatName string, filename string, input interface{}) (*Config, error) {\n\text := getExtension(filename)\n\tif len(ext) > 0 {\n\t\tif f, found := configLoaderByExt[ext]; found {\n\t\t\treturn f.Loader(input)\n\t\t}\n\t}\n\n\tif f, found := configLoaderByName[formatName]; found {\n\t\treturn f.Loader(input)\n\t}\n\n\treturn nil, newError(\"Unable to load config in \", formatName).AtWarning()\n}\n\nfunc loadProtobufConfig(data []byte) (*Config, error) {\n\tconfig := new(Config)\n\tif err := proto.Unmarshal(data, config); err != nil {\n\t\treturn nil, err\n\t}\n\treturn config, nil\n}\n\nfunc init() {\n\tcommon.Must(RegisterConfigLoader(&ConfigFormat{\n\t\tName:      \"Protobuf\",\n\t\tExtension: []string{\"pb\"},\n\t\tLoader: func(input interface{}) (*Config, error) {\n\t\t\tswitch v := input.(type) {\n\t\t\tcase cmdarg.Arg:\n\t\t\t\tr, err := confloader.LoadConfig(v[0])\n\t\t\t\tcommon.Must(err)\n\t\t\t\tdata, err := buf.ReadAllToBytes(r)\n\t\t\t\tcommon.Must(err)\n\t\t\t\treturn loadProtobufConfig(data)\n\t\t\tcase io.Reader:\n\t\t\t\tdata, err := buf.ReadAllToBytes(v)\n\t\t\t\tcommon.Must(err)\n\t\t\t\treturn loadProtobufConfig(data)\n\t\t\tdefault:\n\t\t\t\treturn nil, newError(\"unknow type\")\n\t\t\t}\n\t\t},\n\t}))\n}\n"
  },
  {
    "path": "config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: config.proto\n\npackage core\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n\tserial \"v2ray.com/core/common/serial\"\n\ttransport \"v2ray.com/core/transport\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\n// Config is the master config of V2Ray. V2Ray takes this config as input and\n// functions accordingly.\ntype Config struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Inbound handler configurations. Must have at least one item.\n\tInbound []*InboundHandlerConfig `protobuf:\"bytes,1,rep,name=inbound,proto3\" json:\"inbound,omitempty\"`\n\t// Outbound handler configurations. Must have at least one item. The first\n\t// item is used as default for routing.\n\tOutbound []*OutboundHandlerConfig `protobuf:\"bytes,2,rep,name=outbound,proto3\" json:\"outbound,omitempty\"`\n\t// App is for configurations of all features in V2Ray. A feature must\n\t// implement the Feature interface, and its config type must be registered\n\t// through common.RegisterConfig.\n\tApp []*serial.TypedMessage `protobuf:\"bytes,4,rep,name=app,proto3\" json:\"app,omitempty\"`\n\t// Transport settings.\n\t// Deprecated. Each inbound and outbound should choose their own transport\n\t// config. Date to remove: 2020-01-13\n\t//\n\t// Deprecated: Do not use.\n\tTransport *transport.Config `protobuf:\"bytes,5,opt,name=transport,proto3\" json:\"transport,omitempty\"`\n\t// Configuration for extensions. The config may not work if corresponding\n\t// extension is not loaded into V2Ray. V2Ray will ignore such config during\n\t// initialization.\n\tExtension []*serial.TypedMessage `protobuf:\"bytes,6,rep,name=extension,proto3\" json:\"extension,omitempty\"`\n}\n\nfunc (x *Config) Reset() {\n\t*x = Config{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_config_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Config) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Config) ProtoMessage() {}\n\nfunc (x *Config) ProtoReflect() protoreflect.Message {\n\tmi := &file_config_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Config.ProtoReflect.Descriptor instead.\nfunc (*Config) Descriptor() ([]byte, []int) {\n\treturn file_config_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *Config) GetInbound() []*InboundHandlerConfig {\n\tif x != nil {\n\t\treturn x.Inbound\n\t}\n\treturn nil\n}\n\nfunc (x *Config) GetOutbound() []*OutboundHandlerConfig {\n\tif x != nil {\n\t\treturn x.Outbound\n\t}\n\treturn nil\n}\n\nfunc (x *Config) GetApp() []*serial.TypedMessage {\n\tif x != nil {\n\t\treturn x.App\n\t}\n\treturn nil\n}\n\n// Deprecated: Do not use.\nfunc (x *Config) GetTransport() *transport.Config {\n\tif x != nil {\n\t\treturn x.Transport\n\t}\n\treturn nil\n}\n\nfunc (x *Config) GetExtension() []*serial.TypedMessage {\n\tif x != nil {\n\t\treturn x.Extension\n\t}\n\treturn nil\n}\n\n// InboundHandlerConfig is the configuration for inbound handler.\ntype InboundHandlerConfig struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Tag of the inbound handler. The tag must be unique among all inbound\n\t// handlers\n\tTag string `protobuf:\"bytes,1,opt,name=tag,proto3\" json:\"tag,omitempty\"`\n\t// Settings for how this inbound proxy is handled.\n\tReceiverSettings *serial.TypedMessage `protobuf:\"bytes,2,opt,name=receiver_settings,json=receiverSettings,proto3\" json:\"receiver_settings,omitempty\"`\n\t// Settings for inbound proxy. Must be one of the inbound proxies.\n\tProxySettings *serial.TypedMessage `protobuf:\"bytes,3,opt,name=proxy_settings,json=proxySettings,proto3\" json:\"proxy_settings,omitempty\"`\n}\n\nfunc (x *InboundHandlerConfig) Reset() {\n\t*x = InboundHandlerConfig{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_config_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *InboundHandlerConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*InboundHandlerConfig) ProtoMessage() {}\n\nfunc (x *InboundHandlerConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_config_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use InboundHandlerConfig.ProtoReflect.Descriptor instead.\nfunc (*InboundHandlerConfig) Descriptor() ([]byte, []int) {\n\treturn file_config_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *InboundHandlerConfig) GetTag() string {\n\tif x != nil {\n\t\treturn x.Tag\n\t}\n\treturn \"\"\n}\n\nfunc (x *InboundHandlerConfig) GetReceiverSettings() *serial.TypedMessage {\n\tif x != nil {\n\t\treturn x.ReceiverSettings\n\t}\n\treturn nil\n}\n\nfunc (x *InboundHandlerConfig) GetProxySettings() *serial.TypedMessage {\n\tif x != nil {\n\t\treturn x.ProxySettings\n\t}\n\treturn nil\n}\n\n// OutboundHandlerConfig is the configuration for outbound handler.\ntype OutboundHandlerConfig struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Tag of this outbound handler.\n\tTag string `protobuf:\"bytes,1,opt,name=tag,proto3\" json:\"tag,omitempty\"`\n\t// Settings for how to dial connection for this outbound handler.\n\tSenderSettings *serial.TypedMessage `protobuf:\"bytes,2,opt,name=sender_settings,json=senderSettings,proto3\" json:\"sender_settings,omitempty\"`\n\t// Settings for this outbound proxy. Must be one of the outbound proxies.\n\tProxySettings *serial.TypedMessage `protobuf:\"bytes,3,opt,name=proxy_settings,json=proxySettings,proto3\" json:\"proxy_settings,omitempty\"`\n\t// If not zero, this outbound will be expired in seconds. Not used for now.\n\tExpire int64 `protobuf:\"varint,4,opt,name=expire,proto3\" json:\"expire,omitempty\"`\n\t// Comment of this outbound handler. Not used for now.\n\tComment string `protobuf:\"bytes,5,opt,name=comment,proto3\" json:\"comment,omitempty\"`\n}\n\nfunc (x *OutboundHandlerConfig) Reset() {\n\t*x = OutboundHandlerConfig{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_config_proto_msgTypes[2]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *OutboundHandlerConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*OutboundHandlerConfig) ProtoMessage() {}\n\nfunc (x *OutboundHandlerConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_config_proto_msgTypes[2]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use OutboundHandlerConfig.ProtoReflect.Descriptor instead.\nfunc (*OutboundHandlerConfig) Descriptor() ([]byte, []int) {\n\treturn file_config_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *OutboundHandlerConfig) GetTag() string {\n\tif x != nil {\n\t\treturn x.Tag\n\t}\n\treturn \"\"\n}\n\nfunc (x *OutboundHandlerConfig) GetSenderSettings() *serial.TypedMessage {\n\tif x != nil {\n\t\treturn x.SenderSettings\n\t}\n\treturn nil\n}\n\nfunc (x *OutboundHandlerConfig) GetProxySettings() *serial.TypedMessage {\n\tif x != nil {\n\t\treturn x.ProxySettings\n\t}\n\treturn nil\n}\n\nfunc (x *OutboundHandlerConfig) GetExpire() int64 {\n\tif x != nil {\n\t\treturn x.Expire\n\t}\n\treturn 0\n}\n\nfunc (x *OutboundHandlerConfig) GetComment() string {\n\tif x != nil {\n\t\treturn x.Comment\n\t}\n\treturn \"\"\n}\n\nvar File_config_proto protoreflect.FileDescriptor\n\nvar file_config_proto_rawDesc = []byte{\n\t0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0a,\n\t0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d,\n\t0x6f, 0x6e, 0x2f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x64, 0x5f,\n\t0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x16, 0x74,\n\t0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e,\n\t0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc9, 0x02, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,\n\t0x12, 0x3a, 0x0a, 0x07, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28,\n\t0x0b, 0x32, 0x20, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x49,\n\t0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e,\n\t0x66, 0x69, 0x67, 0x52, 0x07, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x3d, 0x0a, 0x08,\n\t0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21,\n\t0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x4f, 0x75, 0x74, 0x62,\n\t0x6f, 0x75, 0x6e, 0x64, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69,\n\t0x67, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x38, 0x0a, 0x03, 0x61,\n\t0x70, 0x70, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,\n\t0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72,\n\t0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,\n\t0x52, 0x03, 0x61, 0x70, 0x70, 0x12, 0x3e, 0x0a, 0x09, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f,\n\t0x72, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,\n\t0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e,\n\t0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x02, 0x18, 0x01, 0x52, 0x09, 0x74, 0x72, 0x61, 0x6e,\n\t0x73, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x44, 0x0a, 0x09, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69,\n\t0x6f, 0x6e, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,\n\t0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72,\n\t0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,\n\t0x52, 0x09, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x4a, 0x04, 0x08, 0x03, 0x10,\n\t0x04, 0x22, 0xcc, 0x01, 0x0a, 0x14, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x48, 0x61, 0x6e,\n\t0x64, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61,\n\t0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x53, 0x0a, 0x11,\n\t0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67,\n\t0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,\n\t0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69,\n\t0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52,\n\t0x10, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67,\n\t0x73, 0x12, 0x4d, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69,\n\t0x6e, 0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x76, 0x32, 0x72, 0x61,\n\t0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65,\n\t0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,\n\t0x65, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,\n\t0x22, 0xfb, 0x01, 0x0a, 0x15, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x48, 0x61, 0x6e,\n\t0x64, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61,\n\t0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x4f, 0x0a, 0x0f,\n\t0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18,\n\t0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,\n\t0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c,\n\t0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0e, 0x73,\n\t0x65, 0x6e, 0x64, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x4d, 0x0a,\n\t0x0e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18,\n\t0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,\n\t0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c,\n\t0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0d, 0x70,\n\t0x72, 0x6f, 0x78, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x16, 0x0a, 0x06,\n\t0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x65, 0x78,\n\t0x70, 0x69, 0x72, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x18,\n\t0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x2f,\n\t0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,\n\t0x50, 0x01, 0x5a, 0x0e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f,\n\t0x72, 0x65, 0xaa, 0x02, 0x0a, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x62,\n\t0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_config_proto_rawDescOnce sync.Once\n\tfile_config_proto_rawDescData = file_config_proto_rawDesc\n)\n\nfunc file_config_proto_rawDescGZIP() []byte {\n\tfile_config_proto_rawDescOnce.Do(func() {\n\t\tfile_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_config_proto_rawDescData)\n\t})\n\treturn file_config_proto_rawDescData\n}\n\nvar file_config_proto_msgTypes = make([]protoimpl.MessageInfo, 3)\nvar file_config_proto_goTypes = []interface{}{\n\t(*Config)(nil),                // 0: v2ray.core.Config\n\t(*InboundHandlerConfig)(nil),  // 1: v2ray.core.InboundHandlerConfig\n\t(*OutboundHandlerConfig)(nil), // 2: v2ray.core.OutboundHandlerConfig\n\t(*serial.TypedMessage)(nil),   // 3: v2ray.core.common.serial.TypedMessage\n\t(*transport.Config)(nil),      // 4: v2ray.core.transport.Config\n}\nvar file_config_proto_depIdxs = []int32{\n\t1, // 0: v2ray.core.Config.inbound:type_name -> v2ray.core.InboundHandlerConfig\n\t2, // 1: v2ray.core.Config.outbound:type_name -> v2ray.core.OutboundHandlerConfig\n\t3, // 2: v2ray.core.Config.app:type_name -> v2ray.core.common.serial.TypedMessage\n\t4, // 3: v2ray.core.Config.transport:type_name -> v2ray.core.transport.Config\n\t3, // 4: v2ray.core.Config.extension:type_name -> v2ray.core.common.serial.TypedMessage\n\t3, // 5: v2ray.core.InboundHandlerConfig.receiver_settings:type_name -> v2ray.core.common.serial.TypedMessage\n\t3, // 6: v2ray.core.InboundHandlerConfig.proxy_settings:type_name -> v2ray.core.common.serial.TypedMessage\n\t3, // 7: v2ray.core.OutboundHandlerConfig.sender_settings:type_name -> v2ray.core.common.serial.TypedMessage\n\t3, // 8: v2ray.core.OutboundHandlerConfig.proxy_settings:type_name -> v2ray.core.common.serial.TypedMessage\n\t9, // [9:9] is the sub-list for method output_type\n\t9, // [9:9] is the sub-list for method input_type\n\t9, // [9:9] is the sub-list for extension type_name\n\t9, // [9:9] is the sub-list for extension extendee\n\t0, // [0:9] is the sub-list for field type_name\n}\n\nfunc init() { file_config_proto_init() }\nfunc file_config_proto_init() {\n\tif File_config_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Config); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*InboundHandlerConfig); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*OutboundHandlerConfig); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_config_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   3,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_config_proto_goTypes,\n\t\tDependencyIndexes: file_config_proto_depIdxs,\n\t\tMessageInfos:      file_config_proto_msgTypes,\n\t}.Build()\n\tFile_config_proto = out.File\n\tfile_config_proto_rawDesc = nil\n\tfile_config_proto_goTypes = nil\n\tfile_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "config.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core;\noption csharp_namespace = \"V2Ray.Core\";\noption go_package = \"v2ray.com/core\";\noption java_package = \"com.v2ray.core\";\noption java_multiple_files = true;\n\nimport \"common/serial/typed_message.proto\";\nimport \"transport/config.proto\";\n\n// Config is the master config of V2Ray. V2Ray takes this config as input and\n// functions accordingly.\nmessage Config {\n  // Inbound handler configurations. Must have at least one item.\n  repeated InboundHandlerConfig inbound = 1;\n\n  // Outbound handler configurations. Must have at least one item. The first\n  // item is used as default for routing.\n  repeated OutboundHandlerConfig outbound = 2;\n\n  reserved 3;\n\n  // App is for configurations of all features in V2Ray. A feature must\n  // implement the Feature interface, and its config type must be registered\n  // through common.RegisterConfig.\n  repeated v2ray.core.common.serial.TypedMessage app = 4;\n\n  // Transport settings.\n  // Deprecated. Each inbound and outbound should choose their own transport\n  // config. Date to remove: 2020-01-13\n  v2ray.core.transport.Config transport = 5 [deprecated = true];\n\n  // Configuration for extensions. The config may not work if corresponding\n  // extension is not loaded into V2Ray. V2Ray will ignore such config during\n  // initialization.\n  repeated v2ray.core.common.serial.TypedMessage extension = 6;\n}\n\n// InboundHandlerConfig is the configuration for inbound handler.\nmessage InboundHandlerConfig {\n  // Tag of the inbound handler. The tag must be unique among all inbound\n  // handlers\n  string tag = 1;\n  // Settings for how this inbound proxy is handled.\n  v2ray.core.common.serial.TypedMessage receiver_settings = 2;\n  // Settings for inbound proxy. Must be one of the inbound proxies.\n  v2ray.core.common.serial.TypedMessage proxy_settings = 3;\n}\n\n// OutboundHandlerConfig is the configuration for outbound handler.\nmessage OutboundHandlerConfig {\n  // Tag of this outbound handler.\n  string tag = 1;\n  // Settings for how to dial connection for this outbound handler.\n  v2ray.core.common.serial.TypedMessage sender_settings = 2;\n  // Settings for this outbound proxy. Must be one of the outbound proxies.\n  v2ray.core.common.serial.TypedMessage proxy_settings = 3;\n  // If not zero, this outbound will be expired in seconds. Not used for now.\n  int64 expire = 4;\n  // Comment of this outbound handler. Not used for now.\n  string comment = 5;\n}\n"
  },
  {
    "path": "context.go",
    "content": "// +build !confonly\n\npackage core\n\nimport (\n\t\"context\"\n)\n\n// V2rayKey is the key type of Instance in Context, exported for test.\ntype V2rayKey int\n\nconst v2rayKey V2rayKey = 1\n\n// FromContext returns an Instance from the given context, or nil if the context doesn't contain one.\nfunc FromContext(ctx context.Context) *Instance {\n\tif s, ok := ctx.Value(v2rayKey).(*Instance); ok {\n\t\treturn s\n\t}\n\treturn nil\n}\n\n// MustFromContext returns an Instance from the given context, or panics if not present.\nfunc MustFromContext(ctx context.Context) *Instance {\n\tv := FromContext(ctx)\n\tif v == nil {\n\t\tpanic(\"V is not in context.\")\n\t}\n\treturn v\n}\n"
  },
  {
    "path": "context_test.go",
    "content": "package core_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t. \"v2ray.com/core\"\n)\n\nfunc TestContextPanic(t *testing.T) {\n\tdefer func() {\n\t\tr := recover()\n\t\tif r == nil {\n\t\t\tt.Error(\"expect panic, but nil\")\n\t\t}\n\t}()\n\n\tMustFromContext(context.Background())\n}\n"
  },
  {
    "path": "core.go",
    "content": "// Package core provides an entry point to use V2Ray core functionalities.\n//\n// V2Ray makes it possible to accept incoming network connections with certain\n// protocol, process the data, and send them through another connection with\n// the same or a difference protocol on demand.\n//\n// It may be configured to work with multiple protocols at the same time, and\n// uses the internal router to tunnel through different inbound and outbound\n// connections.\npackage core\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n\nimport (\n\t\"runtime\"\n\n\t\"v2ray.com/core/common/serial\"\n)\n\nvar (\n\tversion  = \"4.31.0\"\n\tbuild    = \"Custom\"\n\tcodename = \"V2Fly, a community-driven edition of V2Ray.\"\n\tintro    = \"A unified platform for anti-censorship.\"\n)\n\n// Version returns V2Ray's version as a string, in the form of \"x.y.z\" where x, y and z are numbers.\n// \".z\" part may be omitted in regular releases.\nfunc Version() string {\n\treturn version\n}\n\n// VersionStatement returns a list of strings representing the full version info.\nfunc VersionStatement() []string {\n\treturn []string{\n\t\tserial.Concat(\"V2Ray \", Version(), \" (\", codename, \") \", build, \" (\", runtime.Version(), \" \", runtime.GOOS, \"/\", runtime.GOARCH, \")\"),\n\t\tintro,\n\t}\n}\n\n/*\n::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::c:::::::::::::::::::::::ccc:::cccc::::::c:::::cccc::::cc::::::::::::::::::::::::ccccccc::cccccccccc::cc:::;:::::::::::::::::::::::::::ccc:::cccc:ccc::::::c:::::::::::::::::::::::::::cccc:cccccccccccccccccccccc:;;::::::::::::::::::c::::ccc::::::ccc:::ccc::cccccc::::cc:cc:::ccccccccccccccccccccccccccccccccccccccc\n:::;::::::::::::::::::::::::::::::::::::::::::::::cc:::::::::::::::::::::::::::::::::::::ccc::cc:::::c:::::::::::ccc::ccc:::::ccc::::::cc:::::cccc:::::::::::::::::::::cccccccccccccccccccccccccc:::::::::::::::::::::::::cc::ccc::::::::::::::c::c::::::::::::c::::::::c::::::cccccccccccccccccccccccccc:;:::::::::::::::ccc::cccccccc::c:cccc::cc:::cccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\n:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::cc::::::::cc::::::::::::ccccc:::::ccccccccc::cccc::ccccccc:::c::::::::c:c:::::cccccccccccccccccccccccccc::::::::::::::::::::::::cc:::::ccc:::c::::::::::::::::c::::::::::::::::::::::ccccccccccccccccccccccccccc:::::::::::::::::::::cccccc:ccccc::ccccccccc:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\n::;;::::::::::::::::::::::::::::::::::::::::::::::::::::::::c:::::::::::::::::::::cc::::::::::::::::c:::cc::::c::::::::cccccc::::cccccccccc::ccccccc::c::::::::c::::::::ccccccccccccccccccccccccc:::::::::::::::::::::::::c::::cccc:::cc:::cc:::::::::::::::::::::::::::c::::::ccccccccccccccccccccccccccc::::::::::::::::::::cccc::cccccc:ccc:cccccccccccccccc:cccccccccccccccccccccccccccccccccccccccccccccccc\n:::::::::::::::::::::::::::::::::::::::::::::::::::::::::cc:::::::::::::::ccc:::::c:::cc::::::::::::::::::::::cc:::c::cccc::::::::::cccccccccccc:ccc::c:::::::ccc:::::::cccccccccccccccccccccccccc:::::::::::::::::::cccccccccccccc::::::::ccc::c::cc:::cc::::::::::::::cc:::::cccccccccccccccccccccccccccc::::::::::::::::::::ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\n::::::::::::::::::::::::::::::::::::::::::::::::::::::c::::::::::::::::::::c::::::::::::::::::::ccccc::::::::::::ccc::cc:::::cccc::::cccccccccccc::::cccccc:::ccccc:::::cccccccccccccccccccccccccc::::::::::::::::::::c:cc:::cc::::::::::::cc::cc:::::::cccc::::::c:::::cc::::::ccccccccccccccccccccccccccc:::::::::ccc::::::ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\n:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::cc:::::::::::::::ccccccc:::::ccccc::ccc::ccccccccccccccccccccccccccccccc:cccc::::cccccc::::cccccccccccccccccccccccccc::::::::::::::::c:::::cc::::::::cc:::cccc::::cc::::ccc:ccc::c:::::::::cccc::::ccccccccccccccccccccccccccc::::::::::cc::::::ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\n::::::::::::::::::::::::::::::::::::::::::::::::::::c::::::::cc::::::::::::::cc:::::::ccccc:::c:::::ccc::cccc:::cccccc:ccccccccccccccccccccccccccccccccccc::::ccccccc:::cccccccccccccccccccccccccc:::::::::cc:::::::::::::cc:::cc::cccccccc::cccccc::ccccccccc:c::::::::ccc:::::cccccccccccccccccccccccccccc:::::::::ccc:::::ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\n::::::::::::::::::::::::::::::::::::::::::::cc:::::::::ccc:::::c::::::cc:::cccc:::c:::ccccc::::ccc::cccccccccc::cccccc::ccccccccccccccccccccccccccccccccccc:ccccccccc::ccccccccccccccccccccccccccc:::::::::::::::::::::::::cc:cccc::cccccccccccc:ccc::cccccc:ccc::::::::cccc:::::ccccccccccccccccccccccccccc:::::::::ccc:::::c:ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\n:::::::::::::::::::::::::::::::::::c:::::::c:::::c:::::cc::::::::::::cccccc::::ccccccccc:::::::ccccccccccccccccccccccc:cccccccccccccccccccccccllccccccccccccccccccccc::cccccccccccccccccccccccccccc:::::::::c:::::::::::ccccccccccccccccccccccc::cc:::::cccccccc:::cc:::ccccc::::ccccccccccccccccccccccccccc:::::::::cccc::::ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\n:::::::::::::::::::::::::::::cc::cc:::::::c:::::::::::::c:::cc:::::::cccccc::::cccccccc:cc:::ccccccccccccccccccccccccccccccccccccccccccccccoxk00Okxddoolllllloodxkkxdoloolccccccccccccccccccccccccc:::::::::c:::::::::cccccccc::cc::ccccc:::cccccc:ccc:ccccccccc:ccccc:::cc:cc:::ccccccccccccccccccccccccccc:::::::::ccccc:::ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\n::::::::::::::::::c::::::::ccc:::cc:::::::c::::cc::c::::c:::ccc:::ccc::::::ccc:::ccccccccccccccccccccccccccccccccccccccccccccloxxkOO0OkkkkOKXK00000000KKK0KKXXNNWWWWNXKKK0kdoolclloooddollccccccccc:::::::::cc:::::cccccccccccc:ccccccccc::cccccccccccccc:cccccc:ccccc:::cc:cc:::cccccccccccccccccccccccccccc:::::::cccccc:::ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\n:::::::::::::::::::::::::::::::::::::::c::ccc:::cc::cc::ccc:::::cc:::cc::::ccc::cccc:cccccccccccccccccccccccccccccccccccccccdkO0KKK0000OOkkOKXXXXXXXXXNNXKXNNNNNNNNNNNXXXXXKKKOO0KKKKKKK0Oxxoolllcc:::::::::cc::::ccc::cccc:cccccccc:ccccccccccccccccccccccccccccccc:cc:::cc:::::ccccccccccccccccccccccccccccc::::::::c::c:::ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\n:::::::::::::::::::::ccc::::c:::c:ccc::c::ccccc:ccc::::ccccccccc:cc:cccccccccccccc:ccccccccccccccccccccccccccccccccccccccclxOOOO00KKKKKKK00KKXXNNNNXNNNNXXXXXNNNNNNNNNXXKKXXXXXXXXXXXKKXXNXXK00KOdl::::::::ccc:::::cccccccccccc:cccc::ccccccccccccccccccccccccccccc::cc:::ccc:cc::ccccccccccccccccccccccccccccc:::::::cccc::::cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\n::::::::::::::::::ccccccccc:cc::cccc::ccc:ccccc:ccc:::ccccccccccccccccccccccccc:ccccccccccccccccccccccccccccccccccclok000O0XNNNNNXK00KKXK0K0xxk000KXXXXXNNNNNNNXNNNNNNXXXXXNNXXXXXKX0dodxxxxddxOOxl::::::::cccc::::ccccccccccccccccccccc::cccccccccccccccccccccccccccccc::cccccc:::cccccccccccccccccccccccccccc::::::::ccccc::cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\n:::::::::::::c::::cccc:::c::ccccccccc::cc:ccccc:ccc::cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclx0XNNNXNXXXNNNXKKKKXXX0OOxooddoodkKXKKKKXNXXNXXXXKKKKXX00KXKKXXNNXK0kko:;;::cccccc::::::::ccc::::ccccccccccccccccccccccccccccccccccccccccccccccccccccc::cccccc:::cccccccccccccccccccccccccccc::::::::cccccc:::cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\n::::::::::::::cc:ccc::ccccc:cccccccccc::cccccccccccccccccccccccccccccc:cccccccccccccccccccccccccccccccccccccccclxKNNNNXOO0KOkO0KXXNXXXXK0kololllol:lO0kkxkOKXXXXK0kkxddxO000OOkOO0KKXNNNXOxl:::coolc::::::::ccc:::ccccccccccccccccccccccccccccccccccccccccccccccccccccc:::cccccc:::ccccccccccccccccccccccccccccc::::ccccccccc::ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\n:ccc::::::::::cc:c:::cccccccccccccccccccccccccccc:ccccccccccccccccccccccccccccccccccccccccc:ccccccccccccccccccoOXNWWNN0dcllldO0KKXXXXXXXXKxllldkkkxxdlc;;lOK00OOOd:;;;:cdk0OxkxoodxxkOOOOO0Okl,cO0kl::::::::ccc:::ccccccccccccccccccccccccccccccccccccccccccccccccccccccc::cccccc::ccccccccccccccccccccccccccccc:::cc:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\n::cc:::::::::c::::ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccldO00KNNNXKOddk0KXXXXXXXXXXKK0OOOOO0KKxc;,,.;oxxddxkOx:;,;loddxxolddlc::ccccc:;cooox0KKkl:::::ccccc:::cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc::ccccccccccccccccccccccccccccc:::::cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\nc:cc:::c::cccccc::ccccccccccc:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccldkkxdxkKK000kxkkOO0000OOOOOkdloOKKO0K0dc,...;ccc:lxO0dccclllccloolllc:;;;:cc:;.,:cok0Okkkl::::cccccc:::ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc::ccccccccccccccccccccccccccccc:::::cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\nccc::::ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclx0KK0OxdxOOOxl::codxxdoooolccoxO0K00kdoodl;''',;;;:lxOOdollccc::cc:;;;;,'',;;;;'','';:coxxl::::cccccc:::cccccccccccccccccccccccccccccccccccccccccccccccccccccccc:cccccc::cccccccccccccccccccccccccccccc::c::ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllccccccccccccccccccccc\ncc:::ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccldxOKXNXKOxxdl:;;,,,,,,,ckOx;:k00Okkxolc;;;:;,''',,'',:ok0kocc::,.',,;;;;,''',;,;,...',;:ccc::::::ccccc:::cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc::ccccclcccclcccccccccccccccccc::ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllcc\nccc::ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccooloOKKKK0Oo:;,''..'.. ;xO0OxxOkxdddddoll:;,..,,,,;'.'',:ll:,,,,'..'''',,;;,,,,;;;,',,;;::cc:cccc:ccccc::ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc::ccccllccccccclcclllcccccccclcc::ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclllccccccccccccc\ncccc:ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclollxOOOO0Oxl:;'''',;;;cdxodxdoolllldk00Od:,'..,;,;;;,,'.....'',,,,,'''.''''.....,,,''',::ccc:cccc::ccccc:ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc:::cccclcccllcclcccllcccccccclcc:::ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllcclcclcccccccccccccccc\nccc:ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclxkxdddxO0Oxdoc;'',;:ldxdlc:coolcc::ldxolc;;::,..,,;;;;;;'...'';cccc::;,,,,,,,'....,',;:oolccccccccccccccc:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc::cclcccccllccccclccclcllllclccc:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccclllccccclllcccccccccccccccccccccl\ncc::cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclxOOxddxkkkdoool:;,.';ccc:::::;::::::cc;;;:cdddo:'''',;;;;;;,,;:codddolc:;;,,,;,,''',,,,;:llllc:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclllclllcccccccclllllllllllcccccccccccccccccccccccccccccccccccccccccccccccccccllccllccccccllccccccccccccllcccccccllcccccc\nccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclxkkkkO00koc;,'.';;,...;;::;::;,,;:::::::;;;::::::;'''',,,,;,;;:loxkkOkxdolc:;;;,,,'...',:lllclccccc::cccccc:ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc:cclllllllclllcccclllllllllllcccccccccccccccccccccccccccccccccccccccccccccccccccllcclllcccccccccccccccccllclccllccclccccccc\nccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccldddkOOO00OOOOxl,.';;'...,;;;;;;,;;;;:::;;::;,'',;;,',,,,,,,,;;:loodxxxxxxxddoolc:;;,...;cdkkdlllc:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllllcllllllccclllllllclllllcccccccccccccccccccccccllccccccccccclccclcccllccccllcccccccccccccccllcclllccclccllccccccccccc\ncccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccloodOOkkkOOOOOOkxc,;:,.   ..',;;;;;;'',,,,,,,;,...,;,,;;;,,,;;;:clllllcc::clodxxddolc;'',;:ccodlccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc:cclllllllllllllllllllllllllllc:ccccccccccccccccccccllccclllcccccccccllcccccccccccccccccclccccccllcccccccclccccccccccccccc\nccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclollxOkxxxxxxxddddoc;'....     ..,;;;,'....';,.','.',,;::::;;;;;::cloddddooc:;::cclddolc:;:::::cllllc:cccccccclcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclccccc:ccllllllllllllllllllllllllcllc:cccccccccccccccccccccccccllccccccccccccccccccccllccccccllllcccccccccccccccccccccccccccccll\nccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclccdkkxdooollccc:::;'..........  ..,,,;,''',;,.''',,,;:ccc:::::::::::cccclccc::::::cloolllc:ccccccllccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclccccc::cllllllllllllllllllllllllllllc:cccccccccccccccccccccccccccccccccccccccclllllccccclllccccccccccccccccccccccccccllllllllll\ncccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccoxdxkdl::::::cc;,,''..      .....',,,;;,,,,,'',;;:cloodollc::;;;;:;;,,;;;;::::::c:looooolcclllllllcccccccccccccccccccccccccclllcccccccccccccccccccccccccccclccclccccccccccccccccccccccllllllllllllllllllllllllllllc:cccccccccccccccccccccccccccccclllcclllllllllllcccccccccccccccccccccccccclllllllllllllllll\nccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllllloooc:;,'',;;,,;:.....    ....'',,,,,,,,;;;:ccooddxxxxxdol:;;;:ccc::;;;,;;;;;;clollllllllllllllcccccccccccccccccccclccccclccccccccccccccccccccccclcccccccccllcccclcccccccccccccccccllllllllllllllllllllllllllllccccccccccclcccccccccccclllclllllllllllccclllccccccccccccccccccccccllllllllllllllllllllllll\ncccccccccccccccclccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc::;,,;:;..  ';;';c;'';;'.   ....'',,,;;;;;;:clodddxxxxkkkkkkxdoddxxdol:,,,,;;,;:oxdlllllllllllllllcccccccccccccccclcccccccclccccclllcccccccccllcccclcccccccclllccccccccccccccccccccccclllllllllllllllllllllllllllcccccccccccccccllcccccccccccclcccccccccccccccccccccccccccccclllllllllllllllllllllllllllllll\nccc::cccccccccccccccccccclccccllcccccccccccclcccccccccccccccccccccccccccccccccccccccccccccccccclccol:;,,''''....','';:;,:;.     ...',,,,;;;;;:ccloddxxxxxkkOOOO000Okxddool;'',,;;:loxOkoclllllllllllllcccccccccclccccccccccccccccclccllllllcccccccclcccccccccccclllcccccccccccccccllccccccllllllllllllllllllllllllllllccccccccccccccllccccccccccccccccccccccccccccccccccllllllllllllllllllllllllllllllllllllllll\nccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclcccclllccccccccccccccccclllllo:;,,,',,,,,,,,'';::::,.      ..',,;;;::::cccooddxxxxkkkOOO00000Okxolllc;;:::coxkO00dllllllllllllllccccccccccccccccccccccllllcclcclllllllcccccclllccccccccccclcccclcccccccccccccccccccclllllllllllllllllllllllllllllcccccccccllccccccccccccccccccccccccccccclllllllllllllllllllllllllllllllllllllllllllllllll\nccccccllccllccccccccccccccccccccccccccccccccccccccccclccccccccccccccccccccclllcclccccccllcccclcclccc:;;;,,,,,,;;;::;;:c::;'.  .....',;;:::::ccllloddxxxxxkkkkOOO000000OkxdolooddxkOOO00Oolllllllllllllcccccccccccccccllllcclllllcllcclllllllcllccllllcccccccccccccccccccccccccccccclllcccccllllllllllllllllllllllllllllc:cccccccccccccccccccccccccccccccllllllllllllllllllllllllllllllllllllllllllllllllllllllll\nccccccccccccccclccllccllllllcccclccccccccccccccccccccccccccccccccccccccclllllllllcccllcclllllllcllcc:::::;;,',;;;:cl::lc:;;,,,,'...,;:::ccclollllooddddddxxxxkkkkOO00000OOOOOOO00OOOOO00xlllllllllllllccccccccccclcccclllcclllclccccclccccccccccccccccccccccccccccccccccccccccllcllllllccccllllllllllllllllllllllllllllc:cccccccccccccccccccccllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll\nccccccccccccccccccccclcccllcccclllclllclllllccccccccccccccccccccccccccccccccccccccccccccccccccccccccc:::;''...,;;;::;;:clcc:::::;;,;:::cccloooooooooooodddddddxxxkkOOOOO0000000KKKK00O0KOollllllllllllccccccccccccccccccccccccccccccccccccccccccccccccccllllllllllllllllllllcccccclcccccccclllllllllllllllllllllllllllllc:ccccccccccclllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll\ncccccccccccccccccccccccccccccccccccccccccclllclccclcccllllllllcclllccccccccccccccccccccccccccccccccccc:;,.....,;;;:;;,,;;::clllllcc::ccllllllloooooooooooddddddxxkkkOOOOOOOOOOOOOO00K0KKKxllllllllllllcccccccccccccccccccccccccllllcclllllllllllcclllllllllllllcccllccllllllclccccccccccccccllllllllllllllllllllllllllllccllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll\ncccccccccccccccccccccccccccccccccccccccccccccccccccccccllcccccccccccllcccccclllccllllllllllllllllllllcc:;;,..';:::;;,,'.'',,;::cc:::clloooolloddodddoooooddddddxxxkkOOOOOOOkxodxkO00KKKXXOolllllllllllccccccclccclllllllllllcclllcllllcllllllllllllcccccllllcccccccccccccccllcccccccccccc::clllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllool\nllllllllllllccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllllclllllllcc:;,..,;;;,,,,,''...',,;;;;;:loooooddddddddddddoooddddddxxxkkkkkkkkkxddOKXXXXKKXXXKxllllllllllllcccccccccccccccllcclllcllccclccccccccccccccccccccccccccccccccccccccccccccccccccccccccllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll\nllllllllllllllllllllllllllllcllccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccllccc:,'';:;,,,,,,;,'...',,,,;;;clooddddoodddddddooddooodddddxxxxkkkkkkkOkxkkxdxxkkxxkOkolllllllllllccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllolllllllllllllllllllllllllllooloooloo\nllllllllllllllllllllllllllllllllllllllllllllllcllcccccccccccccccccccccccccccccccccccccccccccccccccccccc:,.,cllc:;;;;;;;,,'',;;;;;;:llooddddodddddddddddooooodddddxxxkkkkkO0KOdc;..'',:cccoollllllllllllccccccccccccccccccccccccccccccccccccccccccccccccllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllloollllllllllllllollllolooooooooo\nllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllcccccccccccccccccccccccccccccccccc::;;cllol:;;;:::;,'',;;;;;;:clloooodddooddddddoooooodddddddxxxkkOOO00K0ko:;;;:;clllllllllllllllllc:ccccccccccccccccccccclccclllcllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllollllllllllllloooolllllloooooooooollolll\nllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllcllollcccc:;,'',;;,,,,;;;;;:::ccllloooooooooooooooooooodddddddxxkkkkkOO0KK0kdlclolllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllollllllllllllllllllllllllllllllllllllllllllllllllllllllllloooollllloollooolllloooooooollooooooloolllllcc\nllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllollool::;,;;;:;'..',,,,;;;::::::ccclllllllooooooooooooooddddddddxxxxxdddxO0000Oxllollllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllolllllllllllllllllllllllllllllllllllllllllllllllllllllllllllollllllloollloollloooooooooollooollolllllcccc::::::\nlllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllldo:;;:cllll:'...;;;::ccccccccccccccllllllllloooooooooooodddddddddolclooollloollllllllllllllllllllllollllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllooolllloooollllllloooollloooloooooolooooooooolllllcccc::::::::::::::\nllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllc:clooooollcc:;..';::clllllolcccccccccccllllllllllllloooooooooddddxkkkxdxxxxoclllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllloollllloollllllolllllllllllllllollllllllloooolllooooooolllllllloolloolloooloooolllllcccc::::;:::::::::::::::::\nlllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllc:::::::c:::;,',;;:clooooddolcccccccccccccccllllllllloooooooddddxkOOOkdlloddooloollllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllloollllllloolloollllollllllllllllllollooollllllllllloooloooooooolllloollllllloooooolllllllccc::::::;::::::::::::::::cccccccc\nlllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllc:::::::::;;,'''.,:cloodddddolcccccccccccllcclccclllllloooooddxxkOOOOkdoccclooooolollllllllllolllllllllllllllllollllllllllllllllllllllllllllllllllllllllllllllllllllllllllloolllllllllllllollooooooooooooolllloooooollllooooollllloooollooooooooooooooooollllllccccc::::::::::::::::::::::::ccccccclllllllo\nlllllllllllllllllllllllllllllllllllllllllolllllllllllllllllllllllllllllllllllllllllllllllllllllllllllc::;:::;;::cc:;'.,:coodddxxddolc:cccllllllllllllclllllllllooodxxkO000K00kdoooolllllllllollllllllolllllllllolllloolloolllllllllllllllllllllllolllllllllllllllloolllllllllllllloollllooooolloooooooooooooooooooooooooolllloollooooooooooollooooooollllllcccc:::::::;:::::::::::::::::ccccccclllllllllllllllll\nooollllllllloolllllllllllllllllllllllllooollllllllllllllllllllllllllllllllllllllllllllllllllllllllloolc:;;;:::cclllllc:clodddxxxxxdolc::cccllllllllllllllllllllllooddxkO00KKKKK0kdooollllooloooooollooollllllllloolllllllllllllllllllllllllllllllllllllllllllooolllollllllllllllllllolloollooolooloolooooooooooooooooooooooolooollooooooollllllllccccc::::::::;:::::::::::::::ccccccccllllllllloolllllllllccc:::\nlloooolllollloollllllllllllllllllllllllllooollllllllolllllllllllloolllllllllllolloolllllllllllllllllollc:;;:::::::::cclllodddxxxxxxddlc::::ccccccclllllllllllllllllloodxxkOOOOkkxdolooooooooooooolllooolllllllllooollloolllllllloolllooloollloolllllloollllooooollllollloollloolooloooooolloollooooooloooooooooooooooooooooooooollllllccccc:::::::;::::::::::::::::::::ccccccclllllllllloollllllllcccc::::cccccl\nooooolllllllllollllllolllllllolllooolllllloooollllllllllllollllllllllolllllllllllllllllllllllllloolllllccc:c::::::;;::lloodddxxxxkkxxdolcc::ccccccclcclllllllllllllllllloooddddoddoooooooooooooooooooooooooooooooloooooollllllllooollllllooollooolllooooooooolllloooooolllllloolllooooolooooollooooooooooooooooooooooooooooolc:::;;;;;;:;;;::::::::::::::::cccccccclllllllllllloollllllllcccc:::::ccccclllllllll\nlllllllloooooolllooooollollooolllooooooolllooooolllllllllloooooooollooooooollooooollllooooolllooolloooolcccccc:::::::clooodddxxxkkkkkxdddoollllcccccclllllllllllloooollllloooooooooooooooooooooooooooooooooooooooollloooooooolllooolllllllllloooooooooooooooollooloooooooooooollloooooolooooooooooooooooooooooooooooooooooool:;,,;;;;;::::::::::cccccccccclllllllllloollolllllllccccc:::::ccccclllllllooolloollo\n:::c:cccccclllllllooooooooooooolloooooollooooooolooolllooooollooolllooooooolooooooolooooollooooooloooooolc::::::;;;:clooooodddxxxxkkkkkkxxxdddolllcccccclllllllloooooooooooddddoooooooooooooooooooooooooooooooooooooooooooooooolooooolooolloooooooooooooooooooooooooooooooooooolloooooooollllllloooooooooooooooooooooooooooolc:;;;;:::::cccccccllllllllllloollllllllllccccc::cc:cccccclllllllloooooooooooooooolo\n::::::::::::::::::cccccccclllllllllllooooooooooooooollloooooolooooooooooooooooooooooooooolooooooooooooool:::::::;;;cllooooodddxxxxkkkkkkkkkxxxddoolllcccllllloooooooodddddddddoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooolllllllllllcccccc::::::cloooooooooooooooooooooooooooolcccccccllllllllllllooolllllllllccccc::::cccccclllllllllooooooooooooooooooooooolooo\n:::::::::::::::::::::::::::::::::::cccccccllllllllllllllllloooooooooooooooooooooooooooooooooooooooooooollc::c::::;:loooooooddddxxxkkkkkkkkkkxxxdddooollccccllllllooodddooooooooooooooooooooooooooooooooooooooooodxxkkOOOkkkkkxdooooooooooooooooooooooolollllllllllccccccc:::::::::::::::::::::::loooooooooooooooooooooooooooolllllllllllllolllllllccccccccccccccccclllllllooollooooolooooooooooooooooloooooooooo\nlllllccccccccc:c:::::::::::::::::::::::::::::::::::::::cccccccccccllllllllllooooooooooooooooooooooooooooolc:::::::clooooooooddddxxxkkkkkkkkkkxxxxxddddoollcclllloooooooooooooooooooooooooooooooooooooooooooodxkO0KKK000OOOOOOOOkkkxolllllllllccccccccc::::::::::::::::::::::::::::::::::::::::::loooooooooooooooooooooooooooollllllllllllool::::::cccccccllllllllooooooooloooooooooooooooooooooooooooooooooooooo\nloolooollollllllllllllccccccccc:::::::::::::::::::::::::::::::::::::::::::::cccccccccccccclllcllllllllllllc::::::cloooooooooddddxxxkkkkkkkkkxxxxxxxxxxxxxddollllooloooooooooooooooooooooooooooooooooooooolloO0OO0KNNNNNXK0OOOOOOOOkkxlc::::::::::::::::::::::::::::::::::::::cccccccccccllllllcclooooooooooooooooooooooooooooolllllllllollolccclllllllooolloooooollloolloooooolooooooooooooooooooooooooooooooooo\nllllooooooooooooooooooooolllllllllllllcccccccccccccccc::c::::::::::::::::::::::::::::::::::::::::::::::::::::::;;:loodddoooooddddxxxkkkkkkkxxxxxxxxxxxxxxxxdolllolcllccccclooooooooooooooooooooooooooooooloxkxdxkO0KXXNNNNX0OxxkOOOOO0ko::::::::::::::ccccccccccccccccccllllllllllllllllolooollllloooooooooooooooooooooooooooolllllllloollollllllloooloooooooooooooooooolooooooooooooooooooooooooooooooooooooooo\n::::ccccccllllllllllllloooloooooooooooloooollllllllllllllllllcccccccccccccccccccccccccccc::::::::::::::::::::::::cloooddoooooddddxxxkkkkkkkxxxxxdxxxxxxxxddddoollccll:::::cooooooooooooooooooooooooooooodddollllodxkkO0KXXNNNK0xddxkO00Odccccccccclllllllllllllllllloooolloooooooolllollllloollllloooooooooooooooooooooooooooollllllllollooolllllloooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\nllccccccccccc::cccccccccccllllllllloooooooooooooooooooooooooooooooolllllllllllllllllllllllllcclccccccccccccccc:::clooddddoooooddddxxxkkkkkkxxxddddxxdddddddddooollclolc:::coooooooooooooooooooooooooooxkkxlllllllllooxkO00KXXNNX0xooddddxdollllllooooooooooooooooooooolloolllllllcclcccclllloollllooooooooooooooooooooooooooooolllloloooooooollooloooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\nlllloooolllllllllllccccccccccccccccccccccclllllllllllllooooooooooooooooooooooooooooooooooooooooooooollllllllollcccooddddddooooodddxxxkkkkkkkxxxxxxxxxdddddddoooollllodollclooooooooooooooooooooooooodxxxxollc:;,;:clllodxkO0KXXNNNKOxdoooxdoolooooooooollllllllllllcccccccc::cc:ccccccccloolllllllooooooooooooooooooooooooooooolllollooooooolllooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\noooooooooooooooooooooooolllllllllllllcccccccccccccccccccccccccllllllllllllllllooooooooooooooooooooooooooooooooooloodddddddddoooddddxxkkkkkkkkkkkkkkkxxxddooooooolllldxdollloooooooooooooooooooooodddlclll:;:;,'''',;cclllodxO0KXNNNNXKOdoddlclccccccccccccccccccccccccccclllllllllllllllloooooollloooooooooooooooooooooooooooooollllooolooooollooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\nooooooooooooooooooooooooooooooooooooooooooolllollllllllllllccccccccccccccccccccccccccccccclllllllllllllllllllllloddddddddddddddddddxxkkkkkkkkkkkkkkkkkxxddoooooolllodkxolllooooooooooooooooooooddol::::::::cccc:;,'''',:llloxOO00KKXXXXKOxolcclcclclllllllllllllloooooooooooooooolllllllloooooollllooooooooooooooooooooooooooooolloooooooooooolooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\nooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooolllllllllllllllllllcccclccccccccccccccccldxxddxxxdddddddddddxxkkkkkkkkkkkxxxxxkkkxxddddooooodxkkdlllooooooooooooooooooddolc:ccc:::lxkOkkkxddoc:;,;codk000OOOKKKKXXKOdooooooooooooooooooooooooooooooooooooooooooollooooooolllooooooooooooooooooooooooooooolllooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\nooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooodxxxxxxxxxxdddxddddddxkkOOOkkkxxxxxxxxxxxxxddxxddddddxkkdooodxxdooooooooooooddolcllllccccloxkkkkOO00KKKKK00KKK00000OOKKKKKXXX0kdoooooooooooooooooooooooooooooooooooooooollloooooolllooooooooooooooooooooooooooooolllooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\nooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooxkkkkkxxxxxxxxxxxxddddxkOOOOOkkxxxdddddddddddxxxxxddxxkkOOOkdxO00OOkxxdooooooolllllllllccclloddddxxxkOKKKXXXK0OOO0KKK00KXXKKXXXXKOxoooooooooooooooooooooooooooooooooooooollloooooollloooooooooooooooooooooooooooooollooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\noooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooodxkOkkkkkkkkkkkkkkkxxdddxkOO0OOkxxddddddddooddxkkkkkxxkkkkOO00xloxkO0KKK0Okxollllllllllllcccclodooooooodxxxxk0KK0OOO00KK00KKKKKKXXXXX0kdoooooooooooooooooooooooooooooooooooolloooooollloooooooooooooooooooooooooooooollooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\noooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooodxkOOOOOkkkkkkkOkkkkkkxxdddxOO00OOxxdddooooooddkkkOOOkkkkkOOOOO0Oolooddxkkxxddoollooollllllcc:::clllccclloolccldk0KK00000000O0KKKKKKKKKXX0xooooooooooooooooooooooooooooooooooollooooooollooooooooooooooooddoooooooooooollooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\nooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooodxkOO00000OOOOOOOOOOOOOOkkxxddxkO000OkxddoooooddxkOOOOOOOOOOOOOOOO00d:cooooooooddooooooolllllllccc:::::,,,'':olccccldk00000O000OO00KKKKKKKKKX0xooooooooooooooooooooooooooooooooooolooooooolllooodoooooooodddddooooooooooooolooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\nooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooddxkOO00000000000OOOO0000000OOkkxxxxkO000OkdddddddxkkO00000OOOOOOO00OO000xl:cloddddddddoooollllllllllccc:cclcclodxxollllllodxO0000000OO0KKKKKKKXXXKKOdooooooooooooooooooooooooooooooooolooooooolllodoodoooooooddoooooooddddooooolloooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\noooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooodxkkO00KKKKKKKKKKK00000000000KKK00OkkkxxkO0KK0kxdddxxkOO00KKK00OOOO0000000KK0kdc::coddddddooooolllllllllllccccoddxkkkxxxdoodddddoxO0000000O0KKKKKKKXXXXXK0kdoooooooooooooooooooooooooooooooloooooooollooooddoodddddddddddoodoooooooolloooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooood\nooooooooooooooooooooooooooooooooodooooooooooooooooooooooooooooooooooooooooooooooooooooooodxkkO0KKKKKKKKKKKKKKKKKKKKKKKKKKKKKXKKK00OOkkxk0KKKOOkkOOO000KKXXKK0OO00KKKKK0KKXK0kol::clooooooolllllllllllllllllllodddoooddxdodddxxdddkO00000000KKKKKXXXXXXKXKOdooooooooooooooooooooooooooooooooooooooollooooodoodddddddddddoodooooodoolloooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\noooooooooooooooooooooooodoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooodxkO0KKKKKKKKKKKKKKKKKKKKXKKXXKKKKKKKXXXXXXXK00OkkkOKXK00000KKKKKXXXXKKKKKXXXXXXXXXXXXX0kdlccccllllllllllllllllllllllllllcclllllloddxxxdxdddddkO0000000KKKKKXXKXXXKKK0xoooooooooooooooooooooooooooooooooooooollooddddoodddddddddddddddddddddoolodooooooooooooooooooooooooooooooooooooooooooooooooooooooooooodddoooooooooooo\nooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooddddddoodkO0KKKKKKKKKKKKKKKKKKKKKXXXXXXXXXXXXXXXXNNXNNNXKK00OkO0KXKKKXXXXXXXXNNXXXXNNNNNNNNXXXNNNNNX0kddocccccccccclllllllllllllloddoooollllllooxkxxxdddddxkO00000000KKKKKKKKKKKKOdoooooooooooooooooooooooooooooooooooooolooddddddddddooddddddddoddooddooloooooooooooooooooooooooooooooooooooooooooooooooooooooddddooodddooddooooooood\noooooooooooooooooooooooooooooooooodooooooooooooooooooooooodddooododddddooddooddxkOKXXKXKKKKKKKKKKKKKXXXXXXXXXXXXXXXXNNNNNNNNNNNNNNNNXXXKKKXXXXXXNNXXXXNNNNNNNNNNNNNNNNNNNNNNNNNXK0kdol:;;;:::::ccccccllcccldkkOkxddooooooodxkkkxxxxxxxxkOOOOO00000KKKKKKKKKKOdooooooooooooooooooooooooooooooooooooolloddddddodddooddddddddddddddddooooooooooooooooooooooooooooooooooooooooodddooodddoooddddddddddddddddddooooodd\noooooodddddoooddoooooddooooooooooooooooodddoooddoooooooooooooddddddoooddxxkkO0KXXXXXXXXXXXXXXKXXXXXXXXXXXXXXXXXXXXNNNNNNNNNNNNNNNNNNNNNNNXXXNNNNNNNNNNNNNNNNNNNWWWNNNNNNNNNNNNNXX0Okdolc;;;;;;::::::ccccccldxxxdoooodddddddxxxxxxxxxxxdxxkkOOOOOOO00000KKKKK0kdoooooooooooooooooooooooooooooooooooolloddddddddddddddddddddddddodddooooooooooooodoooooooooooooddooddoooooooooodooodddooodddddddddddddddddddoodddo\ndooooddoodddddddoooooooodddddooooooooooooooooodoodddoodoodddddoooddxkO0KXXXXXXXXXXXXXXXXXXKKKK00KK00KKKKKXXXXXXXXXXXNNNNNNNNNNWWWWWWNNNNNNNNNNNNNWWNNNNNNNNNNWWNWWWWWWWNNWNNNNNNXK0kxdolc:;;;;;;;;;;:::ccc:codoooollooooddddddddddddddddddxxkkkkkkOOOOO000KKK0xoooooooooooooooooooooooooooooooodooooloddddddddddddddddddddddddddddoolodoooooddddooodoooooooooddoooooddoodoooddddodddddddddddddoddddddddddddddddo\nddoooooddddddddddddddddddddddddddddddddddoooooddddddooddddddodxkO0KXXXXXXXXXXXXXXXXXXXXXXKKK0Okkkxxk00KKXXXXXXXXNNNNNNNNNWWNNNNWWWWWWWWWWWWWWWNWWWWWNNNNNWWWWNNNWWWWWWWWWWWNNNNNXK0Okxdoolc:;;,,,,,,;;:clldO00OdoooolllllllllllooooooooodoodddxxxxxkkkkOOO0KK0Oxoddooooooooooooooooooooooooooooooooolodddddddddddddddddddddddddddddoooddddddooddooddooooooooooooddodddodddddddddooddddddddddddodddddoddddddddddd\nodddddddddddddddddddddddddddddddddddoodddddddddddddddddddodxO0KXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXKK0000KKKXXXXXXXXNNNNNNNNNNNNNNNWWWWWWWWWWWWWWWWWWWWWWNNNNNNNNNNNWWWWWWWWWWWWWWNNXXXK0Okxxddolc:;;,,,,;cdkO0KXXNX0xoooolllllllllllllllllllollllooddddxxxkkOO000000xoodddooooooooooooooooooooooodddddoolodddddddddddddddddddddddddddddoooddooooooddoooodooddddddddddddddddddddddddddddddddddddddddddddddddddddddddd\nddddddddddddddddoddddddddddddddoodddoddddddddddddddddddddk0KXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXKKKKXXXXXXXXXNNNNNNNNNNNNNNNNWWWWWWWWWWWNNNNWWWWWWWNNNNNNNNNNNNNNNWWWWWWNNNNNXXXK00Okkxxddolc:;;;;;:okOO0KXXXXKkdooollllllccccccccccccccclllllooddddxxkOOO000KKkdoddooodddoooodddooooooooooddooooolooddddddddddddddddddddddddddddoooddoooooddddooodddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd\nddddddddddddddddddddddddddddddddoddddddddddddddddddddddk0KKKKXXKXXXXXXKXXXXXXXXXXXXXXXXXXXXXXXXXXXXKKXXXXXXXXXXNNNNNNNNNNNNNNNNNWWWNNNNNNNNNNNNNNNNNNNNNNNXXXXXXNNNNNNNNNNNNNNNNXXXK00OOkkxxxdolc:::::lxkO0KKXXXXX0kdooolllllllccccccccccccccclllloooodddxkkOOO0KKOdoddoooddooooooooooooodoooodoodooooodddddddddddddddddddddddddddddooododddddddddoddddddddodddddddddddddddddddddddddddddddddddddddddddddddddddd\ndddddddddddddddddddddddddddddddddddddddddddddddddddddxO0KKKKKKKKKKKKKKXXXXXXXXXKKXXXXXXXXKKXXXXXXXXKKXXXXXXXXNNNNNNNNNNNNNNNNWNNNWWWWWWWWWWWNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNWWNNNNXXKK000OOkkkxxddolcc:codxO0KKKXKXXKKkdoooollllllcccclccccccccccccclllloodxxkOOOOOOkdodddoddddoooodddooooooooodddddoooodddddddddddddddddddddddddddddooodddddddddddoodddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd\nddddddddddddddddddddddddddddddddddddddddddddddddddddxO000KKKKKKKKKKKKKKKKKKKKKKKKXXXKKXXXXXXXXXXXXXXXXXXNNNNNNNNNNNNNNNNNNNNNNNNNNWWWWWWWWWWWWWWWWWWWWNNNNNWWWWWWWWWWWNWWWWWWNNNNXXXKK000OOOOkkxxxddolclodxO00KKKKKKKK0kooooolllllcccccccccccccccc:ccllllodxxxxdoodxxdddooddddooddddddddoooooodddddoolodddddddddddddddddddddddddddddooodddddddddddoddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd\ndddddddddddddddddddddddddddddddddddddddddddddddddddxO0000KKKKKKKKKKKKKKKKKKKKKKKKKKKKKXKKXXXXXXXXXXXXNNNNNNNNNNNNNNNNNNNNNNNNNNNNWWWWWWWWWWWWWWWWWWWWWWWWWNWWWWWWWWWWWWWWWWNNNNNNNXXXK0000OOOOkkkkxxddolloxkO0000KKKKKK0Oxdoloollllcccccccccccccc::::cccllllolllccclxxdododddooddddddddooddoooodddddolodddddddddddddddddddddddddddddoooddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd\nddddddddddddddddddddddddddddddddddddddddddddddddddxkOO00000KKKKKKKKKKKKKKKKKKKKKKKKKKKXXXXXXXXXXXXXXXNNNNNNNNNNNNNNNNNNNNNNNNNNNNNWWWWWWWWWWWWWWWWWWWWWWWWNNNNNNNNNWWWWWWWWNNNNNNNXXXKK0000OOOOkkkkxxddooddxkO00000KKK00Okxxddolllllllllllcccccccccccclllcccc::cccccdkxddddddooodddddddddddoooddddddooodddddddddddddddddddddddddddddolodddddddddddoodddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd\ndddddddddddddddddddddddddddddddddddddddddddddddddxkO000000KKKKKKKKKKKKKKK0KKKKKKKKKKKXXXXXXXXNNXXXXXXNNNNNNNNNNNNNNNNNNNNNNNNNNNNNWWWWWNNNNNNNNNWWWWWWWWNNNNNNNNNNNNNNNNNNNNNNNNNNXXXXKK000OOOOOkkkkkxddoddxkOO00000KKKOkxxkOOkkxdoollllllccccccccccccccc::;;::ccllldxkxddddddodddddddddddddooddddddoooddddddddddddddddddddddddddddddooddddddddddddodddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd\ndddddddddddddddddddddddddddddddddddddddddddddddddxkOO00000KKKKKKKKKKK0000000KKKKKKKXXXXXXXXXXXXXXXXXXNXXXXNNNNNNNNNNNNNNNNNNNNNNNNNNWWNNNNNNNNNNNNNNNNNNNXXXXXXXXXXXXXXNNNNNNNNNNXXXXKKK0000OOOOOkkkkxdddddxkkOO00000KK0kxxkOO000KK0Oxdlllllcccc::::::::;;;;;;;:clooodxxddddddddddddddddddddooddddddoooodddddddddddddddddddddddddddddooddddddddddddodddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd\nddddddddddddddddddddddddddddddddddddddddddddddddxkOOO000000000000000000000000000KKXXXXXXXXXXXXXXXXXXXXXXXXXXNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNXXXXKKKKKKKKKKKKKKKKXXXXXNNNNNNNNNXXXXXXKKK000OOOOOOkkkxxddddxxkkOO000KKKKOxxkO00KKKKKXXK0kdlllcccc::::;;;;;;;;;;:cloodddxxdddddddddddddddddddooddddddoooodddddddddddddddddddddddddddddooddddddddddddodddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd\ndddddddddddddddddddddddddddddddddddddddddddddddxkkOOO00000000000000000000000000KKKXXXXXXXXXXXXXXXXXXXXXXXXXXXXXNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNXXXKK00O000000KKKXXXXXNNNNNNNNNNXXXXXXXKKK00000OOOkkkkxxxddddxxkOO0000KKK0kkO0KKKKKKXXXXXXKxllccc:::::::;;;;;;;;;:clodddxkkddddddddddddddddddooddddddooooddddddddddddddddddddddddddddddoodddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd\ndddddddddddddddddddddddddddddddddddddddddddddddxkOOOOO000000000000000000000000KKKKXXXXXXXXXXXXXXXXXXXXXXXXXXXNXXXXXXNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNXKKK000KKXXXXNNNNNNNNNNNNNNXXXXXXKKKKK0000OOOOkkkxxxxxdddxkOOO00K000K0O0KKKKKKKXXXXXXXKxllccc::::::::;;;;;;;::coddxxkOkdddddddddddddddddoodddddddoooddddddddddddddddddddddddddddddoodddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd\nddddddddddddddddddddddddddddddddddddddddddddddxkkOOOOOOO0000000000000000000KKKKKKKKXXXXXXKKKKKKKXXXXXXXXXXXXNNXXXXXNNNNNNNNNNNNNNNNNNNNNNNNNNNNWWWWWWNNXXXXXXXXXXXNNNNNNNNNNNNXXXXXXXXKKKK0000OOOOkkkkxxxxdddxxkOO000000KK00KKKKKKKKKXXXXXNKxlccc:::::::::;;;;;;;:clodxxkkkkdddddddddddddddddoddddddddooddddddddddddddddddddddddddddddoodddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd\nddddddddddddddddddddddddddddddddddddddddddddddxkkkOOOOO0000000000000000000000000KKKKKKKKKKKKKKKKKKKKXXXXXXXXXXXXXXNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNWWWWNNNNNNXXXXXXXXXXNNNNNXXNNNXXXXXXXXKKKK0000OOOOkkkkkxxxxxxxxkOOO0000000000KKKKKKKKKXXXXXXKxllc:::::::::;;;:;;;;:codxkkkkkkddddddddddddddddoodddddddooddddddddddddddddddddddddddddddoodddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddx\ndddddddddddddddddddddddddddddddddddddddddddddxxkkkkOOOOO000000000000000OO000000000000000KKKKKKKKKKKKXXXXXXXXXXXXXXNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNXXKKKKXXXXXXXXLOVEXYOUXFOREVERK0000OOOOkkkkxxxxxxxxxkkOOOO000000000000KKKKKKXXXXXX0dllc:::::::::;;;;;;;;:lodxkkkkkkxddddddddddddddoodddddddooddddddddddddddddddddddddddddddoodddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd\ndddddddddddddddddddddddddddddddddddddddddddddxxkkkkOOOOO000000000O0OOOOOOOOOOOOOOOOOO00000000000KKKKKKKKXXXXXXXXXXXXXXXXXXXXXXXXXXXXNNNNNNNNNNNNNNNNNNXXNNNXKK00KKKXXXXXXXXXXXXXXXXKKKKKKKK0000OOOkkkkkxxxxxxxxkkOOOOO00000O0000000KKKKKKXXXXKxllcc::::;;;;::::;;;;::codxxxxkOkddddddddddddddoodddddddooddddddddddddddddddddddddddddddooddddddddddddddddddddddddddddddddddddddddddddddddddddddxxdddddddddddddddd\ndddddddddddddddddddddddddddddddddddddddddddddxxkkkOOOOO000000000OOOOOOOOkkkxxkkkkkkkkOOOOOOO000000KKKKKKKKXXXXXXXXXXXXXXXXXXXXXXXXXXXNNNNNNNNNNNNNNNNNXNNNNXKK0KKKXXXXXXXXXXXXXXXXKKKKKKKK00000OOOOkkkkxxxxxxxxkkkOOOOOOOOkkOOOOO0000KKKKKKKKKxllccc::::;;:::;;;;;;;::cloodxxkkxddddddddddddddddddddddooodddddddddddddddddddddddddddddoodddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd\ndddddddddddddddddddddddddddddddddddddddddddddxxxkkOOOOOO0000000OOOOOOOOOkkxdddxxxxddxxkkkOOOOO000000KKKKKKKXXXXXKXXXXXXXXXXXXXXXXXXXXXNNNNNNNNNNNNNNNNNNNNNNXXXXXXXXXXXXXXXXXXXXXXKKKKKKKKK0000OOOOkkkxxxxxxxxxxxkOOkkOkkkddxkkkkOO000000KKKKKklllccc::::::::;;;;;;;;;;:cloddxkkxddddddddddddddddddddddoodddddddddddddddddddddddddxddxdodddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd\nddddddddddddddddddddddddddddddddddddddddddddddxxkkkkOOOOOO000OOOOOOOOOOkkxollllooolodxxxxkkOOOOO000000KKKKKKKKXKKKKKXXXXXXXXXXXXXXXXXXNNNNNNNNNNNNNNNNNNNNNNNNXXXXXXXXXXXXXXXXXXXKKKKKKKKK0000OOOOOkkkxxxxxdlccoxkkkkkkxxdlldxxxxkkOOO0000000Kkollccc:::::::::::;;;;;;;;;:codxkkkxddddddddddddoddddddddoodddddddddddddddddddddddddxxxxdooddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd\ndddddddddddddddddddddddddddddddddddddddddddddddxxkkkkOOOOOOOOO000000OOOOkkdlcccllccloddxxxkkkkOOO0000000KKKKKKKKKKKKKXXXXXXXXXXXXXXXXXXXXNNNNNNNNNNNNNNNNNNNNXXKKKXXXXXXXXXKKKKKKKKKKKKKKK0000OOOOkkkkxxxxdol:codxkkkkxdo:;clodddxxkkOO0000KKK0dlllcc:::;;:::::::;;;;;;;;;:cldxkOkxdddddddddddoddddddddoodddddddddddddddddddddddddxxxxdooddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd\ndddddddddddxxddddddddddddddddddddddddddddddddddxxxxkkkkOOOOOO000000OOOOOOOkdcccccccloodddxxxkkkkOOOOOO00000KKKKKKKKKKKKKKKKKKKKXXXXXXXXXXXXNNNNNNNNNNNNNNNNNNXXKKKKKKKKXKKKKKKKKKKKKKKKK0000000OOOkkkxxxxxddollodxxxxxdl:',;cclooddxxkkOO000KKKkollccc:::::;;;;::;;;;;;;,;;;cldxkOOkdddddddddddddddddddoodddddddddddddddddddddddddddxxdooddddddddddddddddddddddddddddddxxxxddddddddddddddddddddddddddddddddxxxxx\nddddddddddddddxxdddddddddddxdddddddxdddddxdooddddxxxkkkkkOOOO000000OOO000OOkocccccclooddddxxxxkkkkkkOOOOO00KKKKKXKKKKKKKKKKKKKXXXXXXXXXXXXXXXXXXNNNNNNNNNNNNXXXKKKKKKKKKKKKKKKKKKKKK000000000OOOOkkkkxxxddxdoooddxxxxdl;'',;;:cclooodxxkkOO000K0dllcccc::::::::;;;;;;;;;;;;;;:ldkO00kddddddddddddddddddoodddxxdxdddddddddddddxxxdddddxdoodxdddddddddxddddddddddddddddddddddddddddddddddddddddddddxxddxxxxxxxxxxx\ndddddddddddddxxdddddddddddddddddddxxdddddddoooodddxxxkkkkkOOOO0000000000000Oxoccc:clllooodddxxxkkkkkkkkkkkkO0KK000000KKKKKKKKKKKKXXXXXXXXXXXXXXXXXXXXXNNXXXNNXKK000KKKKKKKKKKKKKKKK00000000OOOOOkkkkxxddddddoooddddddl;'.',,;::ccllooodxxkkkOO00koccccc::::::::;;;:;;;;;;;;;;;:ldkO00Oxddddddddddddddddooddddxxddddddxxddxddxxxxxxxxdxddodxxdddddddddddddddddddxddddddddddddddddddddddddddxxxxxxxxxxxxxxxxxxxxxx\nxdddxdddxxddddddddddddddddddddxxxxxxdddddxdooooddddxxxxkkkOOOO00000000KKKK00Oxl::ccllllooooodddxxxxxxxkxxxdooooxkkOOO000000KKKKKKKKKKKKXXXXXXXXXXXXXXXXXXXXNNXXK0000000KKKKKKKKKKK00000OOOOOOOOkkkxxxdddddooooooodddl'...',;;;::cccllloodddxxkkOOdlcccc::::::;;;;:::;;;;;;;;;;;:ldkOO0Oxddddddddddddddddodxxdxxdxxxxxxxxxxxxxxxdxxxxxxddodxxddddddddddddddddddddddddddddddddddxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\nxxxxxdddxxxxxdddddddddddddddxxxddddddddddddooooodddddxxxkkOOOOO00000KKKKKKK00koc::ccllllllllooodddddxxxxxdoc::ldkOOO000000000KKKKKKKKKKKKKKKKKXXXXXXXXXXXXXXNXXXK00000000000000000000OOOOOOkkkkkkxxdddddoooooooodool,....',;;;;::cccccclllooddxxkxocccc::::::;;;;::;;;;;;;;;;;;;:lxkOOOOkdddddddddddddddoodxdxxxxxdxxxxxxxxxxxxxxxxxxxxdodxxdddddddddddddddddddddddddddddxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\nddddddxxxxxxxxxxxxdxxxxxxxxxxxxxxxxxxxxddddooooooodddxxxkkkkOOOO000KKKKKKKKK00xl:;:ccllccccclllooodddddxxxdlcldkOOO0O00OOOO000000000KKKKKKKKKKKKKKKKKKKKKKXXNNNXKK000OO00000000000000OOOOkkkkkkkxxxdddooooooooooooo:',;''',;;;;:::ccccccccllloddxxocccc::::::::;;:;::;;;;;;;;;;;;:lxkkkOOkxdddddddddddddoodxxxxxxdddxxxxxxxxxxxxxxxxxxxdooxxddddddddddddddddxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\ndddddxxxddxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxdolloooooddxxxkkkkkOOO000KKKKKKKKKK0kd:,;:ccccccccccclloooodddddddodxkkkkOOOOOOOOOOOOOO000000000KKKKKKKKKKKKKKKKXXNNNNXXK00OOOOOOOO0OO000OOOOOOkkkkkxxxxdddooooollllloool;':oc;,,;;::::::cccccccccllooddocccc:::::::::;;;;;;;;;;;;;;;;;;coxxkkkOkxddddddddddddoodxdxxxxxxxxxxxxxxxxxxxxxxxxxxxddxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\nxxdxxxxxxxxxxxddxxxxxxxxxxxxxxdxxxdxxxxxxxdollooooooddxxxkkkkOOO00KKKKKKKKKKK0Oxc,',:ccccccccccccllllooooooodddxxxxkkkkkkkkkOOOOOO00000000000KKKKKKKKKKKKXNNNNNNNXXXK00OOOOOO0OOOO0000OOOOkkkkkxxxddddooooooolooodl,':ddl:;;;::::::ccccccccllllooolcccccc::::::;;;;;;;;;;;;;;;;;;;:loodxxkkkddxdddddddddoodddxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\nxxxxxxxxxxxxxxdxxxxxxxxxxxxxxxdxxxxxxxxxxxdolllooooooddxxxkkOO0000KKKKKKKKKKK0Oxl;..';::ccccccccccccllllloooooddddxxxxxxxkkkkkOOOOO0000000000KKKKKK0KKKXXNNNNNNNNNNNNNXXKKKKKKKKKKKKKK0000OOOOOkkxxddddddooooooodddc,cddddl:;:::::cccccccccclllloolcccccc::::::::;;;;;;;::;;;;;;;;;:ccloddxkxdddddddddddddxxxxxxxxxxxxxxxxxxxxxxxdxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxdxxxxxxxxxdollloooooooddxkOOO000KKKKKKKKKKKK00Oko:,..',;::::ccccccccccccllllooooddddxxxxxxxkkkkOOOOO0000KKKKKKKKXXXXXNNNNNWNNNNNNNNNNNNNXXXXXXXXXXXXXKKKKK0000OOOkkxxxdddddodddddxko:cdxdddoc::::cccccccccccllloddllccccc::::::::;;;;;;;::;;;;;;;;;;::cllodxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxolllooodddddxkO0000KKKKKKKKKKKKKK00Oko:,...'',;;::ccccccccccccccllllooooddddxxxxxkkkOOOO000KKKKXXXXXNNNNNNNNNNNNNNNNNNNNNNNNNNNXXXXXXXXXXXXKKKKKK00000OOkkkxxxxddddxxxkOklcdxdddddlc::cccccccccccclodxdlcccccc:::::::;;:;;;;;;;;;;;;;;;;;;;;:cloodxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxdooooddxxxkkOO000KKKKKKKKKKKK00K000Okdc,...'',,;;:cccccccccccccccccllllloodddxxxkkkOO000KKKKXXXXXXXXNNNNNNNNNNNNNNNNWWNNNNNNNNXXXXXXXXXXXXXKKKKKKK00000OOOkkkkxxxxxxxkkOOdldxdddddddlccccccccccccllodxdlccccc::::;;;;;::;;;;;;;;;;;;;;;;;;;;;:ccloxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxdddddxkkOO00000K0KKKKKKKKKK0K000000Oxdc,...',,,,;;::cccccccccccccccllloooddxxkkOOOO0000KKKKKKKKXXXXXNNNNNNNNNNNNNNNNNNNNNNNNNNNXNNXXXXXXXXKKKKKKK000000OOOOkkkkkkkkkxkkkkxodxxxxxxxxxdlccllccccccllodddlcccccc::::::::::;;;;;;;;;;;;;;;::;;;;;;:codxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkkkOOO00K00KKKKKKKKKKKK00K00000OOxdc,..''',,,;;::cccccccccclllllooodxxkkOOOO000000000KKKKKKKXXXXNNNNNNNNNWWWWNNNNNNNNXXXNXXXXNNNNNXXXXKKKKKKK000000OOOOOOkkkkkxkkxxxkkddxxxxxxxxxxxxdollllcccccllooolccccccc:::::::::;;;;;;;;;;;;;;;;::;;,,;;:ldxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkkkOOOO000000KKKKKKKK000000000000Okxoc'..''',,,;;::cccccclllllooodddxkkOOO0000000000KKKKKKXXXXXXNNNNNNNWNNNWWNNNNXXXXXXXKXXXXXXXXXXXXXXXKKKKKKK0000000OOOOOOkkkxxxxxxxxxxdxxxxxxxxxxxxxxdollllcccclllolcccccccc::::::::::::;;;;;;;;;;;;;::;;;;;:cdxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkkOOOO00000000KKKKKKK0000000000000Okxo:'.''',,,;;:::ccclllooooodddxxkkOOOO000000000KKKKXXXXXXXXXXXNNNNNNNNNNNNNXXXXKKKKKKKK00KKKKKKKKKKKKKKKKKKKKK0000000OOOkkkkxxxxxxxxxxxxxxxxxxxxxxxxxxxdolllcccllllllccccccc:::::::::;;;;;;;;;;;;;;;;;::;;;;:cdxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkkOO00000000000KKKKKKKKK0000000000OOkxo:'.''',,,;;::cclllooooddddxxxkkkkOOOO0000KKKKKKXXXXXXXXXXXXXXXXXXXXXXXXXXXXKK000OOOO000000K0000KKKKKKKKKKKKKK000000OOOkkkkxxxxxxxxxkkxxxxxxxxxxxxxxxxxxdollllccllllcccccccccc:::::::;;;;;;;;;;;;;;;;:::ccloodxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkOO0000000000000000K00KK000000000OOkkxl;,'''',,;;::cclloooooddddxxxxxkkkkOOOO000KKKKKKKKXXXXXKKKKKKKKKKKKKKKKKKKKKK0000OOOOO00000KK0000000K000KKKK000000OOOOkkkkkxxxxxxxxxkkxxxxxxxxxxxxxxxxxxxxddolccclccccccccccc:::::::::;;;;;;;;;;;;;;;::clodxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkkOO000000000000000000000000000000OOOkdl;;,,,,,,;;::ccloooooodddddxxxxxxxkkOOOOO0000000KKKKKKKKKKKKKKKKKK0KKKKKKKK0000KKKK0000KKKKKKKK000000000000000000OOOOOkkkkkkxxxxxxxxkkxxxxxxxxxxxxxxxxxxxxxxxollcccccccccccc:::::::::::::;;;;;;;;;;;;::clloxkxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkkOO000000000000000000000000000000OOkxdl::;;,,,;;;::cloooooooddddddddxxxxkkkkkOOOO0000000000000000000000000KKKKKKKKKKKKXXKKKKKKKKKKKKKKKK0000000000OOOOOOOOkkkkkkkkkxxxxxxkkkxxxxxxxxxxxxxxxxxxxxxxxxdolccccccccc::::::::::::::::;;;;;;;;;;;;::ccloxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxddddoool\nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkOOO000OOOOO00000000000000000000OOOkxdlc::;;;;;;;::clooooooooddddddddddxxkkkkkOOOO0000OOOOOOOOOOOOO000000KKKKKKKXXXXXXXXXXKKKKKKKKKKKKKKKK0000000OOOOOkkkkkkkkkkkkkkxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxdocccccccc::cccc:::::::::;;;;;;;;;;;;;;;;:cloxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxddddooollllllcccc\nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxddxkkOOOOOOOOOOO0000000000000000000OOOkxdolcc::;;;;;:cllloooddddddxxxxxxxxxxxxkkkkOO0000OOOOOOkkkkkkOOO0000KKKKKKKXXXXXXXXXXXKKKKKKKKKKKKKKKKK0000000OOOOOkkOkkkkkkkkkkkkxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxolccccccccc::::::::::::;;;;;;;;;;,;;;;;;:clodxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxddddoooolllllcccccccccccccl\nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxdddxkkkOOOOOOOOOO00000000000K000000OOOkxdxdlcc::;;;;:cclloooddddxxxxkkxxxxxxxxkkkOOOOOO000OOOOOkkkOOOO0000KKKKKKKKKKXXXXXXXKKKKKKKKKKK0000000000000000OOOOOOOOOkkkkkkkkkkkkxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxdlccccccc::::::::::::;;;;;;;;;;;;;;;;;;;:coxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkxxxxxxxxxddddoooolllllllccccccccccclllllllloooo\nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxooodxxkkkOkkkkOOOOO00000000KK000000OOkxdxxxdocc:::;::ccclllooddxxxkkkkkkkkkkkkkkkkOOOOOOOOOOOOOOOOOO000000000KKKKKKKKKKKKKKKKKKK000000000000000000000OOOOOOkkkkkkkkkkkkkkkkxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxdllccccccc:::::;;;::::;;;;;;;;;;;;;;;;;cdxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkkxxxxxxxdddddoooolllllccccccccccccllllllllllooooodddooooooo\nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxooodxxkkkkkkkkkOOOOO00000000000000OOOkxdxxxxxolc::::::ccclloodddxxkkkkkkOOOOOkkkkkkkkkkkkkkkkkkkOOOO00000000000000000KKKKKKKKKK00000000000000000000OOOOOOkkkkkkkkkkxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxdollccc::::::::;;:;:;;;;;;;;;;;;;;;;cdxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxdddddooooolllllllcccccccccccllllllllooooddddddooooooooooooodddd\nkkkkkxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxooodxxkkkkkkkkkOOOOO00000000000000OOOkxdxxxxxxdlc:c:::cccclloodddxxxxkkkOOOOOkkxxxxxxxxxkxxxxxxxkkOOOOOOOOOOO000000000000000000OOkOOOOOOO00000000OOOOOkkkkkxxxxxxxxxxxdddddddxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxolccc::::::::::::::;;;;;;;;;;::;cdxxxxxxxxxxxxxxxxxxxxxxxkxxxxkxxxxxxxxxxddddooooolllllllcccccccccccllllllllloooooodddddooooooooooooooodddxxxkkkkkkkk\nxxxxxxxkkkkkkkkkkkkkkkkkkkkkxxxxxxxxxxxdoddxxkkkkkkkkkOOOOO0000000000000OOOkkxdxxxxxxxxolcc::ccllllloooodddxxxkkkOOOkkxxxddddddddddddxxxkkOOOOOOOOOOOOOOOOOOOOOO000OOkkkxxkkkkOOOOOOOOOOOOOOkkkxxxddoooodddddddoooodddxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxdolccc::::::::::::;;;;;;;;;;::cdxxxxxxxxxkxxxxxxxxxxxxxddddddooooollllllllccccccccccclccllllllllloooodddddddooooooooooooodddddxxxxkkkkkkkkkkkkkkkkkk\nllllooooooddddddddxxxxxxxxkkkkkkkkxkkkxdddxxxkkkkkkkkkOOOOOOO00000000000OOkkxdxxxxxxxxxxdocc:clllllllllooooddxxxxkkkkkxxddoooooooooddxxxkkkkkkkkkkOOOOOkkOOOOOOOOOOOkkkxxxxxxxkkkkkkOOOOOkkkkxxxdddoollooooooooollooodxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxdolc::::::::::::::;;;;;;;;:coxxxxxxxxddddoooooooollllllllcccccccccccclclllllllllllooooddddddooooooooooooooooddddxxxkkkkkkkkkkkkkkkkkkkkkkkkkkxxxdd\nllllllcccclllllllllllooooooooddddddddddddxxxkkkkkkkkkkOOOOOOOO00000000OOOkkkxdxxxxxxxxxxxxoccccllllllllllllooodddxxxxxddooolllllllooddxxxkkkkkkkkkkkkkkkkkkkkkkkOOOOOkkxxxxxxxkkkkkkkkkkkkxxxxdddoooolllllloooooooooodxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxolc:::::::::::::;;::;;;:cloooolllllllccccccccclcclcllccllllllllloooooodddddddooooooooooooooddddddxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxddooollcccc\ndddddooooooooollllllllllcccccllllllllooddxxxxkkkkkkkkkOOOOOOOOOO000000OOOOkxdxxxxkkkkkkkkkxoccclcccccllllllllllooooooooolllllcccclloddxxxxkkkkkkkkkkkkkkkkkkkkkkkOOOOOkkkkkkkkkkkkkOOkkkkkxxxdddddoooolllllloooooodddxkkxxxkkxxkkxkkkkxxxxxxxxxxxxxxxxxddddddddddoolcccc::::::::::;;;;;;:cccccccccllllllllllloooooooooodddddddddoooooooooooooodddddddxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxddddooolllccc::::::::::\nddddddddxxxxxxxdddddooooooooooooooollodddxxxxkkkkkkkkkOOOOOOOOOOOO000OOkkkxxdoodddddddddddddlcccclcclllllllllllllllllollllllccccclooddxxxxkkkkkkkkkkxkkkkkkkkOOOOOOOOOOOkkkOOOOOOOOOOOOkkkkxxxxdddooodddoooooodddddddxxxxxxxxdddddddddoooooooooooolllllllllllllllclccllcccccccccc:;;::cllooooooooooodddddddddddddooooooooodddodddddddddxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxddddoolllccc::::::::::::::::::::::\ndddddddddddddddddoooodddddddddxxddxxddddxxxxkkkkkkkkkkkOkOOOOOOOOO000OOkkkxxolcllllllllllllllcccclllllllllllooooooooooooooolllcclloodddxxxkkkkkkkkkkkkkOOOOOOOOOOOOOOOOOOOOO000000OOOOOOOOOkkkxxddooddxxxxxdddddddddollllllllllllllllllllllccccllcccllllllllllllloolooooooooooodoooooodxxxddddooooooooooodddddddddddddddxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxdddoolllcccc:::::::::::::::::::::::::::::::::\nkkkkkkkkkkkkkxxxxxdddddddddddddddddddoddxxxxkkkkkkkkkkkkkkOOOOOOOOOOOOkkxxxddoooooooooooooollllccclllllllllooooooooddddxddddoolloooddddxxxxxxxkkkkkkkOOOO00O000000000000000KKK000000000OOOOOkkkkxxddddddxxxxddddddddollllllllllooooooooooooooooooooooooodddddddddddddddddddooooooooooooddddddddddddddddxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxdddooolllccccc::::::::::::::::::::::::::::::::::::::::::::\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxdddxxxxkkkkOOOkkxxxkkkkkOOOOOOOkkkkxxddddxdddxxxxxxxxxdddolccllllllllooooooodddddddxxdddddddddddddxxxxxxxxkkkOOOO0000000000KK00KKKKKKKKKKKKKKK000000O0OOOOkkkxxddooddddddddddooddddddxxddxxxxxxxxxxddddddddoooddoooooooooodddddddddddddddddddxxxxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxdddoooolllcccc::::::::::::::::::::::::::::::::::::::::::::::::::::::::c:\nxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxdddxxxkkkOOOOOkkkxxxxxkkkkkkkkkkkkkxxddddddddddddddddddddoolccllllllloooooodddddddddddddddddddddddddxxxxxkkOO0000KKKKKKKKKKKKKKKXXKKKKKKKKKKKKK0000000OOOOkkkkxxdololloooooooloddoooooooododdddddddddddddddddddddddxdxxxxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxdddoooollllcccccc::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::ccccccc::\ncllllloooodddddxxxxxkkkkkkkkkkkkkkkkxdddxxxkkOOOOOOOkkkxxxxxkkkkkkkkxxxxdddxkkkkkkkkkkxxxxxxxxxxdllllloooooooddddddddddddddoooooododdddddxxkkOO00KKKKKKXXXXXXXXXXXXXXXXKKKKKKKKKKKKK000000OOOOOkkkkxxdolllclclllllodddddddddxxxxxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxxxdddddooollllccccccc::::::::::::::::::::::::::::::::::::::::::::::::::::::::c:::cccccccccccccccccc::cc::::\n::::::::::::ccccccccclllloooooddddxxdoddxxkOOOOO000OOOkxxxxxxkkkkkkxxxxddddkkkkkkkkkkkkkkkkkkkkkkdolloodddxxxxxxddddddddooooooooddoodddxkkOO00KKKKKKXXXXXXXXXXXXXXXXKKKKKKKXKKKKKKKKK00000OOOOOkkkxxxddoollccccclloxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxxddddoooolllllcccccccc::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::cccccccccccccccccc::::::::::ccccccccc\n::::::::::::::::::::::::::::::::::cclodxxkkOO00000000OOkxxxxxxxkkkkxxxddodxkkkkkkkkkkkkkkkkkkkkkkkxoloddxxxkkkOOkkkkkkkxxxxxxxxxxxxxxkkOO00KKKKKKKKKKKKKXXXXXXXXXXKKKKKKKKKKKKKKKKKKK00000OOOOkkkkxxddoooollccllllokkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxxxxxxddddddoooooolllllccccccc:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::ccc::ccccccccccccccccccccc::::::::cc:::cccccccccccccccc\n:::::::::::::::::::::::::::::::::::clddxkkOO000KKKKKK00OkxxxxxxkkkxxxddolllloolooooooodddddddddxxxxdoodxxkkkO000000000000000000OOkkkkOO000KKKKKKKKKKKKKKKKXXXXXXKKKKKKKKKKKKKKKKKKKKKK0000OOOOkkkxxxddoooolllllllloxxxxxxdddxdddddddddoooolllllllllllccccccccccc:::::::::::::::::c:c::::::::::::::::::::::::::::::::::::::::::::::::::::cccccccccccccccccccccccccccccccc:::::::::::cccccccccccccccccccccccccc:::\n:::::::::::::::::::::::::::::::::::clddxkO000KKKKKKKKKK0Okxxxxxxkkkxxddocc:::::::::::::::::cccccccccldxxkOOO00KKKKKKKKKXXXXXXXKK00OOOO000KKKKKKKXKKKXXXXKKKXXXXKKKKKKKKKKKKKKKKKKKKKKKKK000OOkkkxxxxxdddooollllclccccccccccc:::::cc:::::::::::::c::::::::::::::::cc::::::::::::::::::::::::::::::::::::::::::::::cc:::::::ccccc:ccccccccccccccccccccccccc::::::::ccc::ccccccccccccccccccccccccccc:::::::::::::::\nccccccccccc::::::c::::::::::::::::ccodxkO0000KKKKKKXXXKK0Okxxxxxxkkxddol:::::::::::::::::::::::::cc:ldxkOO000KKKKKKXXXXXXXXXXXXXKK00000KKKKXXXXXXXXXXXXXXXXXXXXKKKK000KKXXXXXXXXXXXXXKKKKK00Okkkxxxxxxxxxddoollllc::::::ccc::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::cc::c::::cc:ccccccccccccccccccccccccccccccccccc:::ccccccccccccccccccccccccccccccccccccc::cc::::::::::::cccccccccccc\nccccccccccccccccccccccccccccccccccccodkO00KKKKKXXXXXXXXKK0Okxxxxxkxxdolc:::::::::::::::::::::::::c::lxkOO000KKKKKKXXXXXXXXNNNNNXXXKKKKKKXXXXXXXXXXXXXXXXXXXXXKKKK00000KXXXXXNNNNXXXXXXXXKKK00OOkxxxxkkkkkkxxddoolc:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::ccccccccccccccccccccccccccccccccccccccccccc::ccccccccccccccccccccccccccccccccccccc:cc:ccc:c::::::::cccccccccllllllllllllooo\ncccccc:ccccccc::cccccccccccccccccccloxO0KKKKKXXXXXXXXXXXKKOkkkkkkkxxdoccc:::::::c::c:::::::::::ccc:lxOOO00KKKKKKKXXXXXXXXXXNNNNXXXKKKXXXXXXXXXXXXXXXXNNNNNNNXXXXK0OO0KKXXXXNNNNNNXXXXXXXXKKK00OOkkkkOOOOkkkkxxddocc:::::::::::::c::::::::::::::::c::::::::cc::cccccccccccccccccccccccccccccccccccccccc:ccccccccccccccccccccccccccccccccccccccccccccccccccccc:cc:::c::::::::ccccccccclllclllllllloooooooooooooodd\ncccccccccccccccccccccccccccccccccccldkO00KKKKXXXXXXXXXXXXK0kkkkkkkxxolccccccccccccccccccccccccccccokO0000KKKKKKKXXXXXXXXXXXXNNXXXXKKKKKKXXXXXXXXXXXXXXNNNNNNNNNXXXXXXXXXXXXXNNNNNNNXXXXXXXKKK00OOkkOOOOOOOOkkkxxoccccccccc:ccccccccccccccccccccccccccccccccccccccccccccccccccccccccc::cccccccccccccccccccccccccccccccccccccclcccccccccccccc::cc::c:::cccc::ccccccccccclllllllllllllooooooooooooooddddddddddddddd\nccccccccccclccllcccllcccccccccccccloxkO000KKKKXXXXXXXXXXXKK0OOOOOkkxocccccccccccccccccccccccccccldkO0000KKKKKKKKXXXXXXXXXXXXXXXXXKKKKKKKKKKKKXXXXXXXXXXXXXNNNXXXXK0OOOO0KXXXXXXXXXXXXXXXXKKKK000OOOO000000OOOkkkdlcccccccccccccccccccccccccccccccccccccccc:cccccccccccccccccccccccccccccccccccccccccllcccccccccccccccccccccccccccccccccccccccc::cccccccclccllllllllloooooooooooooodddddddddddddddddddddxxxxxxxxx\ncccccccccccccccccccccccccccccclcclloxkOO00KKKKXXXXNNXXXXXXXKK0000OOxlcccccccccccccccccccccccccccok0000KKKKKKKKKKXXXXXXXXXXXXXXXXXKKK0KKKKKKKKKKKKKKKXXXXXXXXXXXXXNXOddxkOKXXXXXXXXXXKXXXKKKKK000OOO0000000OOOOOOxocccccccccccccccccccccc:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclclllllllllllloooooooooooodddddddddddddddddddxxxxxxxxxxxxxxxxxxxxxxxxxxxx\nllllllllllcccccccccccccccccccccccclooxkO000KKKXXXXXXXXXXXXXXXXXXK0Odlllllcccccccccccccccccccccldk0000KKKKKKKKKXXXXXXXXXXXXXXXXXXXKKKK00KKKK0000KKKKKKKKKKXXXXXNNNNNXKKXNNNNXXXXKKKKKKKKKKKKKK000OOO0000000OOOOOOkdlcccccccclcccccccccccccccccccccccccccclccccccclllcccccccccccccccccccccccccccccccccccccccccccccccllllcclllllllllloooooooooooooooooddddddddddddddddddddxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxk\nddddddddoooooollolllllllllllllllllllloxkO00KKKKKXXXXXXXXXXXXNNXXK0OdlllllccllccllllllllllllllldO00KKKKKKKXXXXXXXXXXXXXXXXNNNNNXXXXKKKKKK000000000KKKKKKKKKKXXXXXNNNNNNNNNNXXXKKKKKKKKKKKKKKK000OOOO0000000OOOOOOOkolllllllcllllcclllccclcccccccccccccccccccccccccccccccccccccccccccccccccccccccclllllllllllllloooooooooodddooodddddddddddddddddddddxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkxxxxxkkkkkkkkkkkkkkkkk\nkkxxxxxxxxxxxxxxxxxxdddddddddddoooollldxkO000KKKXXXXXXXXXXXXXXKKKK0dllllllllllllllllllllllllldOO00KKKKKKXXXXXXXXXXXXXNXXNNNNNNNXXXXKKKKK000000000000KKKKKKKKKKXXXXXNNNXXXXXKKKKKKK0KKKKKK00000OOOOO00000000OOOOOkkdlccccccccccccccccccccccccccccccccccccccccccccclllllllllllllllllllllllloooooooooooooooddddddddddddddddddxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkkxxxkkkkkxkkkkxxkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkxkxkxxxxxxxxxxxxdollodxO0000KKKXXXXXXXXXXXXXXKKK0xoooooooollollllllllllllldkO000000KKKKXXXXXXXXNNNNNNNNNNNNNXXXXXXKKKKK00000000000000000KKKKKKXXXXXXXXXKKKKKKK0000000000000OOOOOO00K00000OOOOOkkxolllllllllllllllllllllllllllllllllllloooooooooooooooooooooddddddddddddddddddddddddxdddxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkkxxxxxkkxxkkkkkkxkkkkkkkkkxxxxkkkkxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxdooodxkOO000KKKXXXXXXXXXXXXXXKKKOxxxxxxxxddddddddddddddodxkO0000000KKKKXXXXXXXXXNNNNNNNNNNNXXXXXXXKKKKK000000000000000000KKKKKKKKKKKKKKKKK0000000000000OOOOOOOOO00KK0000OOOOOOkkdoooooooooooooooooooodddddddddddddddddddddddddddddddddxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkkxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxdoodxxkkkO000KKKXXXXXXXXXXXXXXKK0OkkkkkkkkxkkxxxxxxxxxxxxkkOOO00000000KKKKKKXXXXXXXXNNNNNNXXXXXXXKKKKKK0000000000000000000000000KKKKKK0000000OOOOOO0OOOOOOOOOOO00KKKK00000OOOOOkxxxxdddddxxxxdxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkkkkkkxxkkkkkkkkkkkkkkkkxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkddddxxxkkkOO000KKXXXXXXXXXXXXXXXKKOkkkkkkkkkkkkkkkkkkkkkkxkkkOOOOOO000000000KKKKKXXXXXXXXXXXXXXKKKKKKKKKK0000000000000000000000000KK000000000OOOOOOOOOOOOOOOOOOO00KKKKK000000OOOkkxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkx\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkdddxxkkkOOO0000KKKKKXXXXXXXXXXXXXK0kkkkkkkkkkkkkkkkkkkkkxxxkkkkkkkOOOOOOOOOO000KKKKKKKKKXXXXXKKKKKKKKKKKKKKKK00000000000000000000000000000OOOOOOOOOOOOOOOOOOOOOO0KKKKKKK000000OOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxxxxxxxxdd\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxddxkkkOOOO0000KKKKKKXXXXXXXXXXXXK0kkkkkkkkkkkkkkkkkkkkkxxxxxkkkkkkkOOOOOOOOOOO0000KKKKKKXXXKKKKKKKKKKKKKKKKK0000000000000OO00000000000000OOOOOOOOOOOOOOOOOOOOO000KKKKKK0000000OOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxxxxxxxdddooooooooooo\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxddxkkOOOO00000KKKKKXXXKKXXXXXXXXXKOkkkkkkkkkkkkkkkkkkkkxddxxxkkkkkkkkkkkkkkkkOOOO00000KKKKKKKK000000000K00000000000000000O00000000000000OOOOOOOOOOOOOOOOOOO000000KKKK000000000OOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxxxxxxxxxdddooooooooooooooooddddxxxx\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxdxxkkOOO000000KKKKKKKKXKKXXXXXXXXK0OkkkkkkkkkkkkkkkkkkkxxxxxkkkkkkkkkkkkkkkkkkkkkOOOOOO000000000000000000000000000000000000000000000000OOOOOOOOOOOOOOOOOOO000000KKKK0000000000OOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxxxxxxxxxddddoooooooooooooooooddddxxxxxxxxxxkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkdddxkkOOO0000KKKKKKKXXXXKKKKXXXXXXK0OkkkkkkkkkkkkkkkkkkkkxxkkkkkkkkkkkkkkkkkkxxxdxxxxxxkkkOOOOOOOOOOOO00000000000000OO0000000000000000OOOOOOOOOOOOOOOOOOOO00000000KKK0000000000OOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxxxxxxddddddooooooddooooooooooddddxxxxxxxxxxxxkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkdodxkkOOOOOO000KKKKXXXXXXKKKKKXXKKKK0kkkkkkkkkkkkkkkkkkkkxkkkkOOOkkkkkkkkkkkkkkxxxdddodddddxxxxkkkOOOOOO00OOOO0OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO00000000000000000000000OOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxxxxxxxxddddddddooooodddddddddddddddddddxxxxxxxxxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nxxxxxxxxkkkkkkkkkkkkkkkkkkkkkkkkkxdodxxkkOOOOO0000KKKXXXXXKKKKKKKKKKKK0OkkkkkkkkkkkkkkkkkkxxkkOOOOOOOOOOOkkkkkkkkkkkxxdoooooddxxxxxkkkkkOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO000000000000000000000000OOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxkxxxxxxxxxxxxddddddddoooodddddddddddddddddddddxxxxxxxxxxxxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nddddddddddddddddddddxxxxxxxxxxxxxxdoddxkOOOOOO0000KKKKXXXKKKKKKKKKKKKK0OkkkkkkkkkkkkkkkkkkkkOOOO000000000OOOkkxxxxxxxxddooodddxxxxxxxxkkkkkkkkkkkkkkkkkkkkkkkOOOOOOOOOOOOOkkOOOOOOOOOOOOO00000000OOOOOOO0000000000OOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxkxxxxxxxxxxxxxdddddddddddddddddddddddddddddddddddxxxxxxxxxxxxxxxkxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nxxxxxxxxxxxxxxxdddddddddddddddxdddooodxkOOOOOOO0000KKKKKKKKKKKKKKKKKKK0OkkkkkkkkkkkkkkkkkkkOOOO000000000000OOOkkxxxdddddddddddxxxkkxxxxxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOOOOOOOOO0000OOOOOOOO00000000000OOOkxkkkkkkkkkkkkkkkkkkkkkkxxxxxxxxxxxxxxxxxxxxxddddddddddddddddddddddddddddddddddddddddddxxxxxxxxxxxxxxxkxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkx\nkkkkkkkkkkkkkkkkkxxxxxxxxxxxxxxxxxdoodxkkOOO0OO000000KKKKKKKKKKKKKKKK00kdddddddddddddxxxxkOOO00000000000000000000OOkkxxxxxxxxxxddxkkxxxxxxxxxxxxxkkkkkxxkxxxxkkkkxxxkkkkkkkkkkkkkkkkkkkOOOOOOOOOOkkkkOO0000000000OOOkkxxxxxxxxdxxxxdddddddddddddddddddddddddddddddddddddddddddddddddxxxxxxxxxxxxxxxxxxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxddddoooolloo\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkdooodxkOOOOOO000000KKKKKKKKKKKKKKK000kxxxxdddddddddddxkkOOO0000000000000000KKKKKK000OOOOOkkkxxddxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkxxkkkkkkkkOOOOOOOkkkkkkOO000000000OOOkkxxdddddddddddddddddddddddddddddxxxxxxxxxxxxxxxxxxxxxxxxxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxddooooollllllloooodddxxx\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxolodxkkOOOO0000000KKKKKKKKKKKKKKK000OkkkkkkkkxkxxkxxxkkOOO0000000000000KKKKKKKKKKKKKKKK000OkxxddddxxddxxddxxxxxxddddddddxddddddxxxxxdddxxxxxxxkkkkkkkkkkkkkkkxxxkkkOOOOOOOOOOkkkkxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxdddooooooolllloooooodddxxxxkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxooodxxkkOOO0000000KKKKKKKKKKKKKK000OOkkkkkkkkkkkkkkkkkkOOO00000000000K0000KKKKKKKKKKKKKKKKK0Okxddddddddddddddddddddddddddddddddddddddddddddxxxxxkkkkkkkkkkkkkxxxkkxxxkkkkkkxxxxxxxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxddddooooooooooolooooooodddxxxxkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkdooodxxkOOO000000KKKKKXXXXKKKKKK000OkkkkkkkkkkkkkkkkkkkOOO0000000000K00000000KKKKKKKKKKKKKKK0Okddooooooooooodddddddddddddddddddddddddddddddddddxxxxxxkkkkkkkkxxxxxdoooooddxxxxxkkxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxdddddoooooooooooooooooddddxxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\ndxxxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkdoooodxkkOOO0000KKKKXXXXXXXKKKKK00OOkkkkkkkkkkkkkkxkkkkOOO000000000KKKKK0000000KKKKKKKKKKKKKK0Okdooooooodoooooddoooodddddddoooooooooooooooooddddddxxxxxxxxxxxxxxxdollllodxkkkkkxxddxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxxddddddoooooooollooooooooddddxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nddddddddddddddddddddddddxxxxxxkkkkkxoooodxxkkOOO000KKKKXXXXXXXKKKKK00OkkkkkkkkkkkkkkkxxkkOOOO000000000KKKKKK00000KKKKKKKKKKKKKKKK0Okddooooooooooooooooooooooooddoooooooooooooooooooddddddxxxxxxdddddollloodxxxxxddddddxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxddddddoooooooooooolloooooooooddddxxxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkxxxxxxxddddddddddddddddooooddxxkkOO0000KKKKXXXKKKKKKKK00OkkkkkkkkkkkkkkkxxkkOOOO0000000000KKK0000KKKKKXXKKKKK000KKKKK00kxdoooooooooooooooolooooodkOOOOOkkxoooooooooooooooodddddddddddoolllodddddddddxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxxxxxdddddddddooooooooooooooooooooooooooodddddxxxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkdoooodxxkkkOO0000KKKKKKKKKKKKKK0OxddddddddddddddddxkkkOOOO0000000000000000KKKKXXXXXXXXKKKKKKKKK00OxooooooolllllllllloodxkkxO00000kkxdoooooooooooloooooooooooooooodxkkkkkkkkkkkOOOOkxxxdddddddddddddoooooooooooooooooooooooooooooooooddddddddxxxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxoooodxxxkkkOOO000KKKKKKKKKKKKK00kkkkkkxxxxxxxxxxdxxkkOOOOO0000000000000000KKKKXXXXXXXXKKKKKKK0000kxoloollllllllllooodxO00kxdodddkkO0Okxolooooollllllllloooooooxk000000O00000000O0Oxdoooooooddddddddddddxxxxxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkdlooddxxxkkkkOO00KKKKKKKKKKKK00OkkkkkkkkkkkkkkOkxxkkkOOOOO000000000000000KKKKKKKKKKKKKXXKXXKK0000OkxolllllllllloodxkxdxkOkdlcccldkO0OOOxdoooollllllclllooooodxO000000000000KKK000OOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxoloddxxkkkkkkOO000KKKKKKKKKK00OkkkkkkkkkkkkkkkkxxkkkOOOOOOO000000000000KK00KKKKKKKKKKKKKXXXXK0OkkOkxdlccccloddxxdoodxxk0KKKkddO0KK0OkxxxddoolllllllllllloodxO0000000000KKKKKK0000Okkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkdloodxxkkkkkkOOO00KKKKKKKKKK00OkkkkkkkkkkkkkkkkkkkkkkOOOOOO000000000000000KKKKKKKKK0KKKKKXXXXK0kxkkkkxolcclodxkkkkkkkO0OkkkkxxO000kdodkkkxoollllllllllloodxO0000KKKKKKKKKKKKKK000OOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxooodxkkkkkOOOOOO000KKKKKKKK0OOkkkkkkkkkkkkkkkkkkOOkkkkOOO0000000000000000KKKKKKKKKK000KKKKKXXXKkddxkxxdlclllll::ododxxdolllllodddxddxdodooollllllllllloxkOO000KKKKKKKKKKKKKKK0000Okkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkdlllodkkkOOOOOOOO000KKKKKKK0OOkkkkkkkkkkkkkkkkkOOOOkkkOOO0000000000000000KKKKKKKKKK00KKKKKKKKXXKOxddddddoloooolloolllcccccccclllloocloodxdollllllllodxkOOO0000KKKKKKKKKKKKKKK0000Okkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkoloodkkOOO00000000KKKKKKKK0OkkkkkkkkkkkkkkkkkOOOOOkkkOOO0000000000000000000KKKKKKKKKKKKKKKKKXXXXKOdooooolclloolc:ccccc::;;;::ccccllooolollccclllodxkOOO00000KKKKKKKKKKKKKKKKK000Okkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOxloodxkO000KKKK00KKKKKKKXK0OkkkkkkkkkkkkkkkkkOOOOOkkkOOOO000000000000000000KKKKKKKKKKKKKKKKKKKXKKK0kolllccccccc:::cc:;,,,,,,,:ccclcccccclcllodxxkOOOO0000KKKKKKKKKKKKKKKKKKKK000OOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkdoodxkOO00KKKKKKKKKKKXXXK0OkkkkkkkkkkkkkkkkkkkkkkkkkkOOOO0000000000000000000KKKKKKKKKKKKKKKKKKKKKKKOdlccccccccc:::;;,;loxxo:;::ccccc::clodxkkOkkkOO000KKKXXXKKKKKKKKKKKKKKK0000OOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxx\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxoodxxkO00KKKKKKKKKKKKXXXKOkkkkkkkkkkkkkxxkkkkkkkkkkkkOOOO0000000000000000000KKKKKKKKKKKKKKKKKKKKKK00xl:ccccccccc:::ldOKXXK0xlc:cccc:cldxkkkkkkkkOO00KXXXXXXXXXXXKKKKKKKKK00000OOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxxxxxxxxxdd\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkdodkkkO00KKKKKKKKKKKKXXXK0kkkkkkkkkkkkkxxxkkkkkkkkkkkkOOOO0000000000000000000KKKKKKKKKKKKKKKKKKKKKKK0kl::ccccccccclokOKXXXXXOocccccloddxxxddddkO0KKXXXXNNXXXXXXXXXXXXXKKKK0000OOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxxxxxxxxxxxddddddddddooooo\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxodkkkO00KKKKKKKKKKKKKXXXKOkkkkkkkkkkkxddxxxxkxxxxxkkkkOOOOOO00000O000000000000KKKKKKKKK00KKKKKKKKKKK0ko:;:c::clldooxO0KXXXKKkllccloodooooodkOKXXXNXXXNNNNNNXXNXXXXXXXXKKKK000OOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxxxxxxxxxxxxdddddddddddddoooollllllllllooll\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkdoxkkOO000KKKKKXXXKKKKXXX0OkkkkkkkkkkxdddxxxxxxxxxxxkkkOOOOOOOOOOOO000OOO00000KK00KKKKKK00KKKKKKKKKKK0Oo;,;:::ldOxldkO0XXXKKOxolllooolodxOKKKXXXNNNNNNNNNNNNNNNXXXXXXXKKKK0000OOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxxxxxxxxxxxxxxxddddddddddoodoooolllllllllllloollloooooodddddd\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkdoxkOOO00OO0KKKKKKKKK0KKXX0OkkkkkkkkkdoodddxxxxxxxxxkkkOOOOOOOOOOO00OOOOO0000000000KKKK0000K000KKKKKK00Oo;',;:okKOllxO0KKXXK00kllolloxO0KKKKXXXXXXNNNNNNNNNNNNNNNXXXXXXKKKK000OOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkddddddddddddddddddooooolllllllllllllloooooooooddddddddddddoooooooolo\nxxxxxxxxxxxxxxxxxxkkkkkkkkkkkOOkkkkkkkOOkkkxddkkkOOOOOOOO0000000000KKKOkkkkkkkkkdooodddddddddxxxkkkkOOOOOOOOO0OOOOO000000000000KKK000000000KKKKK000ko,..:x0XKdlodxk0KK0OO0klloxO0KKKKKXXXXXXXNNNNNNNNNNNNNNNXXXXXXXKKKK00OOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxxxxxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkxoooolllllllllloooolooooooooodddddddddddooooooooooooooooooooddddxx\nddddddddddddddddxdxxxxxxxxxxxxxxxxxxxxxxxxxxxdddxxkkkxxxxkkkOOOOkkOO0K0OOOkkkkOkdlooooddddddddxxxkkkkOOOOOOOOOOOOOO000000000O00000000000K000000K000Oko,'d0KKKKkolloxxxkxOXKxxO000KKKKKXXXXXXXNNNNNNNNNNNNNNNXXXXXXXKKKK00OOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxxxxxxxxxxxxxxxxxxxxxxxxddddddddddxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxkkdoooloooooddddddddddooooooooooooooooooooooodddddxxxkkkkkkkkkkkkkk\nlllllllllllllllloooooooodddddddddddddddddddxxxdoooddddddddddxxkOOOOkO00OkxxxxxxxolloooddddddddxxxxkkkkkkkkOOOOOOOOO0000000O0000000000000000000000000OkooO00KKX0o;::ccccoOXX0000KKKKKKKXXXXXNNNNNNNXXXNNNNNNNNXXXXXXKKKKK00Okkkxxkxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxddddddddddddddddddddddddddoooooolllllllldkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkkxxdoooooooooooooooooooodddddxxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nxxdddddddddoooooooooolooolllllllllllllllllloodoollooooddddodddxxkkOOkO00OxddddddollllooodddddddddxxkkkkkkkkkOOOOOOOOOO000O000000000000000000000000000OkkkkkOO0Odc,'''';dOKK000KKKKKKXXXXXXXNNNNNNXXXXXXNNNNNNXXXXXXKKKKKK0Okxxxxdddddddddddddddddddddddddddddddddoooooooollllllllllllllllllllllllloolloooooddxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkkxxdooodddddxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\noooooooodooodddddddddxxxxxxxxxxxxddddddoooolccccccllooodddddxxxxxxkkkkO0KOxdollllllllooodddddddddxxxxkkkkkkkkkkOOOOOOOOOOOOOOO00000000000000000000000Oxxddodddddo:;,,:lxkOOOO0KKKXXXXXXXXXXXNNNNNXXXXXXXXXXNNXXXXXXXXXKKK00koooooooollllllllllllllllllllllllllllollloooolloooooooooodddddddddddddddddddddxkkxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nxxxxxxxxddddddddddoodddddooooooooooooooooool:::::cccllloddddxxkkkkkkOOOO0KXKK0kxollllooodddddxddxxxxxxkkkkkkkkkkOOOOOOOOOOOOOO0000000000000000000000Oxooolcccclll:;;;clooddddk0KKXXXXXXXXXXXXNNNNXXXXXXXXXXXNXXXXXXXXXXKKK0Odoooooooooooooooddoddddddddddddxxddddddddddddoooooooooooooooooddddddddddddddddxkxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkkxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkxxxxxxxdddddddddddoc::::::::cclooooodxkkOOO00O00KKKXXK0xollloooddxxxxxxxxxxxkkkxkkkkkkkOOOOOOOOOOOOOO00000000000OOOO00000OOxccllc:ccccc:::::ccccllok0KKKXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXKKK0Oxdddddddddoodoooooooooooddoodddddoooodddoddddddddddddddxxxxxxkkkkkkkkkkkkkkkxkkxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkkxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkoc::;;;;;:::cllcccodxkkOO00000KKKKKXK0xoloooddxxxxxxxxxxxkkkkkkkkkkkkkkOOOOOOOOOOOO0000000000OOOOOOOOOOOxc,;c:::cccc:::::::ccclokO0KKKKKXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXKKK0kdxdddddddddddddxxdxxxxxxxxxkkkkkkkkkkkkkkkkkOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkkxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxc::;;:;;;:::clllcclodxkOOOO000KKKKKKKKOdoooddxxxxxkkkkkkkkkkkkkkkkkkkkkkkkkOOkOOOOO000000000OOOOOOOOOOkxl,',:::::::::::::ccccloxO0KKKKKKXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXKKKK0OOOOOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkkxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkl:::;;;;;::::ccloollodxxkkOO000KKKKKKKKKkdoddxxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOOOOOO00000000OOOkkkOOkkkxo:'.....''',;:::ccc::cdxO0KKKKKKKXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXKKKK0Okkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxkkkkxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkdc::;;;;;;;;:::ccllcclodxxkOO0000000K00KK0kdddxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOOOOOO000000000OOkkkkkkkkxoc;.     ...',,;,;,,:oxkO0000KKKKKKKXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXKKKKKOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxkkkkxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkdc::;;;;;;;;;;:::ccclllodxxxkOOOOO0000000KK0xdxxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOOOOOO000000000OOOOkkkkkkxoc;'     ...'''',,,:odxkOO0000KKKKKKKKXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXKKXKKKOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkdc::;;;;;;;;;;::::::cllooddxxxkkOOO000OO00KKKOxxxkkxkkkkkkkkkkkkkkkkkkkkkkkkkkOOOOOOO000000000OOOkkkkkxdol:,.   ..'',,,,;;:ldxkkOO000KKKKKKKKKKKKXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXKKK0OkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkdcc::;;;;;;;;;;:::::::looodddddxkOOO0OO0OO00O0OxxxxxkkkkkkkkkkxxkkkkkkkkkkkkkkkkkOOOOOOOO000000OOkkkkxxdol:,.   ..',,,;;;:lddxxkOO0000KKKKKKKKKKKKXXXKXXXXXXXXXXXXXXXXXXXXXXXXXKKKK0OkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxlc::;;;;;;;;;;;:::::::cloooooodxkOOOO0OkkkkkOOkxxxxkkkkkkkkkkxxxkkkxxxkkkkkkkkkkkOOOOOOOOO000OOOkkkxxddolc;.   ..',,;:::lodxxxkOOO00000000KKKKKKKKKKKKKKKKKKKKKKKXXXXXXXXXXXXXXXXXK0Okkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxoc::;;;;;;;;;;;:::::::::llooolloxxkkOOdloxxkO0OkxxkkkkkkkkkkxxxxxxxxxxxxxxxkkkkkkOOOOOOOOOO00OOOkxxxxddolc:'  ..'',;;::clodxxxkkOOO0000000KKKKKKKKKKKKKKKKKKKKKKKKXXXXXXXXXXXXXXXXKK0OkkkkkkkkkkkOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkdl:::;;;;;;;;;;;;::::::;:clddddooddxOOdcldxxkO0OkkkkkkkkkkkkxxxxxxxxxxxxxxxxkkkkkOOkkOOOOOOO00OOkxxxdddolc:'   .'',;;:cloddxxxkkOOOO0000000K00KKK00KKKKKKKKKKKKKKKXXXXXXXXXXXXXXXXKKK0OkkkkkkkkkkkkkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkoc::;;;;;;;;;;;;;;::cccccloddoooddxkOkolodxkO00OkkkkOkkkkkkxxxxxxxxxxxxxxxxxxkkkkkkkkOOOOOO0OOOkkxddddolc:,. ..',;;:cllodddxxkkkOOOO0000000000000000KKKKKKKKKKKKKXXXXXXXXXXXXXXXXXXKK0OkkkkkkkkkkkkOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxoc::;;;;;;;;;;;;:c::ccc::::cllodxkOO0kocodxkO00OkkkkkkkkxxxxxxxxxxxxxxxxxxxkkkkkkkkkOOOOOOOOOOOkxxddoolc:,.  .',;;:cllodddxxxkkkOOOO000000000000000KKKKKKKKKKKKXXXXXXXXXXXXXXXXXXXXK0OOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxl:::;;;;;;;;;;;;::;;;;;;;::ldkkkkOKKKOocldxkO00OkkkkkkxxxxxxxxxxxxxxxxxxxxkkkkkkkkOOOOOOOOOOOOkxxddoolc:,.  .',;:ccllloddddxxkkkOOOOO00000000000000KKKKKKKKKKKKKKXXXXXXXXXXXXXXXXXKK0OkkkkkkkOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkdc:::;;;;;;;;;;;::::::::::::ldkOOOO000OocdkkO000OkxxxxxxxxxxxxxxxxxxxxxxxxxxxkkkkOOOOOOOOOOOOOkxxddoolc:,.  ..,;:cclllodddxxxxxkOOOOOOO000000000000KKKKKKKKKKKKKKKKXXXXXXXXXXXXXXXKKK0OOOkkkkOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkkkkkkkkkkOko:::;;;;;;;;;;;:cccccc::::::coxxxxkkO0xcokkxxkkkkxxxxxxxxddxxxdxxxxxxxkkxxxxxkkkkOOOOOOOOOOOkkxxddoolc:,.  ..';::cllloodddxxxxkkkOOOOOOOOOO00000000KKKKKKKKKKKKKKKKXXXXXXXXXXXXXXKKK0OOOOkkkOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkdc::::::;;;;;;;;:lloolc:;::;;:loxxxkkOkccoxxolodxxxdddddddxxxxxxxxxxxxxkkkkkkkkkkkkkOOOOOOOOkkxxdoooll:;.  ..';::clllloodddxxxxkkkkkOOOOOOOOO0000000000KKKKKKKKKKKKKXXXXXXXXXXXXXXKKK0OOkkkkkOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkdc::::::;;;;;;;;:cccclc;;;;;;;:ldxxkOOkl:loxxxxxxxxdddddddxxxxddddxxxxxxkkkkkkkkkkkkkkkOOkkkkkxxdoollc:;.  ..,;::ccllloooddddxxxxkkkkkkOOOOOOO0000000000KKKKKKKKKKKKKKKXXXXXXXXXXXXKK00OkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkxxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkdc::::::;;;;;;;;;:::::;;;,,,;:coxkOO0Oo;:lodxddxxxddddddddxxdddddxxxxxxxkkkkkkkkkkkkkkkkkkkkxxddoollc:;.  ..';::cccllloodddddxxxxxkkkkkOOOOOO0000000000000000KKKKKKKKKKKKXXXXXXXXXKKK0OOOOkOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkxkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxdolc::::;;;;;;;;;;;;;;,'..,;:oxOO00KOl;:codxkOOxdxdddddddddddddxxxxxxxkkkkkkkkkkkkkkkkkkkkxxddoollc:;'....',::cccllllooodddddxxxxxkkkkkkkOOOOO0000000000000KKKKKKKKKKKKKKKKXXXXXKKK00OOOkOOkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxkkkkkkkOOkkkkkkkkkkkkkkkkOOkkkxkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxoc:::;;;;;;;;;:::;;'..';cldkOO00Kx:;ccoxkOOkxdddddddddddddddxxxxxxxxxkkkkkkkkkkkkkkxxxxxddoolcc::;'...',;:ccclllllooodddddxxxxxxxxxkkkOOOOO0000000000000KKKKKKKKKKKKXXKKXKKKKKKK0OOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkxxkkkkkkkkkkkkkkkkkkkkkkkOOOkkkkkkkkOkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkxdolc:::;;;:::ccc:,...,:codxOO000l,;:codxxdolodddddddddddddddxxxxxxxxkxxxxxkkkkkkkxxxxxddollcc:coc''',,;::cclllllooooodddddxxxxxxxxkkkkOOO00OOOOO0000000KKKKKKKKKKXXXKKXKKKKKKK00OOOOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkxkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkOkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxl:::;;::::cc:,....;:cldkkO00x;',,;:c:;:clooooooddddddddddxxxxxxxxxxxkkkkkkkkxxxxxxdoollcc:cxkl,,,,;:::ccccllllooooddddddxxxxxxxkkkkOOOOOOOOO00000000KKKKKKKKKXXKKXXXKKKKK000OOOkOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkxkkkkkkkkOOkkkkkkkkkkkkkkkkkkkkxkkkOkkkkOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxl:::;:::::c:;,'..';:clodkOOOd:;'....';clooooooddddddddddxxxxxxxxxxxkkkkkkkxxxxxxxddoolcc:lkOxl;,;;:::ccccllllllooooddddddxxxxxkkkkOOOOOOO00000000000KKKKKKKKKKKKKKKKKKKKK000OOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxxkkkkkkkkkkkkkkkkkkkkkkkOOOkkkkkkkkOkkkkOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOxoc::::::::::;,..',;:clldxkkOOOkdl,',:clooooooooodddddddxxxxxxxxxxxxkkkkxxxxxxxxxddoolc::dOkkxc;;;:::cccccllllloooooodddddxxxxxkkkkOOOOOOOOO000000000KKKKKKKKKKKKKKKKKKKK000OOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkxkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkdl:::::;:::;,''.,;;:codxkkxkOO00x:,:cllloooooooooooddddxxxxxxxxxxxkkkxxxxxxxxxdddolcc;cxOkkkxc;;::::cccccclllllloooodddddxxxxxkkkkOOOOOOOOO00000000000KKKKKKKKKKKKKKKKKK000OOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOOkkkOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkocc::::::;;;,,;:::clooodooodddl;,;:cllloooooooooddddddddddxxxxxxxkkxxxxxxxxxxddooc::okkkkkkxl::::ccccccccccllllooooodddddxxxkkkOOOOOOOOOO0000000000KKKKKKKKKKKKKKKKKKKK000OkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOOkkkkkxkkkkkOkkkkkkkOkkkkkkkkkkOOOkkkkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkOOOkkkkkkkkkkkkkkkOOOkkkkkOkkkkkkkkkkkkkkkkkkkOkkxxdl::::;;;,;cc:;;;::::::::;;,,;::cclllooooooooodddddddddxxxxxxxxxxxxxxxxxxxddoc:cxkkkkkkkxl:::ccccccccccclllloooooddddxxxxkkOOOkkkOOOO00000000000KKKKKKKKKKKKKKKKKKKK00OOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkkkkkkkkkkOkkkkkxkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkOkkkkkOkkkkkkkOOkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxl:::::;;;:c::;;;;;;;,'.'',;;::ccllllloollooooooooodddddxxxxxxxxxxxxxxxxxxdoc:okkkkkkkkOxl:ccccccccccccllllllloooooddxxxkkOOOkkOOOOOOOO00000000KKKKKKKKKKKKKKKKKKK000OOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkxkkkOOkkkkkkkkkkkkkkkkkkkOkkkkkkkkkOOkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkOkkkkkOOOOkkkkOkkkkkkkkkkOOOkkkkOOOkkkkkkkkkkkkkkkkkkkkkkkkkdl::::::::::;;,,,,,,'...',;;;:ccclllllllllooooooooodddddddxxxxxxxxxxxxkxxdoccdOkkkkkkkkkxlcccccccccccccllllllooooodddxxkkkOOOOOOOOOOOO00000000000KKKKKKKKKKKKKKK0000OOOOkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkxkkkOOkkkkkOkkkkkkkkkkkkkkOOkkkkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkOOOOOkkkOOOOkkkkOOOOkkkOOOkkOOkkkkkOOkkkkkkkkOOkkkkOkkkkkkkkkOOOkkkkOkkkxdoc:::::::::;;;;;;,,,,;;;;::ccllllllllllllooooooodddddddddxxxddxxxkkkxxoclkOkkkkkkkkkOkoccccccccccccclllllllloodddxxkkkOOOOOOOO0OO0000000000000KKKKKKKKKKKKKK00000OOOkkkkkkkkkkkkkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkxkkkkkkkkkkOkkkkkkkkkOOkkkkkkkkkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nOkkkkkOOOkkkkOOkkkkkkkOOkkkOOOOOkkkkkkkkOkkkkkkOOOOOOOOOOOOOOkkkOkkOOkkkkkkkkkOkkxdolc:::cllllc::;;;::;;:::cccccllllllllooooooooddddddddxxxxxxxxkkkkxocdkkkkkkkOkkOkkkdcccccc::ccccccllllllooooddxxkkkOOOOOOO0000000000000000KKKKKKKKKKKKKK00000OOOkkOOOOOkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkOOOkkkkkkkkkkkkkkkkkkkOOOOOOOOkkkkkkOOOOOkkkkkkOOOOkkkkkOOOOkkkkOOkkkkkkkkkkkkkkkxxxxkkkkxoc:::::::;:::ccccccllllllllooooooooooddddddddxxxxkkkkkkdlxOkkkkkkkkkOkkkkxlcccccc:ccccccclllllooooddxxkkkkOOOOO00000000000000000KKKKKKKKKKKK0000000OOkOOkkkkkkkOOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkxkkkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkOkkkkkkkkkkkkkkkkkkkkOOOOOOkkkOOOOOOOkkkkOOOOkkkkkkkOkkkkkOOOkkkkkOOOkkkkkkkOkkOkkkkdlc::c:::;:::::cccclllllllllllllloooooodddddddxxxkkkkkkdoxOkkkkkkkkkkkkkOkxocccccccccccccclllloooooddxxkkkkkOOO0000000000000000KKK00KKKKKKKKK000000OOOOOkkkOkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkxkkkkkkkOOkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkOOOkkkkkkkkkkkkkkkkkkkkkkOOkkkkkkkkOOOOOOkkkOOOkkkkkkkkkkOkkkOkkkkkkkkkkkkkkkOkkkOkkkkkxlccc:::::::::cccccclllllllllllllllloooooodddddxxkkkkkkxdkkkkkkkkkkkkkOOOkkkdlccccccccccccccllllloooddxxkkkkkOOOO00000000000KKKKK0KKKKKKKKKKK0000000OOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOOkkkkkxkkkkkkkOOkkkkkkkkkkkOOOkkkkkkkkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkOkkkkkkkkkkkkkkkkkkkkOOOkkkkkkkkkkkkkkkkkkkkkOOkkkkkkkkkkkkkkkkkkkkkkkkkkdccc:::::::::cccccccclllclllllllllllooooodddddxxxkkkkkxxkkkkkkkkkkkkkkkOkkkkxoccccccccccccccllllloooddxxkkkkOOOOOO00000000K0000K0KKKKKKKK0000000000OOkkkkkkkkkkkkkkkkkkkkkkkkkOOOkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkxkkkkkkkOkkkkOkkkkkkkkkkkkkkkkkkkkkkOkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOOOkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxocc::::::::::ccccccccccccllllllllllllooooooddxxxkkkkkkkkkkkkkkkkkkkkkkOkkkkkxolclcccccccccccllllloooddxxxkkkkkOOO0000000000KKKKKKKKKKK000000000000OOOkkkkkkkkkkkkkkkkkkkkkkOOOOOkkkkkkkkkkOOkkkkkkkkkkkkkkkkkkxkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkOkkkkkkkkkkkkkkkkkkkOOOkkkOOkkkkkkkkkkkkkkkkOkkkkkkOOkkkkkkkkkkkkkkkkkkkkkkkdlcc::::::::::cccccccccccccccclllllllllooooddxxxkkkkkxxkkkkkkkkkkkkkkkOkkkkkxkxocccccccccccccllllllooddxxxkkkkkOO000000000KKKKKKKKKK000000000000000OOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkkkkOOkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkOOkkkOkkkkkkkkkkkkkkkkkkkkkkkkkOkkOOOkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOOOkkkkkkkkkkkkkkkkkkkkkkkoccc:::::::::cc::ccccccccccccccccllllllloooddxxxxxkkxxkkkOkkkkkkkkOkkOkkkkkxkkxdllccccccc:ccclllllloodddxxkkkkOOO00000000KKKKKKKKK0000000000000000OOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkkkkkkkkkkkkkkkkkkkOkkkkkkkkkkkkOkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkkkOOkkkkkOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkOkkkkkkkkkkkkkkkkkkkkkkkkdcccc::::::::ccc:cccccccccccccccccclllllloodddxxxxkkxxxkkkOOkkkOkOOOOOkkkkkxkkkkxolccccccccccccclllloodddxxkkkOOOO000000000KKKKK000000000000000000OOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkxkkkkOkkOOkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkkkkkkkkOOOOOOOOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkkkOkkOkkkkkkkkkkkkkkkkkkkkOkocccc::::::::::::::::::::ccccccccccclllloooddxxxxkkxxxkkkkkkkkkkkkOOOkxkkkxkkxkOkxolcccccccccccclllooodddxxkkkOOOO00000000KKKKKKKK00000000000000OOOOkkkkkkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkOkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkkkOOkkkkkkkOOOOOOOkkkkkkkkkkkkkkkkkOOkkkkkkkkkkkOOOkkkkkkkkOOkkkkkkkkkkkkkkkkkkkkkkkkxlcccc::::::::::::::::::::::::c::ccccllloooddddxxxxxxxkkkkkkkkkkkkkkOkkkkkxkkkkkOOkdlcccccccccccclllooooddxxkkOOOO00000000KKKKKKKK00000000000000OOOkkOkkkkkkkOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOkkkkOOOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\nkkkkkkkkkkkkkOOOkkkkkkkOOOOOOOOOOkkkkkkkkkkkkkkkkkOOOOOkkkkOOOOOkkkOkkkOkkkkkkkkkkkkkkkkkkkkkkkkkOkoccccc::::::::::::::::::::::::::ccccllllooddddxxxxxdxxkkkkkkkkkkkkOOkkkkkxkkkkkOOOOxllcccccccccccllloooddxxkkOOOO0000000000000KKK00000000OOOOOOOOkkkOkkkkkkkOOOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkOOkkkkkkxkkkkkkkkkkOkkkkkOkkkkkkkkkkkkkkkkkkOkkkkOkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\n*/\n"
  },
  {
    "path": "errors.generated.go",
    "content": "package core\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "features/dns/client.go",
    "content": "package dns\n\nimport (\n\t\"v2ray.com/core/common/errors\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/serial\"\n\t\"v2ray.com/core/features\"\n)\n\n// Client is a V2Ray feature for querying DNS information.\n//\n// v2ray:api:stable\ntype Client interface {\n\tfeatures.Feature\n\n\t// LookupIP returns IP address for the given domain. IPs may contain IPv4 and/or IPv6 addresses.\n\tLookupIP(domain string) ([]net.IP, error)\n}\n\n// IPv4Lookup is an optional feature for querying IPv4 addresses only.\n//\n// v2ray:api:beta\ntype IPv4Lookup interface {\n\tLookupIPv4(domain string) ([]net.IP, error)\n}\n\n// IPv6Lookup is an optional feature for querying IPv6 addresses only.\n//\n// v2ray:api:beta\ntype IPv6Lookup interface {\n\tLookupIPv6(domain string) ([]net.IP, error)\n}\n\n// ClientType returns the type of Client interface. Can be used for implementing common.HasType.\n//\n// v2ray:api:beta\nfunc ClientType() interface{} {\n\treturn (*Client)(nil)\n}\n\n// ErrEmptyResponse indicates that DNS query succeeded but no answer was returned.\nvar ErrEmptyResponse = errors.New(\"empty response\")\n\ntype RCodeError uint16\n\nfunc (e RCodeError) Error() string {\n\treturn serial.Concat(\"rcode: \", uint16(e))\n}\n\nfunc RCodeFromError(err error) uint16 {\n\tif err == nil {\n\t\treturn 0\n\t}\n\tcause := errors.Cause(err)\n\tif r, ok := cause.(RCodeError); ok {\n\t\treturn uint16(r)\n\t}\n\treturn 0\n}\n"
  },
  {
    "path": "features/dns/localdns/client.go",
    "content": "package localdns\n\nimport (\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/features/dns\"\n)\n\n// Client is an implementation of dns.Client, which queries localhost for DNS.\ntype Client struct{}\n\n// Type implements common.HasType.\nfunc (*Client) Type() interface{} {\n\treturn dns.ClientType()\n}\n\n// Start implements common.Runnable.\nfunc (*Client) Start() error { return nil }\n\n// Close implements common.Closable.\nfunc (*Client) Close() error { return nil }\n\n// LookupIP implements Client.\nfunc (*Client) LookupIP(host string) ([]net.IP, error) {\n\tips, err := net.LookupIP(host)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tparsedIPs := make([]net.IP, 0, len(ips))\n\tfor _, ip := range ips {\n\t\tparsed := net.IPAddress(ip)\n\t\tif parsed != nil {\n\t\t\tparsedIPs = append(parsedIPs, parsed.IP())\n\t\t}\n\t}\n\tif len(parsedIPs) == 0 {\n\t\treturn nil, dns.ErrEmptyResponse\n\t}\n\treturn parsedIPs, nil\n}\n\n// LookupIPv4 implements IPv4Lookup.\nfunc (c *Client) LookupIPv4(host string) ([]net.IP, error) {\n\tips, err := c.LookupIP(host)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tipv4 := make([]net.IP, 0, len(ips))\n\tfor _, ip := range ips {\n\t\tif len(ip) == net.IPv4len {\n\t\t\tipv4 = append(ipv4, ip)\n\t\t}\n\t}\n\tif len(ipv4) == 0 {\n\t\treturn nil, dns.ErrEmptyResponse\n\t}\n\treturn ipv4, nil\n}\n\n// LookupIPv6 implements IPv6Lookup.\nfunc (c *Client) LookupIPv6(host string) ([]net.IP, error) {\n\tips, err := c.LookupIP(host)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tipv6 := make([]net.IP, 0, len(ips))\n\tfor _, ip := range ips {\n\t\tif len(ip) == net.IPv6len {\n\t\t\tipv6 = append(ipv6, ip)\n\t\t}\n\t}\n\tif len(ipv6) == 0 {\n\t\treturn nil, dns.ErrEmptyResponse\n\t}\n\treturn ipv6, nil\n}\n\n// New create a new dns.Client that queries localhost for DNS.\nfunc New() *Client {\n\treturn &Client{}\n}\n"
  },
  {
    "path": "features/errors.generated.go",
    "content": "package features\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "features/feature.go",
    "content": "package features\n\nimport \"v2ray.com/core/common\"\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n\n// Feature is the interface for V2Ray features. All features must implement this interface.\n// All existing features have an implementation in app directory. These features can be replaced by third-party ones.\ntype Feature interface {\n\tcommon.HasType\n\tcommon.Runnable\n}\n\n// PrintDeprecatedFeatureWarning prints a warning for deprecated feature.\nfunc PrintDeprecatedFeatureWarning(feature string) {\n\tnewError(\"You are using a deprecated feature: \" + feature + \". Please update your config file with latest configuration format, or update your client software.\").WriteToLog()\n}\n"
  },
  {
    "path": "features/inbound/inbound.go",
    "content": "package inbound\n\nimport (\n\t\"context\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/features\"\n)\n\n// Handler is the interface for handlers that process inbound connections.\n//\n// v2ray:api:stable\ntype Handler interface {\n\tcommon.Runnable\n\t// The tag of this handler.\n\tTag() string\n\n\t// Deprecated. Do not use in new code.\n\tGetRandomInboundProxy() (interface{}, net.Port, int)\n}\n\n// Manager is a feature that manages InboundHandlers.\n//\n// v2ray:api:stable\ntype Manager interface {\n\tfeatures.Feature\n\t// GetHandlers returns an InboundHandler for the given tag.\n\tGetHandler(ctx context.Context, tag string) (Handler, error)\n\t// AddHandler adds the given handler into this Manager.\n\tAddHandler(ctx context.Context, handler Handler) error\n\n\t// RemoveHandler removes a handler from Manager.\n\tRemoveHandler(ctx context.Context, tag string) error\n}\n\n// ManagerType returns the type of Manager interface. Can be used for implementing common.HasType.\n//\n// v2ray:api:stable\nfunc ManagerType() interface{} {\n\treturn (*Manager)(nil)\n}\n"
  },
  {
    "path": "features/outbound/outbound.go",
    "content": "package outbound\n\nimport (\n\t\"context\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/features\"\n\t\"v2ray.com/core/transport\"\n)\n\n// Handler is the interface for handlers that process outbound connections.\n//\n// v2ray:api:stable\ntype Handler interface {\n\tcommon.Runnable\n\tTag() string\n\tDispatch(ctx context.Context, link *transport.Link)\n}\n\ntype HandlerSelector interface {\n\tSelect([]string) []string\n}\n\n// Manager is a feature that manages outbound.Handlers.\n//\n// v2ray:api:stable\ntype Manager interface {\n\tfeatures.Feature\n\t// GetHandler returns an outbound.Handler for the given tag.\n\tGetHandler(tag string) Handler\n\t// GetDefaultHandler returns the default outbound.Handler. It is usually the first outbound.Handler specified in the configuration.\n\tGetDefaultHandler() Handler\n\t// AddHandler adds a handler into this outbound.Manager.\n\tAddHandler(ctx context.Context, handler Handler) error\n\n\t// RemoveHandler removes a handler from outbound.Manager.\n\tRemoveHandler(ctx context.Context, tag string) error\n}\n\n// ManagerType returns the type of Manager interface. Can be used to implement common.HasType.\n//\n// v2ray:api:stable\nfunc ManagerType() interface{} {\n\treturn (*Manager)(nil)\n}\n"
  },
  {
    "path": "features/policy/default.go",
    "content": "package policy\n\nimport (\n\t\"time\"\n)\n\n// DefaultManager is the implementation of the Manager.\ntype DefaultManager struct{}\n\n// Type implements common.HasType.\nfunc (DefaultManager) Type() interface{} {\n\treturn ManagerType()\n}\n\n// ForLevel implements Manager.\nfunc (DefaultManager) ForLevel(level uint32) Session {\n\tp := SessionDefault()\n\tif level == 1 {\n\t\tp.Timeouts.ConnectionIdle = time.Second * 600\n\t}\n\treturn p\n}\n\n// ForSystem implements Manager.\nfunc (DefaultManager) ForSystem() System {\n\treturn System{}\n}\n\n// Start implements common.Runnable.\nfunc (DefaultManager) Start() error {\n\treturn nil\n}\n\n// Close implements common.Closable.\nfunc (DefaultManager) Close() error {\n\treturn nil\n}\n"
  },
  {
    "path": "features/policy/policy.go",
    "content": "package policy\n\nimport (\n\t\"context\"\n\t\"runtime\"\n\t\"time\"\n\n\t\"v2ray.com/core/common/platform\"\n\t\"v2ray.com/core/features\"\n)\n\n// Timeout contains limits for connection timeout.\ntype Timeout struct {\n\t// Timeout for handshake phase in a connection.\n\tHandshake time.Duration\n\t// Timeout for connection being idle, i.e., there is no egress or ingress traffic in this connection.\n\tConnectionIdle time.Duration\n\t// Timeout for an uplink only connection, i.e., the downlink of the connection has been closed.\n\tUplinkOnly time.Duration\n\t// Timeout for an downlink only connection, i.e., the uplink of the connection has been closed.\n\tDownlinkOnly time.Duration\n}\n\n// Stats contains settings for stats counters.\ntype Stats struct {\n\t// Whether or not to enable stat counter for user uplink traffic.\n\tUserUplink bool\n\t// Whether or not to enable stat counter for user downlink traffic.\n\tUserDownlink bool\n}\n\n// Buffer contains settings for internal buffer.\ntype Buffer struct {\n\t// Size of buffer per connection, in bytes. -1 for unlimited buffer.\n\tPerConnection int32\n}\n\n// SystemStats contains stat policy settings on system level.\ntype SystemStats struct {\n\t// Whether or not to enable stat counter for uplink traffic in inbound handlers.\n\tInboundUplink bool\n\t// Whether or not to enable stat counter for downlink traffic in inbound handlers.\n\tInboundDownlink bool\n\t// Whether or not to enable stat counter for uplink traffic in outbound handlers.\n\tOutboundUplink bool\n\t// Whether or not to enable stat counter for downlink traffic in outbound handlers.\n\tOutboundDownlink bool\n}\n\n// System contains policy settings at system level.\ntype System struct {\n\tStats  SystemStats\n\tBuffer Buffer\n}\n\n// Session is session based settings for controlling V2Ray requests. It contains various settings (or limits) that may differ for different users in the context.\ntype Session struct {\n\tTimeouts Timeout // Timeout settings\n\tStats    Stats\n\tBuffer   Buffer\n}\n\n// Manager is a feature that provides Policy for the given user by its id or level.\n//\n// v2ray:api:stable\ntype Manager interface {\n\tfeatures.Feature\n\n\t// ForLevel returns the Session policy for the given user level.\n\tForLevel(level uint32) Session\n\n\t// ForSystem returns the System policy for V2Ray system.\n\tForSystem() System\n}\n\n// ManagerType returns the type of Manager interface. Can be used to implement common.HasType.\n//\n// v2ray:api:stable\nfunc ManagerType() interface{} {\n\treturn (*Manager)(nil)\n}\n\nvar defaultBufferSize int32\n\nfunc init() {\n\tconst key = \"v2ray.ray.buffer.size\"\n\tconst defaultValue = -17\n\tsize := platform.EnvFlag{\n\t\tName:    key,\n\t\tAltName: platform.NormalizeEnvName(key),\n\t}.GetValueAsInt(defaultValue)\n\n\tswitch size {\n\tcase 0:\n\t\tdefaultBufferSize = -1 // For pipe to use unlimited size\n\tcase defaultValue: // Env flag not defined. Use default values per CPU-arch.\n\t\tswitch runtime.GOARCH {\n\t\tcase \"arm\", \"mips\", \"mipsle\":\n\t\t\tdefaultBufferSize = 0\n\t\tcase \"arm64\", \"mips64\", \"mips64le\":\n\t\t\tdefaultBufferSize = 4 * 1024 // 4k cache for low-end devices\n\t\tdefault:\n\t\t\tdefaultBufferSize = 512 * 1024\n\t\t}\n\tdefault:\n\t\tdefaultBufferSize = int32(size) * 1024 * 1024\n\t}\n}\n\nfunc defaultBufferPolicy() Buffer {\n\treturn Buffer{\n\t\tPerConnection: defaultBufferSize,\n\t}\n}\n\n// SessionDefault returns the Policy when user is not specified.\nfunc SessionDefault() Session {\n\treturn Session{\n\t\tTimeouts: Timeout{\n\t\t\t//Align Handshake timeout with nginx client_header_timeout\n\t\t\t//So that this value will not indicate server identity\n\t\t\tHandshake:      time.Second * 60,\n\t\t\tConnectionIdle: time.Second * 300,\n\t\t\tUplinkOnly:     time.Second * 1,\n\t\t\tDownlinkOnly:   time.Second * 1,\n\t\t},\n\t\tStats: Stats{\n\t\t\tUserUplink:   false,\n\t\t\tUserDownlink: false,\n\t\t},\n\t\tBuffer: defaultBufferPolicy(),\n\t}\n}\n\ntype policyKey int32\n\nconst (\n\tbufferPolicyKey policyKey = 0\n)\n\nfunc ContextWithBufferPolicy(ctx context.Context, p Buffer) context.Context {\n\treturn context.WithValue(ctx, bufferPolicyKey, p)\n}\n\nfunc BufferPolicyFromContext(ctx context.Context) Buffer {\n\tpPolicy := ctx.Value(bufferPolicyKey)\n\tif pPolicy == nil {\n\t\treturn defaultBufferPolicy()\n\t}\n\treturn pPolicy.(Buffer)\n}\n"
  },
  {
    "path": "features/routing/context.go",
    "content": "package routing\n\nimport (\n\t\"v2ray.com/core/common/net\"\n)\n\n// Context is a feature to store connection information for routing.\n//\n// v2ray:api:stable\ntype Context interface {\n\t// GetInboundTag returns the tag of the inbound the connection was from.\n\tGetInboundTag() string\n\n\t// GetSourcesIPs returns the source IPs bound to the connection.\n\tGetSourceIPs() []net.IP\n\n\t// GetSourcePort returns the source port of the connection.\n\tGetSourcePort() net.Port\n\n\t// GetTargetIPs returns the target IP of the connection or resolved IPs of target domain.\n\tGetTargetIPs() []net.IP\n\n\t// GetTargetPort returns the target port of the connection.\n\tGetTargetPort() net.Port\n\n\t// GetTargetDomain returns the target domain of the connection, if exists.\n\tGetTargetDomain() string\n\n\t// GetNetwork returns the network type of the connection.\n\tGetNetwork() net.Network\n\n\t// GetProtocol returns the protocol from the connection content, if sniffed out.\n\tGetProtocol() string\n\n\t// GetUser returns the user email from the connection content, if exists.\n\tGetUser() string\n\n\t// GetAttributes returns extra attributes from the conneciont content.\n\tGetAttributes() map[string]string\n}\n"
  },
  {
    "path": "features/routing/dispatcher.go",
    "content": "package routing\n\nimport (\n\t\"context\"\n\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/features\"\n\t\"v2ray.com/core/transport\"\n)\n\n// Dispatcher is a feature that dispatches inbound requests to outbound handlers based on rules.\n// Dispatcher is required to be registered in a V2Ray instance to make V2Ray function properly.\n//\n// v2ray:api:stable\ntype Dispatcher interface {\n\tfeatures.Feature\n\n\t// Dispatch returns a Ray for transporting data for the given request.\n\tDispatch(ctx context.Context, dest net.Destination) (*transport.Link, error)\n}\n\n// DispatcherType returns the type of Dispatcher interface. Can be used to implement common.HasType.\n//\n// v2ray:api:stable\nfunc DispatcherType() interface{} {\n\treturn (*Dispatcher)(nil)\n}\n"
  },
  {
    "path": "features/routing/dns/context.go",
    "content": "package dns\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n\nimport (\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/features/dns\"\n\t\"v2ray.com/core/features/routing\"\n)\n\n// ResolvableContext is an implementation of routing.Context, with domain resolving capability.\ntype ResolvableContext struct {\n\trouting.Context\n\tdnsClient   dns.Client\n\tresolvedIPs []net.IP\n}\n\n// GetTargetIPs overrides original routing.Context's implementation.\nfunc (ctx *ResolvableContext) GetTargetIPs() []net.IP {\n\tif ips := ctx.Context.GetTargetIPs(); len(ips) != 0 {\n\t\treturn ips\n\t}\n\n\tif len(ctx.resolvedIPs) > 0 {\n\t\treturn ctx.resolvedIPs\n\t}\n\n\tif domain := ctx.GetTargetDomain(); len(domain) != 0 {\n\t\tips, err := ctx.dnsClient.LookupIP(domain)\n\t\tif err == nil {\n\t\t\tctx.resolvedIPs = ips\n\t\t\treturn ips\n\t\t}\n\t\tnewError(\"resolve ip for \", domain).Base(err).WriteToLog()\n\t}\n\n\treturn nil\n}\n\n// ContextWithDNSClient creates a new routing context with domain resolving capability.\n// Resolved domain IPs can be retrieved by GetTargetIPs().\nfunc ContextWithDNSClient(ctx routing.Context, client dns.Client) routing.Context {\n\treturn &ResolvableContext{Context: ctx, dnsClient: client}\n}\n"
  },
  {
    "path": "features/routing/dns/errors.generated.go",
    "content": "package dns\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "features/routing/router.go",
    "content": "package routing\n\nimport (\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/features\"\n)\n\n// Router is a feature to choose an outbound tag for the given request.\n//\n// v2ray:api:stable\ntype Router interface {\n\tfeatures.Feature\n\n\t// PickRoute returns a route decision based on the given routing context.\n\tPickRoute(ctx Context) (Route, error)\n}\n\n// Route is the routing result of Router feature.\n//\n// v2ray:api:stable\ntype Route interface {\n\t// A Route is also a routing context.\n\tContext\n\n\t// GetOutboundGroupTags returns the detoured outbound group tags in sequence before a final outbound is chosen.\n\tGetOutboundGroupTags() []string\n\n\t// GetOutboundTag returns the tag of the outbound the connection was dispatched to.\n\tGetOutboundTag() string\n}\n\n// RouterType return the type of Router interface. Can be used to implement common.HasType.\n//\n// v2ray:api:stable\nfunc RouterType() interface{} {\n\treturn (*Router)(nil)\n}\n\n// DefaultRouter is an implementation of Router, which always returns ErrNoClue for routing decisions.\ntype DefaultRouter struct{}\n\n// Type implements common.HasType.\nfunc (DefaultRouter) Type() interface{} {\n\treturn RouterType()\n}\n\n// PickRoute implements Router.\nfunc (DefaultRouter) PickRoute(ctx Context) (Route, error) {\n\treturn nil, common.ErrNoClue\n}\n\n// Start implements common.Runnable.\nfunc (DefaultRouter) Start() error {\n\treturn nil\n}\n\n// Close implements common.Closable.\nfunc (DefaultRouter) Close() error {\n\treturn nil\n}\n"
  },
  {
    "path": "features/routing/session/context.go",
    "content": "package session\n\nimport (\n\t\"context\"\n\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/session\"\n\t\"v2ray.com/core/features/routing\"\n)\n\n// Context is an implementation of routing.Context, which is a wrapper of context.context with session info.\ntype Context struct {\n\tInbound  *session.Inbound\n\tOutbound *session.Outbound\n\tContent  *session.Content\n}\n\n// GetInboundTag implements routing.Context.\nfunc (ctx *Context) GetInboundTag() string {\n\tif ctx.Inbound == nil {\n\t\treturn \"\"\n\t}\n\treturn ctx.Inbound.Tag\n}\n\n// GetSourceIPs implements routing.Context.\nfunc (ctx *Context) GetSourceIPs() []net.IP {\n\tif ctx.Inbound == nil || !ctx.Inbound.Source.IsValid() {\n\t\treturn nil\n\t}\n\tdest := ctx.Inbound.Source\n\tif dest.Address.Family().IsDomain() {\n\t\treturn nil\n\t}\n\n\treturn []net.IP{dest.Address.IP()}\n}\n\n// GetSourcePort implements routing.Context.\nfunc (ctx *Context) GetSourcePort() net.Port {\n\tif ctx.Inbound == nil || !ctx.Inbound.Source.IsValid() {\n\t\treturn 0\n\t}\n\treturn ctx.Inbound.Source.Port\n}\n\n// GetTargetIPs implements routing.Context.\nfunc (ctx *Context) GetTargetIPs() []net.IP {\n\tif ctx.Outbound == nil || !ctx.Outbound.Target.IsValid() {\n\t\treturn nil\n\t}\n\n\tif ctx.Outbound.Target.Address.Family().IsIP() {\n\t\treturn []net.IP{ctx.Outbound.Target.Address.IP()}\n\t}\n\n\treturn nil\n}\n\n// GetTargetPort implements routing.Context.\nfunc (ctx *Context) GetTargetPort() net.Port {\n\tif ctx.Outbound == nil || !ctx.Outbound.Target.IsValid() {\n\t\treturn 0\n\t}\n\treturn ctx.Outbound.Target.Port\n}\n\n// GetTargetDomain implements routing.Context.\nfunc (ctx *Context) GetTargetDomain() string {\n\tif ctx.Outbound == nil || !ctx.Outbound.Target.IsValid() {\n\t\treturn \"\"\n\t}\n\tdest := ctx.Outbound.Target\n\tif !dest.Address.Family().IsDomain() {\n\t\treturn \"\"\n\t}\n\treturn dest.Address.Domain()\n}\n\n// GetNetwork implements routing.Context.\nfunc (ctx *Context) GetNetwork() net.Network {\n\tif ctx.Outbound == nil {\n\t\treturn net.Network_Unknown\n\t}\n\treturn ctx.Outbound.Target.Network\n}\n\n// GetProtocol implements routing.Context.\nfunc (ctx *Context) GetProtocol() string {\n\tif ctx.Content == nil {\n\t\treturn \"\"\n\t}\n\treturn ctx.Content.Protocol\n}\n\n// GetUser implements routing.Context.\nfunc (ctx *Context) GetUser() string {\n\tif ctx.Inbound == nil || ctx.Inbound.User == nil {\n\t\treturn \"\"\n\t}\n\treturn ctx.Inbound.User.Email\n}\n\n// GetAttributes implements routing.Context.\nfunc (ctx *Context) GetAttributes() map[string]string {\n\tif ctx.Content == nil {\n\t\treturn nil\n\t}\n\treturn ctx.Content.Attributes\n}\n\n// AsRoutingContext creates a context from context.context with session info.\nfunc AsRoutingContext(ctx context.Context) routing.Context {\n\treturn &Context{\n\t\tInbound:  session.InboundFromContext(ctx),\n\t\tOutbound: session.OutboundFromContext(ctx),\n\t\tContent:  session.ContentFromContext(ctx),\n\t}\n}\n"
  },
  {
    "path": "features/stats/errors.generated.go",
    "content": "package stats\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "features/stats/stats.go",
    "content": "package stats\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n\nimport (\n\t\"context\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/features\"\n)\n\n// Counter is the interface for stats counters.\n//\n// v2ray:api:stable\ntype Counter interface {\n\t// Value is the current value of the counter.\n\tValue() int64\n\t// Set sets a new value to the counter, and returns the previous one.\n\tSet(int64) int64\n\t// Add adds a value to the current counter value, and returns the previous value.\n\tAdd(int64) int64\n}\n\n// Channel is the interface for stats channel.\n//\n// v2ray:api:stable\ntype Channel interface {\n\t// Channel is a runnable unit.\n\tcommon.Runnable\n\t// Publish broadcasts a message through the channel with a controlling context.\n\tPublish(context.Context, interface{})\n\t// SubscriberCount returns the number of the subscribers.\n\tSubscribers() []chan interface{}\n\t// Subscribe registers for listening to channel stream and returns a new listener channel.\n\tSubscribe() (chan interface{}, error)\n\t// Unsubscribe unregisters a listener channel from current Channel object.\n\tUnsubscribe(chan interface{}) error\n}\n\n// SubscribeRunnableChannel subscribes the channel and starts it if there is first subscriber coming.\nfunc SubscribeRunnableChannel(c Channel) (chan interface{}, error) {\n\tif len(c.Subscribers()) == 0 {\n\t\tif err := c.Start(); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn c.Subscribe()\n}\n\n// UnsubscribeClosableChannel unsubcribes the channel and close it if there is no more subscriber.\nfunc UnsubscribeClosableChannel(c Channel, sub chan interface{}) error {\n\tif err := c.Unsubscribe(sub); err != nil {\n\t\treturn err\n\t}\n\tif len(c.Subscribers()) == 0 {\n\t\treturn c.Close()\n\t}\n\treturn nil\n}\n\n// Manager is the interface for stats manager.\n//\n// v2ray:api:stable\ntype Manager interface {\n\tfeatures.Feature\n\n\t// RegisterCounter registers a new counter to the manager. The identifier string must not be empty, and unique among other counters.\n\tRegisterCounter(string) (Counter, error)\n\t// UnregisterCounter unregisters a counter from the manager by its identifier.\n\tUnregisterCounter(string) error\n\t// GetCounter returns a counter by its identifier.\n\tGetCounter(string) Counter\n\n\t// RegisterChannel registers a new channel to the manager. The identifier string must not be empty, and unique among other channels.\n\tRegisterChannel(string) (Channel, error)\n\t// UnregisterCounter unregisters a channel from the manager by its identifier.\n\tUnregisterChannel(string) error\n\t// GetChannel returns a channel by its identifier.\n\tGetChannel(string) Channel\n}\n\n// GetOrRegisterCounter tries to get the StatCounter first. If not exist, it then tries to create a new counter.\nfunc GetOrRegisterCounter(m Manager, name string) (Counter, error) {\n\tcounter := m.GetCounter(name)\n\tif counter != nil {\n\t\treturn counter, nil\n\t}\n\n\treturn m.RegisterCounter(name)\n}\n\n// GetOrRegisterChannel tries to get the StatChannel first. If not exist, it then tries to create a new channel.\nfunc GetOrRegisterChannel(m Manager, name string) (Channel, error) {\n\tchannel := m.GetChannel(name)\n\tif channel != nil {\n\t\treturn channel, nil\n\t}\n\n\treturn m.RegisterChannel(name)\n}\n\n// ManagerType returns the type of Manager interface. Can be used to implement common.HasType.\n//\n// v2ray:api:stable\nfunc ManagerType() interface{} {\n\treturn (*Manager)(nil)\n}\n\n// NoopManager is an implementation of Manager, which doesn't has actual functionalities.\ntype NoopManager struct{}\n\n// Type implements common.HasType.\nfunc (NoopManager) Type() interface{} {\n\treturn ManagerType()\n}\n\n// RegisterCounter implements Manager.\nfunc (NoopManager) RegisterCounter(string) (Counter, error) {\n\treturn nil, newError(\"not implemented\")\n}\n\n// UnregisterCounter implements Manager.\nfunc (NoopManager) UnregisterCounter(string) error {\n\treturn nil\n}\n\n// GetCounter implements Manager.\nfunc (NoopManager) GetCounter(string) Counter {\n\treturn nil\n}\n\n// RegisterChannel implements Manager.\nfunc (NoopManager) RegisterChannel(string) (Channel, error) {\n\treturn nil, newError(\"not implemented\")\n}\n\n// UnregisterChannel implements Manager.\nfunc (NoopManager) UnregisterChannel(string) error {\n\treturn nil\n}\n\n// GetChannel implements Manager.\nfunc (NoopManager) GetChannel(string) Channel {\n\treturn nil\n}\n\n// Start implements common.Runnable.\nfunc (NoopManager) Start() error { return nil }\n\n// Close implements common.Closable.\nfunc (NoopManager) Close() error { return nil }\n"
  },
  {
    "path": "functions.go",
    "content": "// +build !confonly\n\npackage core\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/features/routing\"\n\t\"v2ray.com/core/transport/internet/udp\"\n)\n\n// CreateObject creates a new object based on the given V2Ray instance and config. The V2Ray instance may be nil.\nfunc CreateObject(v *Instance, config interface{}) (interface{}, error) {\n\tctx := v.ctx\n\tif v != nil {\n\t\tctx = context.WithValue(ctx, v2rayKey, v)\n\t}\n\treturn common.CreateObject(ctx, config)\n}\n\n// StartInstance starts a new V2Ray instance with given serialized config.\n// By default V2Ray only support config in protobuf format, i.e., configFormat = \"protobuf\". Caller need to load other packages to add JSON support.\n//\n// v2ray:api:stable\nfunc StartInstance(configFormat string, configBytes []byte) (*Instance, error) {\n\tconfig, err := LoadConfig(configFormat, \"\", bytes.NewReader(configBytes))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tinstance, err := New(config)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif err := instance.Start(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn instance, nil\n}\n\n// Dial provides an easy way for upstream caller to create net.Conn through V2Ray.\n// It dispatches the request to the given destination by the given V2Ray instance.\n// Since it is under a proxy context, the LocalAddr() and RemoteAddr() in returned net.Conn\n// will not show real addresses being used for communication.\n//\n// v2ray:api:stable\nfunc Dial(ctx context.Context, v *Instance, dest net.Destination) (net.Conn, error) {\n\tdispatcher := v.GetFeature(routing.DispatcherType())\n\tif dispatcher == nil {\n\t\treturn nil, newError(\"routing.Dispatcher is not registered in V2Ray core\")\n\t}\n\tr, err := dispatcher.(routing.Dispatcher).Dispatch(ctx, dest)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar readerOpt net.ConnectionOption\n\tif dest.Network == net.Network_TCP {\n\t\treaderOpt = net.ConnectionOutputMulti(r.Reader)\n\t} else {\n\t\treaderOpt = net.ConnectionOutputMultiUDP(r.Reader)\n\t}\n\treturn net.NewConnection(net.ConnectionInputMulti(r.Writer), readerOpt), nil\n}\n\n// DialUDP provides a way to exchange UDP packets through V2Ray instance to remote servers.\n// Since it is under a proxy context, the LocalAddr() in returned PacketConn will not show the real address.\n//\n// TODO: SetDeadline() / SetReadDeadline() / SetWriteDeadline() are not implemented.\n//\n// v2ray:api:beta\nfunc DialUDP(ctx context.Context, v *Instance) (net.PacketConn, error) {\n\tdispatcher := v.GetFeature(routing.DispatcherType())\n\tif dispatcher == nil {\n\t\treturn nil, newError(\"routing.Dispatcher is not registered in V2Ray core\")\n\t}\n\treturn udp.DialDispatcher(ctx, dispatcher.(routing.Dispatcher))\n}\n"
  },
  {
    "path": "functions_test.go",
    "content": "package core_test\n\nimport (\n\t\"context\"\n\t\"crypto/rand\"\n\t\"io\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/golang/protobuf/proto\"\n\t\"github.com/google/go-cmp/cmp\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/app/dispatcher\"\n\t\"v2ray.com/core/app/proxyman\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/serial\"\n\t\"v2ray.com/core/proxy/freedom\"\n\t\"v2ray.com/core/testing/servers/tcp\"\n\t\"v2ray.com/core/testing/servers/udp\"\n)\n\nfunc xor(b []byte) []byte {\n\tr := make([]byte, len(b))\n\tfor i, v := range b {\n\t\tr[i] = v ^ 'c'\n\t}\n\treturn r\n}\n\nfunc xor2(b []byte) []byte {\n\tr := make([]byte, len(b))\n\tfor i, v := range b {\n\t\tr[i] = v ^ 'd'\n\t}\n\treturn r\n}\n\nfunc TestV2RayDial(t *testing.T) {\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\tdefer tcpServer.Close()\n\n\tconfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&dispatcher.Config{}),\n\t\t\tserial.ToTypedMessage(&proxyman.InboundConfig{}),\n\t\t\tserial.ToTypedMessage(&proxyman.OutboundConfig{}),\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tcfgBytes, err := proto.Marshal(config)\n\tcommon.Must(err)\n\n\tserver, err := core.StartInstance(\"protobuf\", cfgBytes)\n\tcommon.Must(err)\n\tdefer server.Close()\n\n\tconn, err := core.Dial(context.Background(), server, dest)\n\tcommon.Must(err)\n\tdefer conn.Close()\n\n\tconst size = 10240 * 1024\n\tpayload := make([]byte, size)\n\tcommon.Must2(rand.Read(payload))\n\n\tif _, err := conn.Write(payload); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\treceive := make([]byte, size)\n\tif _, err := io.ReadFull(conn, receive); err != nil {\n\t\tt.Fatal(\"failed to read all response: \", err)\n\t}\n\n\tif r := cmp.Diff(xor(receive), payload); r != \"\" {\n\t\tt.Error(r)\n\t}\n}\n\nfunc TestV2RayDialUDPConn(t *testing.T) {\n\tudpServer := udp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := udpServer.Start()\n\tcommon.Must(err)\n\tdefer udpServer.Close()\n\n\tconfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&dispatcher.Config{}),\n\t\t\tserial.ToTypedMessage(&proxyman.InboundConfig{}),\n\t\t\tserial.ToTypedMessage(&proxyman.OutboundConfig{}),\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tcfgBytes, err := proto.Marshal(config)\n\tcommon.Must(err)\n\n\tserver, err := core.StartInstance(\"protobuf\", cfgBytes)\n\tcommon.Must(err)\n\tdefer server.Close()\n\n\tconn, err := core.Dial(context.Background(), server, dest)\n\tcommon.Must(err)\n\tdefer conn.Close()\n\n\tconst size = 1024\n\tpayload := make([]byte, size)\n\tcommon.Must2(rand.Read(payload))\n\n\tfor i := 0; i < 2; i++ {\n\t\tif _, err := conn.Write(payload); err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t}\n\n\ttime.Sleep(time.Millisecond * 500)\n\n\treceive := make([]byte, size*2)\n\tfor i := 0; i < 2; i++ {\n\t\tn, err := conn.Read(receive)\n\t\tif err != nil {\n\t\t\tt.Fatal(\"expect no error, but got \", err)\n\t\t}\n\t\tif n != size {\n\t\t\tt.Fatal(\"expect read size \", size, \" but got \", n)\n\t\t}\n\n\t\tif r := cmp.Diff(xor(receive[:n]), payload); r != \"\" {\n\t\t\tt.Fatal(r)\n\t\t}\n\t}\n}\n\nfunc TestV2RayDialUDP(t *testing.T) {\n\tudpServer1 := udp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest1, err := udpServer1.Start()\n\tcommon.Must(err)\n\tdefer udpServer1.Close()\n\n\tudpServer2 := udp.Server{\n\t\tMsgProcessor: xor2,\n\t}\n\tdest2, err := udpServer2.Start()\n\tcommon.Must(err)\n\tdefer udpServer2.Close()\n\n\tconfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&dispatcher.Config{}),\n\t\t\tserial.ToTypedMessage(&proxyman.InboundConfig{}),\n\t\t\tserial.ToTypedMessage(&proxyman.OutboundConfig{}),\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tcfgBytes, err := proto.Marshal(config)\n\tcommon.Must(err)\n\n\tserver, err := core.StartInstance(\"protobuf\", cfgBytes)\n\tcommon.Must(err)\n\tdefer server.Close()\n\n\tconn, err := core.DialUDP(context.Background(), server)\n\tcommon.Must(err)\n\tdefer conn.Close()\n\n\tconst size = 1024\n\t{\n\t\tpayload := make([]byte, size)\n\t\tcommon.Must2(rand.Read(payload))\n\n\t\tif _, err := conn.WriteTo(payload, &net.UDPAddr{\n\t\t\tIP:   dest1.Address.IP(),\n\t\t\tPort: int(dest1.Port),\n\t\t}); err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\treceive := make([]byte, size)\n\t\tif _, _, err := conn.ReadFrom(receive); err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tif r := cmp.Diff(xor(receive), payload); r != \"\" {\n\t\t\tt.Error(r)\n\t\t}\n\t}\n\n\t{\n\t\tpayload := make([]byte, size)\n\t\tcommon.Must2(rand.Read(payload))\n\n\t\tif _, err := conn.WriteTo(payload, &net.UDPAddr{\n\t\t\tIP:   dest2.Address.IP(),\n\t\t\tPort: int(dest2.Port),\n\t\t}); err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\treceive := make([]byte, size)\n\t\tif _, _, err := conn.ReadFrom(receive); err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tif r := cmp.Diff(xor2(receive), payload); r != \"\" {\n\t\t\tt.Error(r)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "go.mod",
    "content": "module v2ray.com/core\n\ngo 1.15\n\nrequire (\n\tgithub.com/dgryski/go-metro v0.0.0-20200812162917-85c65e2d0165 // indirect\n\tgithub.com/golang/mock v1.4.4\n\tgithub.com/golang/protobuf v1.4.2\n\tgithub.com/google/go-cmp v0.5.3\n\tgithub.com/gorilla/websocket v1.4.2\n\tgithub.com/lucas-clemente/quic-go v0.18.1\n\tgithub.com/miekg/dns v1.1.31\n\tgithub.com/pires/go-proxyproto v0.2.0\n\tgithub.com/seiflotfy/cuckoofilter v0.0.0-20200511222245-56093a4d3841\n\tgithub.com/stretchr/testify v1.8.1\n\tgithub.com/xiaokangwang/VSign v0.0.0-20200828155424-dc1c86b73fbf\n\tgithub.com/xtls/go v0.0.0-20201007031018-d42c13c57942\n\tgo.starlark.net v0.0.0-20201006213952-227f4aabceb5\n\tgolang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0\n\tgolang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0\n\tgolang.org/x/sync v0.0.0-20200930132711-30421366ff76\n\tgolang.org/x/sys v0.0.0-20201006155630-ac719f4daadf\n\tgoogle.golang.org/grpc v1.32.0\n\tgoogle.golang.org/protobuf v1.25.0\n\th12.io/socks v1.0.1\n)\n"
  },
  {
    "path": "go.sum",
    "content": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo=\ndmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU=\ndmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU=\ndmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=\ndmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=\ngit.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=\ngithub.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=\ngithub.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=\ngithub.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=\ngithub.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=\ngithub.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=\ngithub.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=\ngithub.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=\ngithub.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=\ngithub.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=\ngithub.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=\ngithub.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=\ngithub.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=\ngithub.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=\ngithub.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=\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/dgryski/go-metro v0.0.0-20200812162917-85c65e2d0165 h1:BS21ZUJ/B5X2UVUbczfmdWH7GapPWAhxcMsDnjJTU1E=\ngithub.com/dgryski/go-metro v0.0.0-20200812162917-85c65e2d0165/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw=\ngithub.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=\ngithub.com/ebfe/bcrypt_pbkdf v0.0.0-20140212075826-3c8d2dcb253a h1:YtdtTUN1iH97s+6PUjLnaiKSQj4oG1/EZ3N9bx6g4kU=\ngithub.com/ebfe/bcrypt_pbkdf v0.0.0-20140212075826-3c8d2dcb253a/go.mod h1:/CZpbhAusDOobpcb9yubw46kdYjq0zRC0Wpg9a9zFQM=\ngithub.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=\ngithub.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=\ngithub.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=\ngithub.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=\ngithub.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=\ngithub.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=\ngithub.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=\ngithub.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=\ngithub.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=\ngithub.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=\ngithub.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=\ngithub.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=\ngithub.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=\ngithub.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=\ngithub.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=\ngithub.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=\ngithub.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=\ngithub.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=\ngithub.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=\ngithub.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=\ngithub.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=\ngithub.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=\ngithub.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=\ngithub.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=\ngithub.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=\ngithub.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=\ngithub.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\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.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.3 h1:x95R7cp+rSeeqAMI2knLtQ0DKlaBhv2NrtrOvafPHRo=\ngithub.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=\ngithub.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=\ngithub.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=\ngithub.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=\ngithub.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=\ngithub.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=\ngithub.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=\ngithub.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=\ngithub.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=\ngithub.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=\ngithub.com/h12w/go-socks5 v0.0.0-20200522160539-76189e178364 h1:5XxdakFhqd9dnXoAZy1Mb2R/DZ6D1e+0bGC/JhucGYI=\ngithub.com/h12w/go-socks5 v0.0.0-20200522160539-76189e178364/go.mod h1:eDJQioIyy4Yn3MVivT7rv/39gAJTrA7lgmYr8EW950c=\ngithub.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=\ngithub.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=\ngithub.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=\ngithub.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=\ngithub.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=\ngithub.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=\ngithub.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=\ngithub.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=\ngithub.com/lucas-clemente/quic-go v0.18.1 h1:DMR7guC0NtVS8zNZR3IO7NARZvZygkSC56GGtC6cyys=\ngithub.com/lucas-clemente/quic-go v0.18.1/go.mod h1:yXttHsSNxQi8AWijC/vLP+OJczXqzHSOcJrM5ITUlCg=\ngithub.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=\ngithub.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=\ngithub.com/marten-seemann/qpack v0.2.0/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc=\ngithub.com/marten-seemann/qtls v0.10.0 h1:ECsuYUKalRL240rRD4Ri33ISb7kAQ3qGDlrrl55b2pc=\ngithub.com/marten-seemann/qtls v0.10.0/go.mod h1:UvMd1oaYDACI99/oZUYLzMCkBXQVT0aGm99sJhbT8hs=\ngithub.com/marten-seemann/qtls-go1-15 v0.1.0 h1:i/YPXVxz8q9umso/5y474CNcHmTpA+5DH+mFPjx6PZg=\ngithub.com/marten-seemann/qtls-go1-15 v0.1.0/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I=\ngithub.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=\ngithub.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=\ngithub.com/miekg/dns v1.1.31 h1:sJFOl9BgwbYAWOGEwr61FU28pqsBNdpRBnhGXtO06Oo=\ngithub.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=\ngithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\ngithub.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=\ngithub.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=\ngithub.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=\ngithub.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=\ngithub.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=\ngithub.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=\ngithub.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA=\ngithub.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=\ngithub.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=\ngithub.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=\ngithub.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=\ngithub.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=\ngithub.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc=\ngithub.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=\ngithub.com/pires/go-proxyproto v0.2.0 h1:WyYKlv9pkt77b+LjMvPfwrsAxviaGCFhG4KDIy1ofLY=\ngithub.com/pires/go-proxyproto v0.2.0/go.mod h1:Odh9VFOZJCf9G8cLW5o435Xf1J95Jw9Gw5rnCjcwzAY=\ngithub.com/pkg/errors v0.8.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/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=\ngithub.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=\ngithub.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=\ngithub.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=\ngithub.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=\ngithub.com/seiflotfy/cuckoofilter v0.0.0-20200511222245-56093a4d3841 h1:pnfutQFsV7ySmHUeX6ANGfPsBo29RctUvDn8G3rmJVw=\ngithub.com/seiflotfy/cuckoofilter v0.0.0-20200511222245-56093a4d3841/go.mod h1:ET5mVvNjwaGXRgZxO9UZr7X+8eAf87AfIYNwRSp9s4Y=\ngithub.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=\ngithub.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=\ngithub.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=\ngithub.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0=\ngithub.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=\ngithub.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=\ngithub.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw=\ngithub.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI=\ngithub.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU=\ngithub.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag=\ngithub.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg=\ngithub.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw=\ngithub.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y=\ngithub.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=\ngithub.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q=\ngithub.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ=\ngithub.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I=\ngithub.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0=\ngithub.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ=\ngithub.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk=\ngithub.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=\ngithub.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=\ngithub.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=\ngithub.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=\ngithub.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=\ngithub.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=\ngithub.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=\ngithub.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=\ngithub.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=\ngithub.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=\ngithub.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=\ngithub.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=\ngithub.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=\ngithub.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=\ngithub.com/xiaokangwang/VSign v0.0.0-20200828155424-dc1c86b73fbf h1:d4keT3SwLbrgnEe2zbtijPLgKE15n0ZbvJZzRH/a9GM=\ngithub.com/xiaokangwang/VSign v0.0.0-20200828155424-dc1c86b73fbf/go.mod h1:jTwBnzBuqZP3VX/Z65ErYb9zd4anQprSC7N38TmAp1E=\ngithub.com/xtls/go v0.0.0-20201007031018-d42c13c57942 h1:J+h5T5dtgVtszPN0vOFBzTapdVRZ16sXP6o6RPFNs20=\ngithub.com/xtls/go v0.0.0-20201007031018-d42c13c57942/go.mod h1:5TB2+k58gx4A4g2Nf5miSHNDF6CuAzHKpWBooLAshTs=\ngo.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=\ngo.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.starlark.net v0.0.0-20201006213952-227f4aabceb5 h1:ApvY/1gw+Yiqb/FKeks3KnVPWpkR3xzij82XPKLjJVw=\ngo.starlark.net v0.0.0-20201006213952-227f4aabceb5/go.mod h1:f0znQkUKRrkk36XxWbGjMqQM8wGv/xHBVE2qc3B5oFU=\ngo4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=\ngolang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=\ngolang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/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-20190313024323-a1f597ede03a/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-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 h1:hb9wdF1z5waM+dSIICn1l0DkLVDT3hqhhQsDNUmHPRE=\ngolang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=\ngolang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=\ngolang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0 h1:wBouT66WTYFXdxfVdz9sVWARVd/2vfGcmI45D2gj45M=\ngolang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=\ngolang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=\ngolang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=\ngolang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=\ngolang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/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-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20200930132711-30421366ff76 h1:JnxiSYT3Nm0BT2a8CyvYyM6cnrWpidecD1UuSYbhKm0=\ngolang.org/x/sync v0.0.0-20200930132711-30421366ff76/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181029174526-d69651ed3497/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-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201006155630-ac719f4daadf h1:Bg47KQy0JhTHuf4sLiQwTMKwUMfSDwgSGatrxGR7nLM=\ngolang.org/x/sys v0.0.0-20201006155630-ac719f4daadf/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/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 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=\ngolang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngoogle.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=\ngoogle.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=\ngoogle.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=\ngoogle.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=\ngoogle.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=\ngoogle.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=\ngoogle.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=\ngoogle.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=\ngoogle.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=\ngoogle.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=\ngoogle.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=\ngoogle.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=\ngoogle.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=\ngoogle.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=\ngoogle.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=\ngoogle.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=\ngoogle.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=\ngoogle.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.32.0 h1:zWTV+LMdc3kaiJMSTOFz2UgSBgx8RNQoTGiZu3fR9S0=\ngoogle.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=\ngoogle.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=\ngoogle.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=\ngoogle.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=\ngoogle.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=\ngoogle.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=\ngoogle.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=\ngoogle.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=\ngopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=\ngopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=\ngopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=\ngopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=\ngopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=\ngopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\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=\ngrpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=\nh12.io/socks v1.0.1 h1:bXESSI/+hbdrp+22vcc7/JiXjmLH4UWktKdYgGr3ShA=\nh12.io/socks v1.0.1/go.mod h1:AIhxy1jOId/XCz9BO+EIgNL2rQiPTBNnOfnVnQ+3Eck=\nhonnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nrsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=\nrsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=\nsourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=\nsourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=\n"
  },
  {
    "path": "infra/bazel/BUILD",
    "content": "filegroup(\n   name = \"rules\",\n   srcs = glob([\"*.bzl\"]),\n   visibility = [\"//visibility:public\"],\n)\n"
  },
  {
    "path": "infra/bazel/build.bzl",
    "content": "def _go_command(ctx):\n  output = ctx.attr.output\n  if ctx.attr.os == \"windows\":\n    output = output + \".exe\"\n\n  output_file = ctx.actions.declare_file(ctx.attr.os + \"/\" + ctx.attr.arch + \"/\" + ctx.attr.ver + \"/\" + output)\n  pkg = ctx.attr.pkg\n\n  ld_flags = \"-s -w -buildid=\"\n  if ctx.attr.ld:\n    ld_flags = ld_flags + \" \" + ctx.attr.ld\n\n  options = [\n    \"go\",\n    \"build\",\n    \"-trimpath\",\n    \"-o\", output_file.path, \n    \"-ldflags\", \"'%s'\" % ld_flags,\n    \"-tags\", \"'%s'\" % ctx.attr.gotags,\n    pkg,\n  ]\n\n  command = \" \".join(options)\n\n  envs = [\n    \"CGO_ENABLED=0\",\n    \"GOOS=\"+ctx.attr.os,\n    \"GOARCH=\"+ctx.attr.arch,\n    \"GO111MODULE=on\",\n    \"GOCACHE=${TMPDIR}/gocache\"\n  ]\n\n  if ctx.attr.mips: # https://github.com/golang/go/issues/27260\n    envs+=[\"GOMIPS=\"+ctx.attr.mips]\n    envs+=[\"GOMIPS64=\"+ctx.attr.mips]\n    envs+=[\"GOMIPSLE=\"+ctx.attr.mips]\n    envs+=[\"GOMIPS64LE=\"+ctx.attr.mips]\n  if ctx.attr.arm:\n    envs+=[\"GOARM=\"+ctx.attr.arm]\n\n  switchToPwd=\"cd ${SPWD} && \"\n\n  command = switchToPwd + \" \".join(envs) + \" \" + command\n\n  ctx.actions.run_shell(\n    outputs = [output_file],\n    command = command,\n    use_default_shell_env = True,\n  )\n  runfiles = ctx.runfiles(files = [output_file])\n  return [DefaultInfo(executable = output_file, runfiles = runfiles)]\n\n\nforeign_go_binary = rule(\n  _go_command,\n  attrs = {\n    'pkg': attr.string(),\n    'output': attr.string(),\n    'os': attr.string(mandatory=True),\n    'arch': attr.string(mandatory=True),\n    'ver': attr.string(mandatory=True),\n    'mips': attr.string(),\n    'arm': attr.string(),\n    'ld': attr.string(),\n    'gotags': attr.string(),\n  },\n  executable = True,\n)\n"
  },
  {
    "path": "infra/bazel/matrix.bzl",
    "content": "SUPPORTED_MATRIX = [\n  (\"windows\", \"amd64\", \"0\"),\n  (\"windows\", \"386\", \"0\"),\n  (\"windows\", \"arm\", \"7\"),\n  (\"darwin\", \"amd64\", \"0\"),\n  (\"linux\", \"amd64\", \"0\"),\n  (\"linux\", \"386\", \"0\"),\n  (\"linux\", \"arm64\", \"0\"),\n  (\"linux\", \"arm\", \"7\"),\n  (\"linux\", \"arm\", \"6\"),\n  (\"linux\", \"arm\", \"5\"),\n  (\"linux\", \"mips64\", \"0\"),\n  (\"linux\", \"mips\", \"0\"),\n  (\"linux\", \"mips64le\", \"0\"),\n  (\"linux\", \"mipsle\", \"0\"),\n  (\"linux\", \"ppc64\", \"0\"),\n  (\"linux\", \"ppc64le\", \"0\"),\n  (\"linux\", \"riscv64\", \"0\"),\n  (\"linux\", \"s390x\", \"0\"),\n  (\"freebsd\", \"amd64\", \"0\"),\n  (\"freebsd\", \"386\", \"0\"),\n  (\"openbsd\", \"amd64\", \"0\"),\n  (\"openbsd\", \"386\", \"0\"),\n  (\"dragonfly\", \"amd64\", \"0\"),\n]\n"
  },
  {
    "path": "infra/bazel/zip.bzl",
    "content": "# Copied from google/nomulus project as we don't want to import the whole repository.\n\nZIPPER = \"@bazel_tools//tools/zip:zipper\"\n\ndef long_path(ctx, file_):\n    \"\"\"Constructs canonical runfile path relative to TEST_SRCDIR.\n    Args:\n      ctx: A Skylark rule context.\n      file_: A File object that should appear in the runfiles for the test.\n    Returns:\n      A string path relative to TEST_SRCDIR suitable for use in tests and\n      testing infrastructure.\n    \"\"\"\n    if file_.short_path.startswith(\"../\"):\n        return file_.short_path[3:]\n    if file_.owner and file_.owner.workspace_root:\n        return file_.owner.workspace_root + \"/\" + file_.short_path\n    return ctx.workspace_name + \"/\" + file_.short_path\n\ndef collect_runfiles(targets):\n    \"\"\"Aggregates runfiles from targets.\n    Args:\n      targets: A list of Bazel targets.\n    Returns:\n      A list of Bazel files.\n    \"\"\"\n    data = depset()\n    for target in targets:\n        if hasattr(target, \"runfiles\"):\n            data += target.runfiles.files\n            continue\n        if hasattr(target, \"data_runfiles\"):\n            data += target.data_runfiles.files\n        if hasattr(target, \"default_runfiles\"):\n            data += target.default_runfiles.files\n    return data\n\ndef _get_runfiles(target, attribute):\n    runfiles = getattr(target, attribute, None)\n    if runfiles:\n        return runfiles.files\n    return []\n\ndef _zip_file(ctx):\n    \"\"\"Implementation of zip_file() rule.\"\"\"\n    for s, d in ctx.attr.mappings.items():\n        if (s.startswith(\"/\") or s.endswith(\"/\") or\n            d.startswith(\"/\") or d.endswith(\"/\")):\n            fail(\"mappings should not begin or end with slash\")\n    srcs = depset(transitive = [depset(ctx.files.srcs),depset(ctx.files.data),depset(collect_runfiles(ctx.attr.data))])\n    mapped = _map_sources(ctx, srcs, ctx.attr.mappings)\n    cmd = [\n        \"#!/bin/sh\",\n        \"set -e\",\n        'repo=\"$(pwd)\"',\n        'zipper=\"${repo}/%s\"' % ctx.file._zipper.path,\n        'archive=\"${repo}/%s\"' % ctx.outputs.out.path,\n        'tmp=\"$(mktemp -d \"${TMPDIR:-/tmp}/zip_file.XXXXXXXXXX\")\"',\n        'cd \"${tmp}\"',\n    ]\n    cmd += [\n        '\"${zipper}\" x \"${repo}/%s\"' % dep.zip_file.path\n        for dep in ctx.attr.deps\n    ]\n    cmd += [\"rm %s\" % filename for filename in ctx.attr.exclude]\n    cmd += [\n        'mkdir -p \"${tmp}/%s\"' % zip_path\n        for zip_path in depset(\n            [\n                zip_path[:zip_path.rindex(\"/\")]\n                for _, zip_path in mapped\n                if \"/\" in zip_path\n            ],\n        ).to_list()\n    ]\n    cmd += [\n        'ln -sf \"${repo}/%s\" \"${tmp}/%s\"' % (path, zip_path)\n        for path, zip_path in mapped\n    ]\n    cmd += [\n        (\"find . | sed 1d | cut -c 3- | LC_ALL=C sort\" +\n         ' | xargs \"${zipper}\" cC \"${archive}\"'),\n        'cd \"${repo}\"',\n        'rm -rf \"${tmp}\"',\n    ]\n    script = ctx.actions.declare_file(\"%s/%s.sh\" % (ctx.bin_dir, ctx.label.name))\n    ctx.actions.write(output = script, content = \"\\n\".join(cmd), is_executable = True)\n    inputs = [ctx.file._zipper]\n    inputs += [dep.zip_file for dep in ctx.attr.deps]\n    inputs += list(srcs.to_list())\n    ctx.actions.run(\n        inputs = inputs,\n        outputs = [ctx.outputs.out],\n        executable = script,\n        mnemonic = \"zip\",\n        progress_message = \"Creating zip with %d inputs %s\" % (\n            len(inputs),\n            ctx.label,\n        ),\n    )\n    return struct(files = depset([ctx.outputs.out]), zip_file = ctx.outputs.out)\n\ndef _map_sources(ctx, srcs, mappings):\n    \"\"\"Calculates paths in zip file for srcs.\"\"\"\n\n    # order mappings with more path components first\n    mappings = sorted([\n        (-len(source.split(\"/\")), source, dest)\n        for source, dest in mappings.items()\n    ])\n\n    # get rid of the integer part of tuple used for sorting\n    mappings = [(source, dest) for _, source, dest in mappings]\n    mappings_indexes = range(len(mappings))\n    used = {i: False for i in mappings_indexes}\n    mapped = []\n    for file_ in srcs.to_list():\n        run_path = long_path(ctx, file_)\n        zip_path = None\n        for i in mappings_indexes:\n            source = mappings[i][0]\n            dest = mappings[i][1]\n            if not source:\n                if dest:\n                    zip_path = dest + \"/\" + run_path\n                else:\n                    zip_path = run_path\n            elif source == run_path:\n                if dest:\n                    zip_path = dest\n                else:\n                    zip_path = run_path\n            elif run_path.startswith(source + \"/\"):\n                if dest:\n                    zip_path = dest + run_path[len(source):]\n                else:\n                    zip_path = run_path[len(source) + 1:]\n            else:\n                continue\n            used[i] = True\n            break\n        if not zip_path:\n            fail(\"no mapping matched: \" + run_path)\n        mapped += [(file_.path, zip_path)]\n    for i in mappings_indexes:\n        if not used[i]:\n            fail('superfluous mapping: \"%s\" -> \"%s\"' % mappings[i])\n    return mapped\n\npkg_zip = rule(\n    implementation = _zip_file,\n    attrs = {\n        \"out\": attr.output(mandatory = True),\n        \"srcs\": attr.label_list(allow_files = True),\n        \"data\": attr.label_list(allow_files = True),\n        \"deps\": attr.label_list(providers = [\"zip_file\"]),\n        \"exclude\": attr.string_list(),\n        \"mappings\": attr.string_dict(),\n        \"_zipper\": attr.label(default = Label(ZIPPER), allow_single_file = True),\n    },\n)\n"
  },
  {
    "path": "infra/conf/api.go",
    "content": "package conf\n\nimport (\n\t\"strings\"\n\n\t\"v2ray.com/core/app/commander\"\n\tloggerservice \"v2ray.com/core/app/log/command\"\n\thandlerservice \"v2ray.com/core/app/proxyman/command\"\n\tstatsservice \"v2ray.com/core/app/stats/command\"\n\t\"v2ray.com/core/common/serial\"\n)\n\ntype ApiConfig struct {\n\tTag      string   `json:\"tag\"`\n\tServices []string `json:\"services\"`\n}\n\nfunc (c *ApiConfig) Build() (*commander.Config, error) {\n\tif c.Tag == \"\" {\n\t\treturn nil, newError(\"Api tag can't be empty.\")\n\t}\n\n\tservices := make([]*serial.TypedMessage, 0, 16)\n\tfor _, s := range c.Services {\n\t\tswitch strings.ToLower(s) {\n\t\tcase \"handlerservice\":\n\t\t\tservices = append(services, serial.ToTypedMessage(&handlerservice.Config{}))\n\t\tcase \"loggerservice\":\n\t\t\tservices = append(services, serial.ToTypedMessage(&loggerservice.Config{}))\n\t\tcase \"statsservice\":\n\t\t\tservices = append(services, serial.ToTypedMessage(&statsservice.Config{}))\n\t\t}\n\t}\n\n\treturn &commander.Config{\n\t\tTag:     c.Tag,\n\t\tService: services,\n\t}, nil\n}\n"
  },
  {
    "path": "infra/conf/blackhole.go",
    "content": "package conf\n\nimport (\n\t\"encoding/json\"\n\n\t\"github.com/golang/protobuf/proto\"\n\n\t\"v2ray.com/core/common/serial\"\n\t\"v2ray.com/core/proxy/blackhole\"\n)\n\ntype NoneResponse struct{}\n\nfunc (*NoneResponse) Build() (proto.Message, error) {\n\treturn new(blackhole.NoneResponse), nil\n}\n\ntype HttpResponse struct{}\n\nfunc (*HttpResponse) Build() (proto.Message, error) {\n\treturn new(blackhole.HTTPResponse), nil\n}\n\ntype BlackholeConfig struct {\n\tResponse json.RawMessage `json:\"response\"`\n}\n\nfunc (v *BlackholeConfig) Build() (proto.Message, error) {\n\tconfig := new(blackhole.Config)\n\tif v.Response != nil {\n\t\tresponse, _, err := configLoader.Load(v.Response)\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"Config: Failed to parse Blackhole response config.\").Base(err)\n\t\t}\n\t\tresponseSettings, err := response.(Buildable).Build()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tconfig.Response = serial.ToTypedMessage(responseSettings)\n\t}\n\n\treturn config, nil\n}\n\nvar (\n\tconfigLoader = NewJSONConfigLoader(\n\t\tConfigCreatorCache{\n\t\t\t\"none\": func() interface{} { return new(NoneResponse) },\n\t\t\t\"http\": func() interface{} { return new(HttpResponse) },\n\t\t},\n\t\t\"type\",\n\t\t\"\")\n)\n"
  },
  {
    "path": "infra/conf/blackhole_test.go",
    "content": "package conf_test\n\nimport (\n\t\"testing\"\n\n\t\"v2ray.com/core/common/serial\"\n\t. \"v2ray.com/core/infra/conf\"\n\t\"v2ray.com/core/proxy/blackhole\"\n)\n\nfunc TestHTTPResponseJSON(t *testing.T) {\n\tcreator := func() Buildable {\n\t\treturn new(BlackholeConfig)\n\t}\n\n\trunMultiTestCase(t, []TestCase{\n\t\t{\n\t\t\tInput: `{\n\t\t\t\t\"response\": {\n\t\t\t\t\t\"type\": \"http\"\n\t\t\t\t}\n\t\t\t}`,\n\t\t\tParser: loadJSON(creator),\n\t\t\tOutput: &blackhole.Config{\n\t\t\t\tResponse: serial.ToTypedMessage(&blackhole.HTTPResponse{}),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tInput:  `{}`,\n\t\t\tParser: loadJSON(creator),\n\t\t\tOutput: &blackhole.Config{},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "infra/conf/buildable.go",
    "content": "package conf\n\nimport \"github.com/golang/protobuf/proto\"\n\ntype Buildable interface {\n\tBuild() (proto.Message, error)\n}\n"
  },
  {
    "path": "infra/conf/command/command.go",
    "content": "package command\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n\nimport (\n\t\"os\"\n\n\t\"github.com/golang/protobuf/proto\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/infra/conf/serial\"\n\t\"v2ray.com/core/infra/control\"\n)\n\ntype ConfigCommand struct{}\n\nfunc (c *ConfigCommand) Name() string {\n\treturn \"config\"\n}\n\nfunc (c *ConfigCommand) Description() control.Description {\n\treturn control.Description{\n\t\tShort: \"Convert config among different formats.\",\n\t\tUsage: []string{\n\t\t\t\"v2ctl config\",\n\t\t},\n\t}\n}\n\nfunc (c *ConfigCommand) Execute(args []string) error {\n\tpbConfig, err := serial.LoadJSONConfig(os.Stdin)\n\tif err != nil {\n\t\treturn newError(\"failed to parse json config\").Base(err)\n\t}\n\n\tbytesConfig, err := proto.Marshal(pbConfig)\n\tif err != nil {\n\t\treturn newError(\"failed to marshal proto config\").Base(err)\n\t}\n\n\tif _, err := os.Stdout.Write(bytesConfig); err != nil {\n\t\treturn newError(\"failed to write proto config\").Base(err)\n\t}\n\treturn nil\n}\n\nfunc init() {\n\tcommon.Must(control.RegisterCommand(&ConfigCommand{}))\n}\n"
  },
  {
    "path": "infra/conf/command/errors.generated.go",
    "content": "package command\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "infra/conf/common.go",
    "content": "package conf\n\nimport (\n\t\"encoding/json\"\n\t\"os\"\n\t\"strings\"\n\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n)\n\ntype StringList []string\n\nfunc NewStringList(raw []string) *StringList {\n\tlist := StringList(raw)\n\treturn &list\n}\n\nfunc (v StringList) Len() int {\n\treturn len(v)\n}\n\nfunc (v *StringList) UnmarshalJSON(data []byte) error {\n\tvar strarray []string\n\tif err := json.Unmarshal(data, &strarray); err == nil {\n\t\t*v = *NewStringList(strarray)\n\t\treturn nil\n\t}\n\n\tvar rawstr string\n\tif err := json.Unmarshal(data, &rawstr); err == nil {\n\t\tstrlist := strings.Split(rawstr, \",\")\n\t\t*v = *NewStringList(strlist)\n\t\treturn nil\n\t}\n\treturn newError(\"unknown format of a string list: \" + string(data))\n}\n\ntype Address struct {\n\tnet.Address\n}\n\nfunc (v *Address) UnmarshalJSON(data []byte) error {\n\tvar rawStr string\n\tif err := json.Unmarshal(data, &rawStr); err != nil {\n\t\treturn newError(\"invalid address: \", string(data)).Base(err)\n\t}\n\tv.Address = net.ParseAddress(rawStr)\n\n\treturn nil\n}\n\nfunc (v *Address) Build() *net.IPOrDomain {\n\treturn net.NewIPOrDomain(v.Address)\n}\n\ntype Network string\n\nfunc (v Network) Build() net.Network {\n\tswitch strings.ToLower(string(v)) {\n\tcase \"tcp\":\n\t\treturn net.Network_TCP\n\tcase \"udp\":\n\t\treturn net.Network_UDP\n\tdefault:\n\t\treturn net.Network_Unknown\n\t}\n}\n\ntype NetworkList []Network\n\nfunc (v *NetworkList) UnmarshalJSON(data []byte) error {\n\tvar strarray []Network\n\tif err := json.Unmarshal(data, &strarray); err == nil {\n\t\tnl := NetworkList(strarray)\n\t\t*v = nl\n\t\treturn nil\n\t}\n\n\tvar rawstr Network\n\tif err := json.Unmarshal(data, &rawstr); err == nil {\n\t\tstrlist := strings.Split(string(rawstr), \",\")\n\t\tnl := make([]Network, len(strlist))\n\t\tfor idx, network := range strlist {\n\t\t\tnl[idx] = Network(network)\n\t\t}\n\t\t*v = nl\n\t\treturn nil\n\t}\n\treturn newError(\"unknown format of a string list: \" + string(data))\n}\n\nfunc (v *NetworkList) Build() []net.Network {\n\tif v == nil {\n\t\treturn []net.Network{net.Network_TCP}\n\t}\n\n\tlist := make([]net.Network, 0, len(*v))\n\tfor _, network := range *v {\n\t\tlist = append(list, network.Build())\n\t}\n\treturn list\n}\n\nfunc parseIntPort(data []byte) (net.Port, error) {\n\tvar intPort uint32\n\terr := json.Unmarshal(data, &intPort)\n\tif err != nil {\n\t\treturn net.Port(0), err\n\t}\n\treturn net.PortFromInt(intPort)\n}\n\nfunc parseStringPort(s string) (net.Port, net.Port, error) {\n\tif strings.HasPrefix(s, \"env:\") {\n\t\ts = s[4:]\n\t\ts = os.Getenv(s)\n\t}\n\n\tpair := strings.SplitN(s, \"-\", 2)\n\tif len(pair) == 0 {\n\t\treturn net.Port(0), net.Port(0), newError(\"invalid port range: \", s)\n\t}\n\tif len(pair) == 1 {\n\t\tport, err := net.PortFromString(pair[0])\n\t\treturn port, port, err\n\t}\n\n\tfromPort, err := net.PortFromString(pair[0])\n\tif err != nil {\n\t\treturn net.Port(0), net.Port(0), err\n\t}\n\ttoPort, err := net.PortFromString(pair[1])\n\tif err != nil {\n\t\treturn net.Port(0), net.Port(0), err\n\t}\n\treturn fromPort, toPort, nil\n}\n\nfunc parseJSONStringPort(data []byte) (net.Port, net.Port, error) {\n\tvar s string\n\terr := json.Unmarshal(data, &s)\n\tif err != nil {\n\t\treturn net.Port(0), net.Port(0), err\n\t}\n\treturn parseStringPort(s)\n}\n\ntype PortRange struct {\n\tFrom uint32\n\tTo   uint32\n}\n\nfunc (v *PortRange) Build() *net.PortRange {\n\treturn &net.PortRange{\n\t\tFrom: v.From,\n\t\tTo:   v.To,\n\t}\n}\n\n// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON\nfunc (v *PortRange) UnmarshalJSON(data []byte) error {\n\tport, err := parseIntPort(data)\n\tif err == nil {\n\t\tv.From = uint32(port)\n\t\tv.To = uint32(port)\n\t\treturn nil\n\t}\n\n\tfrom, to, err := parseJSONStringPort(data)\n\tif err == nil {\n\t\tv.From = uint32(from)\n\t\tv.To = uint32(to)\n\t\tif v.From > v.To {\n\t\t\treturn newError(\"invalid port range \", v.From, \" -> \", v.To)\n\t\t}\n\t\treturn nil\n\t}\n\n\treturn newError(\"invalid port range: \", string(data))\n}\n\ntype PortList struct {\n\tRange []PortRange\n}\n\nfunc (list *PortList) Build() *net.PortList {\n\tportList := new(net.PortList)\n\tfor _, r := range list.Range {\n\t\tportList.Range = append(portList.Range, r.Build())\n\t}\n\treturn portList\n}\n\n// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON\nfunc (list *PortList) UnmarshalJSON(data []byte) error {\n\tvar listStr string\n\tvar number uint32\n\tif err := json.Unmarshal(data, &listStr); err != nil {\n\t\tif err2 := json.Unmarshal(data, &number); err2 != nil {\n\t\t\treturn newError(\"invalid port: \", string(data)).Base(err2)\n\t\t}\n\t}\n\trangelist := strings.Split(listStr, \",\")\n\tfor _, rangeStr := range rangelist {\n\t\ttrimmed := strings.TrimSpace(rangeStr)\n\t\tif len(trimmed) > 0 {\n\t\t\tif strings.Contains(trimmed, \"-\") {\n\t\t\t\tfrom, to, err := parseStringPort(trimmed)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn newError(\"invalid port range: \", trimmed).Base(err)\n\t\t\t\t}\n\t\t\t\tlist.Range = append(list.Range, PortRange{From: uint32(from), To: uint32(to)})\n\t\t\t} else {\n\t\t\t\tport, err := parseIntPort([]byte(trimmed))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn newError(\"invalid port: \", trimmed).Base(err)\n\t\t\t\t}\n\t\t\t\tlist.Range = append(list.Range, PortRange{From: uint32(port), To: uint32(port)})\n\t\t\t}\n\t\t}\n\t}\n\tif number != 0 {\n\t\tlist.Range = append(list.Range, PortRange{From: uint32(number), To: uint32(number)})\n\t}\n\treturn nil\n}\n\ntype User struct {\n\tEmailString string `json:\"email\"`\n\tLevelByte   byte   `json:\"level\"`\n}\n\nfunc (v *User) Build() *protocol.User {\n\treturn &protocol.User{\n\t\tEmail: v.EmailString,\n\t\tLevel: uint32(v.LevelByte),\n\t}\n}\n"
  },
  {
    "path": "infra/conf/common_test.go",
    "content": "package conf_test\n\nimport (\n\t\"encoding/json\"\n\t\"github.com/google/go-cmp/cmp/cmpopts\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"v2ray.com/core/common/protocol\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/net\"\n\t. \"v2ray.com/core/infra/conf\"\n)\n\nfunc TestStringListUnmarshalError(t *testing.T) {\n\trawJson := `1234`\n\tlist := new(StringList)\n\terr := json.Unmarshal([]byte(rawJson), list)\n\tif err == nil {\n\t\tt.Error(\"expected error, but got nil\")\n\t}\n}\n\nfunc TestStringListLen(t *testing.T) {\n\trawJson := `\"a, b, c, d\"`\n\tvar list StringList\n\terr := json.Unmarshal([]byte(rawJson), &list)\n\tcommon.Must(err)\n\tif r := cmp.Diff([]string(list), []string{\"a\", \" b\", \" c\", \" d\"}); r != \"\" {\n\t\tt.Error(r)\n\t}\n}\n\nfunc TestIPParsing(t *testing.T) {\n\trawJson := \"\\\"8.8.8.8\\\"\"\n\tvar address Address\n\terr := json.Unmarshal([]byte(rawJson), &address)\n\tcommon.Must(err)\n\tif r := cmp.Diff(address.IP(), net.IP{8, 8, 8, 8}); r != \"\" {\n\t\tt.Error(r)\n\t}\n}\n\nfunc TestDomainParsing(t *testing.T) {\n\trawJson := \"\\\"v2ray.com\\\"\"\n\tvar address Address\n\tcommon.Must(json.Unmarshal([]byte(rawJson), &address))\n\tif address.Domain() != \"v2ray.com\" {\n\t\tt.Error(\"domain: \", address.Domain())\n\t}\n}\n\nfunc TestURLParsing(t *testing.T) {\n\t{\n\t\trawJson := \"\\\"https://dns.google/dns-query\\\"\"\n\t\tvar address Address\n\t\tcommon.Must(json.Unmarshal([]byte(rawJson), &address))\n\t\tif address.Domain() != \"https://dns.google/dns-query\" {\n\t\t\tt.Error(\"URL: \", address.Domain())\n\t\t}\n\t}\n\t{\n\t\trawJson := \"\\\"https+local://dns.google/dns-query\\\"\"\n\t\tvar address Address\n\t\tcommon.Must(json.Unmarshal([]byte(rawJson), &address))\n\t\tif address.Domain() != \"https+local://dns.google/dns-query\" {\n\t\t\tt.Error(\"URL: \", address.Domain())\n\t\t}\n\t}\n}\n\nfunc TestInvalidAddressJson(t *testing.T) {\n\trawJson := \"1234\"\n\tvar address Address\n\terr := json.Unmarshal([]byte(rawJson), &address)\n\tif err == nil {\n\t\tt.Error(\"nil error\")\n\t}\n}\n\nfunc TestStringNetwork(t *testing.T) {\n\tvar network Network\n\tcommon.Must(json.Unmarshal([]byte(`\"tcp\"`), &network))\n\tif v := network.Build(); v != net.Network_TCP {\n\t\tt.Error(\"network: \", v)\n\t}\n}\n\nfunc TestArrayNetworkList(t *testing.T) {\n\tvar list NetworkList\n\tcommon.Must(json.Unmarshal([]byte(\"[\\\"Tcp\\\"]\"), &list))\n\n\tnlist := list.Build()\n\tif !net.HasNetwork(nlist, net.Network_TCP) {\n\t\tt.Error(\"no tcp network\")\n\t}\n\tif net.HasNetwork(nlist, net.Network_UDP) {\n\t\tt.Error(\"has udp network\")\n\t}\n}\n\nfunc TestStringNetworkList(t *testing.T) {\n\tvar list NetworkList\n\tcommon.Must(json.Unmarshal([]byte(\"\\\"TCP, ip\\\"\"), &list))\n\n\tnlist := list.Build()\n\tif !net.HasNetwork(nlist, net.Network_TCP) {\n\t\tt.Error(\"no tcp network\")\n\t}\n\tif net.HasNetwork(nlist, net.Network_UDP) {\n\t\tt.Error(\"has udp network\")\n\t}\n}\n\nfunc TestInvalidNetworkJson(t *testing.T) {\n\tvar list NetworkList\n\terr := json.Unmarshal([]byte(\"0\"), &list)\n\tif err == nil {\n\t\tt.Error(\"nil error\")\n\t}\n}\n\nfunc TestIntPort(t *testing.T) {\n\tvar portRange PortRange\n\tcommon.Must(json.Unmarshal([]byte(\"1234\"), &portRange))\n\n\tif r := cmp.Diff(portRange, PortRange{\n\t\tFrom: 1234, To: 1234,\n\t}); r != \"\" {\n\t\tt.Error(r)\n\t}\n}\n\nfunc TestOverRangeIntPort(t *testing.T) {\n\tvar portRange PortRange\n\terr := json.Unmarshal([]byte(\"70000\"), &portRange)\n\tif err == nil {\n\t\tt.Error(\"nil error\")\n\t}\n\n\terr = json.Unmarshal([]byte(\"-1\"), &portRange)\n\tif err == nil {\n\t\tt.Error(\"nil error\")\n\t}\n}\n\nfunc TestEnvPort(t *testing.T) {\n\tcommon.Must(os.Setenv(\"PORT\", \"1234\"))\n\n\tvar portRange PortRange\n\tcommon.Must(json.Unmarshal([]byte(\"\\\"env:PORT\\\"\"), &portRange))\n\n\tif r := cmp.Diff(portRange, PortRange{\n\t\tFrom: 1234, To: 1234,\n\t}); r != \"\" {\n\t\tt.Error(r)\n\t}\n}\n\nfunc TestSingleStringPort(t *testing.T) {\n\tvar portRange PortRange\n\tcommon.Must(json.Unmarshal([]byte(\"\\\"1234\\\"\"), &portRange))\n\n\tif r := cmp.Diff(portRange, PortRange{\n\t\tFrom: 1234, To: 1234,\n\t}); r != \"\" {\n\t\tt.Error(r)\n\t}\n}\n\nfunc TestStringPairPort(t *testing.T) {\n\tvar portRange PortRange\n\tcommon.Must(json.Unmarshal([]byte(\"\\\"1234-5678\\\"\"), &portRange))\n\n\tif r := cmp.Diff(portRange, PortRange{\n\t\tFrom: 1234, To: 5678,\n\t}); r != \"\" {\n\t\tt.Error(r)\n\t}\n}\n\nfunc TestOverRangeStringPort(t *testing.T) {\n\tvar portRange PortRange\n\terr := json.Unmarshal([]byte(\"\\\"65536\\\"\"), &portRange)\n\tif err == nil {\n\t\tt.Error(\"nil error\")\n\t}\n\n\terr = json.Unmarshal([]byte(\"\\\"70000-80000\\\"\"), &portRange)\n\tif err == nil {\n\t\tt.Error(\"nil error\")\n\t}\n\n\terr = json.Unmarshal([]byte(\"\\\"1-90000\\\"\"), &portRange)\n\tif err == nil {\n\t\tt.Error(\"nil error\")\n\t}\n\n\terr = json.Unmarshal([]byte(\"\\\"700-600\\\"\"), &portRange)\n\tif err == nil {\n\t\tt.Error(\"nil error\")\n\t}\n}\n\nfunc TestUserParsing(t *testing.T) {\n\tuser := new(User)\n\tcommon.Must(json.Unmarshal([]byte(`{\n    \"id\": \"96edb838-6d68-42ef-a933-25f7ac3a9d09\",\n    \"email\": \"love@v2ray.com\",\n    \"level\": 1,\n    \"alterId\": 100\n  }`), user))\n\n\tnUser := user.Build()\n\tif r := cmp.Diff(nUser, &protocol.User{\n\t\tLevel: 1,\n\t\tEmail: \"love@v2ray.com\",\n\t}, cmpopts.IgnoreUnexported(protocol.User{})); r != \"\" {\n\t\tt.Error(r)\n\t}\n}\n\nfunc TestInvalidUserJson(t *testing.T) {\n\tuser := new(User)\n\terr := json.Unmarshal([]byte(`{\"email\": 1234}`), user)\n\tif err == nil {\n\t\tt.Error(\"nil error\")\n\t}\n}\n"
  },
  {
    "path": "infra/conf/conf.go",
    "content": "package conf\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n"
  },
  {
    "path": "infra/conf/dns.go",
    "content": "package conf\n\nimport (\n\t\"encoding/json\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"v2ray.com/core/app/dns\"\n\t\"v2ray.com/core/app/router\"\n\t\"v2ray.com/core/common/net\"\n)\n\ntype NameServerConfig struct {\n\tAddress   *Address\n\tPort      uint16\n\tDomains   []string\n\tExpectIPs StringList\n}\n\nfunc (c *NameServerConfig) UnmarshalJSON(data []byte) error {\n\tvar address Address\n\tif err := json.Unmarshal(data, &address); err == nil {\n\t\tc.Address = &address\n\t\treturn nil\n\t}\n\n\tvar advanced struct {\n\t\tAddress   *Address   `json:\"address\"`\n\t\tPort      uint16     `json:\"port\"`\n\t\tDomains   []string   `json:\"domains\"`\n\t\tExpectIPs StringList `json:\"expectIps\"`\n\t}\n\tif err := json.Unmarshal(data, &advanced); err == nil {\n\t\tc.Address = advanced.Address\n\t\tc.Port = advanced.Port\n\t\tc.Domains = advanced.Domains\n\t\tc.ExpectIPs = advanced.ExpectIPs\n\t\treturn nil\n\t}\n\n\treturn newError(\"failed to parse name server: \", string(data))\n}\n\nfunc toDomainMatchingType(t router.Domain_Type) dns.DomainMatchingType {\n\tswitch t {\n\tcase router.Domain_Domain:\n\t\treturn dns.DomainMatchingType_Subdomain\n\tcase router.Domain_Full:\n\t\treturn dns.DomainMatchingType_Full\n\tcase router.Domain_Plain:\n\t\treturn dns.DomainMatchingType_Keyword\n\tcase router.Domain_Regex:\n\t\treturn dns.DomainMatchingType_Regex\n\tdefault:\n\t\tpanic(\"unknown domain type\")\n\t}\n}\n\nfunc (c *NameServerConfig) Build() (*dns.NameServer, error) {\n\tif c.Address == nil {\n\t\treturn nil, newError(\"NameServer address is not specified.\")\n\t}\n\n\tvar domains []*dns.NameServer_PriorityDomain\n\tvar originalRules []*dns.NameServer_OriginalRule\n\n\tfor _, rule := range c.Domains {\n\t\tparsedDomain, err := parseDomainRule(rule)\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"invalid domain rule: \", rule).Base(err)\n\t\t}\n\n\t\tfor _, pd := range parsedDomain {\n\t\t\tdomains = append(domains, &dns.NameServer_PriorityDomain{\n\t\t\t\tType:   toDomainMatchingType(pd.Type),\n\t\t\t\tDomain: pd.Value,\n\t\t\t})\n\t\t}\n\t\toriginalRules = append(originalRules, &dns.NameServer_OriginalRule{\n\t\t\tRule: rule,\n\t\t\tSize: uint32(len(parsedDomain)),\n\t\t})\n\t}\n\n\tgeoipList, err := toCidrList(c.ExpectIPs)\n\tif err != nil {\n\t\treturn nil, newError(\"invalid ip rule: \", c.ExpectIPs).Base(err)\n\t}\n\n\treturn &dns.NameServer{\n\t\tAddress: &net.Endpoint{\n\t\t\tNetwork: net.Network_UDP,\n\t\t\tAddress: c.Address.Build(),\n\t\t\tPort:    uint32(c.Port),\n\t\t},\n\t\tPrioritizedDomain: domains,\n\t\tGeoip:             geoipList,\n\t\tOriginalRules:     originalRules,\n\t}, nil\n}\n\nvar typeMap = map[router.Domain_Type]dns.DomainMatchingType{\n\trouter.Domain_Full:   dns.DomainMatchingType_Full,\n\trouter.Domain_Domain: dns.DomainMatchingType_Subdomain,\n\trouter.Domain_Plain:  dns.DomainMatchingType_Keyword,\n\trouter.Domain_Regex:  dns.DomainMatchingType_Regex,\n}\n\n// DnsConfig is a JSON serializable object for dns.Config.\ntype DnsConfig struct {\n\tServers  []*NameServerConfig `json:\"servers\"`\n\tHosts    map[string]*Address `json:\"hosts\"`\n\tClientIP *Address            `json:\"clientIp\"`\n\tTag      string              `json:\"tag\"`\n}\n\nfunc getHostMapping(addr *Address) *dns.Config_HostMapping {\n\tif addr.Family().IsIP() {\n\t\treturn &dns.Config_HostMapping{\n\t\t\tIp: [][]byte{[]byte(addr.IP())},\n\t\t}\n\t} else {\n\t\treturn &dns.Config_HostMapping{\n\t\t\tProxiedDomain: addr.Domain(),\n\t\t}\n\t}\n}\n\n// Build implements Buildable\nfunc (c *DnsConfig) Build() (*dns.Config, error) {\n\tconfig := &dns.Config{\n\t\tTag: c.Tag,\n\t}\n\n\tif c.ClientIP != nil {\n\t\tif !c.ClientIP.Family().IsIP() {\n\t\t\treturn nil, newError(\"not an IP address:\", c.ClientIP.String())\n\t\t}\n\t\tconfig.ClientIp = []byte(c.ClientIP.IP())\n\t}\n\n\tfor _, server := range c.Servers {\n\t\tns, err := server.Build()\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"failed to build name server\").Base(err)\n\t\t}\n\t\tconfig.NameServer = append(config.NameServer, ns)\n\t}\n\n\tif c.Hosts != nil && len(c.Hosts) > 0 {\n\t\tdomains := make([]string, 0, len(c.Hosts))\n\t\tfor domain := range c.Hosts {\n\t\t\tdomains = append(domains, domain)\n\t\t}\n\t\tsort.Strings(domains)\n\t\tfor _, domain := range domains {\n\t\t\taddr := c.Hosts[domain]\n\t\t\tvar mappings []*dns.Config_HostMapping\n\t\t\tif strings.HasPrefix(domain, \"domain:\") {\n\t\t\t\tmapping := getHostMapping(addr)\n\t\t\t\tmapping.Type = dns.DomainMatchingType_Subdomain\n\t\t\t\tmapping.Domain = domain[7:]\n\n\t\t\t\tmappings = append(mappings, mapping)\n\t\t\t} else if strings.HasPrefix(domain, \"geosite:\") {\n\t\t\t\tdomains, err := loadGeositeWithAttr(\"geosite.dat\", strings.ToUpper(domain[8:]))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, newError(\"invalid geosite settings: \", domain).Base(err)\n\t\t\t\t}\n\t\t\t\tfor _, d := range domains {\n\t\t\t\t\tmapping := getHostMapping(addr)\n\t\t\t\t\tmapping.Type = typeMap[d.Type]\n\t\t\t\t\tmapping.Domain = d.Value\n\n\t\t\t\t\tmappings = append(mappings, mapping)\n\t\t\t\t}\n\t\t\t} else if strings.HasPrefix(domain, \"regexp:\") {\n\t\t\t\tmapping := getHostMapping(addr)\n\t\t\t\tmapping.Type = dns.DomainMatchingType_Regex\n\t\t\t\tmapping.Domain = domain[7:]\n\n\t\t\t\tmappings = append(mappings, mapping)\n\t\t\t} else if strings.HasPrefix(domain, \"keyword:\") {\n\t\t\t\tmapping := getHostMapping(addr)\n\t\t\t\tmapping.Type = dns.DomainMatchingType_Keyword\n\t\t\t\tmapping.Domain = domain[8:]\n\n\t\t\t\tmappings = append(mappings, mapping)\n\t\t\t} else if strings.HasPrefix(domain, \"full:\") {\n\t\t\t\tmapping := getHostMapping(addr)\n\t\t\t\tmapping.Type = dns.DomainMatchingType_Full\n\t\t\t\tmapping.Domain = domain[5:]\n\n\t\t\t\tmappings = append(mappings, mapping)\n\t\t\t} else if strings.HasPrefix(domain, \"dotless:\") {\n\t\t\t\tmapping := getHostMapping(addr)\n\t\t\t\tmapping.Type = dns.DomainMatchingType_Regex\n\t\t\t\tswitch substr := domain[8:]; {\n\t\t\t\tcase substr == \"\":\n\t\t\t\t\tmapping.Domain = \"^[^.]*$\"\n\t\t\t\tcase !strings.Contains(substr, \".\"):\n\t\t\t\t\tmapping.Domain = \"^[^.]*\" + substr + \"[^.]*$\"\n\t\t\t\tdefault:\n\t\t\t\t\treturn nil, newError(\"substr in dotless rule should not contain a dot: \", substr)\n\t\t\t\t}\n\n\t\t\t\tmappings = append(mappings, mapping)\n\t\t\t} else if strings.HasPrefix(domain, \"ext:\") {\n\t\t\t\tkv := strings.Split(domain[4:], \":\")\n\t\t\t\tif len(kv) != 2 {\n\t\t\t\t\treturn nil, newError(\"invalid external resource: \", domain)\n\t\t\t\t}\n\t\t\t\tfilename := kv[0]\n\t\t\t\tcountry := kv[1]\n\t\t\t\tdomains, err := loadGeositeWithAttr(filename, country)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, newError(\"failed to load domains: \", country, \" from \", filename).Base(err)\n\t\t\t\t}\n\t\t\t\tfor _, d := range domains {\n\t\t\t\t\tmapping := getHostMapping(addr)\n\t\t\t\t\tmapping.Type = typeMap[d.Type]\n\t\t\t\t\tmapping.Domain = d.Value\n\n\t\t\t\t\tmappings = append(mappings, mapping)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tmapping := getHostMapping(addr)\n\t\t\t\tmapping.Type = dns.DomainMatchingType_Full\n\t\t\t\tmapping.Domain = domain\n\n\t\t\t\tmappings = append(mappings, mapping)\n\t\t\t}\n\n\t\t\tconfig.StaticHosts = append(config.StaticHosts, mappings...)\n\t\t}\n\t}\n\n\treturn config, nil\n}\n"
  },
  {
    "path": "infra/conf/dns_proxy.go",
    "content": "package conf\n\nimport (\n\t\"github.com/golang/protobuf/proto\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/proxy/dns\"\n)\n\ntype DnsOutboundConfig struct {\n\tNetwork Network  `json:\"network\"`\n\tAddress *Address `json:\"address\"`\n\tPort    uint16   `json:\"port\"`\n}\n\nfunc (c *DnsOutboundConfig) Build() (proto.Message, error) {\n\tconfig := &dns.Config{\n\t\tServer: &net.Endpoint{\n\t\t\tNetwork: c.Network.Build(),\n\t\t\tPort:    uint32(c.Port),\n\t\t},\n\t}\n\tif c.Address != nil {\n\t\tconfig.Server.Address = c.Address.Build()\n\t}\n\treturn config, nil\n}\n"
  },
  {
    "path": "infra/conf/dns_proxy_test.go",
    "content": "package conf_test\n\nimport (\n\t\"testing\"\n\n\t\"v2ray.com/core/common/net\"\n\t. \"v2ray.com/core/infra/conf\"\n\t\"v2ray.com/core/proxy/dns\"\n)\n\nfunc TestDnsProxyConfig(t *testing.T) {\n\tcreator := func() Buildable {\n\t\treturn new(DnsOutboundConfig)\n\t}\n\n\trunMultiTestCase(t, []TestCase{\n\t\t{\n\t\t\tInput: `{\n\t\t\t\t\"address\": \"8.8.8.8\",\n\t\t\t\t\"port\": 53,\n\t\t\t\t\"network\": \"tcp\"\n\t\t\t}`,\n\t\t\tParser: loadJSON(creator),\n\t\t\tOutput: &dns.Config{\n\t\t\t\tServer: &net.Endpoint{\n\t\t\t\t\tNetwork: net.Network_TCP,\n\t\t\t\t\tAddress: net.NewIPOrDomain(net.IPAddress([]byte{8, 8, 8, 8})),\n\t\t\t\t\tPort:    53,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "infra/conf/dns_test.go",
    "content": "package conf_test\n\nimport (\n\t\"encoding/json\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/golang/protobuf/proto\"\n\t\"v2ray.com/core/app/dns\"\n\t\"v2ray.com/core/app/router\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/platform\"\n\t\"v2ray.com/core/common/platform/filesystem\"\n\t. \"v2ray.com/core/infra/conf\"\n)\n\nfunc init() {\n\twd, err := os.Getwd()\n\tcommon.Must(err)\n\n\tif _, err := os.Stat(platform.GetAssetLocation(\"geoip.dat\")); err != nil && os.IsNotExist(err) {\n\t\tcommon.Must(filesystem.CopyFile(platform.GetAssetLocation(\"geoip.dat\"), filepath.Join(wd, \"..\", \"..\", \"release\", \"config\", \"geoip.dat\")))\n\t}\n\n\tgeositeFilePath := filepath.Join(wd, \"geosite.dat\")\n\tos.Setenv(\"v2ray.location.asset\", wd)\n\tgeositeFile, err := os.OpenFile(geositeFilePath, os.O_CREATE|os.O_WRONLY, 0600)\n\tcommon.Must(err)\n\tdefer geositeFile.Close()\n\n\tlist := &router.GeoSiteList{\n\t\tEntry: []*router.GeoSite{\n\t\t\t{\n\t\t\t\tCountryCode: \"TEST\",\n\t\t\t\tDomain: []*router.Domain{\n\t\t\t\t\t{Type: router.Domain_Full, Value: \"example.com\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tlistBytes, err := proto.Marshal(list)\n\tcommon.Must(err)\n\tcommon.Must2(geositeFile.Write(listBytes))\n}\nfunc TestDnsConfigParsing(t *testing.T) {\n\tgeositePath := platform.GetAssetLocation(\"geosite.dat\")\n\tdefer func() {\n\t\tos.Remove(geositePath)\n\t\tos.Unsetenv(\"v2ray.location.asset\")\n\t}()\n\n\tparserCreator := func() func(string) (proto.Message, error) {\n\t\treturn func(s string) (proto.Message, error) {\n\t\t\tconfig := new(DnsConfig)\n\t\t\tif err := json.Unmarshal([]byte(s), config); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn config.Build()\n\t\t}\n\t}\n\n\trunMultiTestCase(t, []TestCase{\n\t\t{\n\t\t\tInput: `{\n\t\t\t\t\"servers\": [{\n\t\t\t\t\t\"address\": \"8.8.8.8\",\n\t\t\t\t\t\"port\": 5353,\n\t\t\t\t\t\"domains\": [\"domain:v2ray.com\"]\n\t\t\t\t}],\n\t\t\t\t\"hosts\": {\n\t\t\t\t\t\"v2ray.com\": \"127.0.0.1\",\n\t\t\t\t\t\"domain:example.com\": \"google.com\",\n\t\t\t\t\t\"geosite:test\": \"10.0.0.1\",\n\t\t\t\t\t\"keyword:google\": \"8.8.8.8\",\n\t\t\t\t\t\"regexp:.*\\\\.com\": \"8.8.4.4\"\n\t\t\t\t},\n\t\t\t\t\"clientIp\": \"10.0.0.1\"\n\t\t\t}`,\n\t\t\tParser: parserCreator(),\n\t\t\tOutput: &dns.Config{\n\t\t\t\tNameServer: []*dns.NameServer{\n\t\t\t\t\t{\n\t\t\t\t\t\tAddress: &net.Endpoint{\n\t\t\t\t\t\t\tAddress: &net.IPOrDomain{\n\t\t\t\t\t\t\t\tAddress: &net.IPOrDomain_Ip{\n\t\t\t\t\t\t\t\t\tIp: []byte{8, 8, 8, 8},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tNetwork: net.Network_UDP,\n\t\t\t\t\t\t\tPort:    5353,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tPrioritizedDomain: []*dns.NameServer_PriorityDomain{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tType:   dns.DomainMatchingType_Subdomain,\n\t\t\t\t\t\t\t\tDomain: \"v2ray.com\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tOriginalRules: []*dns.NameServer_OriginalRule{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tRule: \"domain:v2ray.com\",\n\t\t\t\t\t\t\t\tSize: 1,\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\tStaticHosts: []*dns.Config_HostMapping{\n\t\t\t\t\t{\n\t\t\t\t\t\tType:          dns.DomainMatchingType_Subdomain,\n\t\t\t\t\t\tDomain:        \"example.com\",\n\t\t\t\t\t\tProxiedDomain: \"google.com\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tType:   dns.DomainMatchingType_Full,\n\t\t\t\t\t\tDomain: \"example.com\",\n\t\t\t\t\t\tIp:     [][]byte{{10, 0, 0, 1}},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tType:   dns.DomainMatchingType_Keyword,\n\t\t\t\t\t\tDomain: \"google\",\n\t\t\t\t\t\tIp:     [][]byte{{8, 8, 8, 8}},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tType:   dns.DomainMatchingType_Regex,\n\t\t\t\t\t\tDomain: \".*\\\\.com\",\n\t\t\t\t\t\tIp:     [][]byte{{8, 8, 4, 4}},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tType:   dns.DomainMatchingType_Full,\n\t\t\t\t\t\tDomain: \"v2ray.com\",\n\t\t\t\t\t\tIp:     [][]byte{{127, 0, 0, 1}},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClientIp: []byte{10, 0, 0, 1},\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "infra/conf/dokodemo.go",
    "content": "package conf\n\nimport (\n\t\"github.com/golang/protobuf/proto\"\n\t\"v2ray.com/core/proxy/dokodemo\"\n)\n\ntype DokodemoConfig struct {\n\tHost         *Address     `json:\"address\"`\n\tPortValue    uint16       `json:\"port\"`\n\tNetworkList  *NetworkList `json:\"network\"`\n\tTimeoutValue uint32       `json:\"timeout\"`\n\tRedirect     bool         `json:\"followRedirect\"`\n\tUserLevel    uint32       `json:\"userLevel\"`\n}\n\nfunc (v *DokodemoConfig) Build() (proto.Message, error) {\n\tconfig := new(dokodemo.Config)\n\tif v.Host != nil {\n\t\tconfig.Address = v.Host.Build()\n\t}\n\tconfig.Port = uint32(v.PortValue)\n\tconfig.Networks = v.NetworkList.Build()\n\tconfig.Timeout = v.TimeoutValue\n\tconfig.FollowRedirect = v.Redirect\n\tconfig.UserLevel = v.UserLevel\n\treturn config, nil\n}\n"
  },
  {
    "path": "infra/conf/dokodemo_test.go",
    "content": "package conf_test\n\nimport (\n\t\"testing\"\n\n\t\"v2ray.com/core/common/net\"\n\t. \"v2ray.com/core/infra/conf\"\n\t\"v2ray.com/core/proxy/dokodemo\"\n)\n\nfunc TestDokodemoConfig(t *testing.T) {\n\tcreator := func() Buildable {\n\t\treturn new(DokodemoConfig)\n\t}\n\n\trunMultiTestCase(t, []TestCase{\n\t\t{\n\t\t\tInput: `{\n\t\t\t\t\"address\": \"8.8.8.8\",\n\t\t\t\t\"port\": 53,\n\t\t\t\t\"network\": \"tcp\",\n\t\t\t\t\"timeout\": 10,\n\t\t\t\t\"followRedirect\": true,\n\t\t\t\t\"userLevel\": 1\n\t\t\t}`,\n\t\t\tParser: loadJSON(creator),\n\t\t\tOutput: &dokodemo.Config{\n\t\t\t\tAddress: &net.IPOrDomain{\n\t\t\t\t\tAddress: &net.IPOrDomain_Ip{\n\t\t\t\t\t\tIp: []byte{8, 8, 8, 8},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tPort:           53,\n\t\t\t\tNetworks:       []net.Network{net.Network_TCP},\n\t\t\t\tTimeout:        10,\n\t\t\t\tFollowRedirect: true,\n\t\t\t\tUserLevel:      1,\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "infra/conf/errors.generated.go",
    "content": "package conf\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "infra/conf/freedom.go",
    "content": "package conf\n\nimport (\n\t\"net\"\n\t\"strings\"\n\n\t\"github.com/golang/protobuf/proto\"\n\tv2net \"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/proxy/freedom\"\n)\n\ntype FreedomConfig struct {\n\tDomainStrategy string  `json:\"domainStrategy\"`\n\tTimeout        *uint32 `json:\"timeout\"`\n\tRedirect       string  `json:\"redirect\"`\n\tUserLevel      uint32  `json:\"userLevel\"`\n}\n\n// Build implements Buildable\nfunc (c *FreedomConfig) Build() (proto.Message, error) {\n\tconfig := new(freedom.Config)\n\tconfig.DomainStrategy = freedom.Config_AS_IS\n\tswitch strings.ToLower(c.DomainStrategy) {\n\tcase \"useip\", \"use_ip\":\n\t\tconfig.DomainStrategy = freedom.Config_USE_IP\n\tcase \"useip4\", \"useipv4\", \"use_ipv4\", \"use_ip_v4\", \"use_ip4\":\n\t\tconfig.DomainStrategy = freedom.Config_USE_IP4\n\tcase \"useip6\", \"useipv6\", \"use_ipv6\", \"use_ip_v6\", \"use_ip6\":\n\t\tconfig.DomainStrategy = freedom.Config_USE_IP6\n\t}\n\n\tif c.Timeout != nil {\n\t\tconfig.Timeout = *c.Timeout\n\t}\n\tconfig.UserLevel = c.UserLevel\n\tif len(c.Redirect) > 0 {\n\t\thost, portStr, err := net.SplitHostPort(c.Redirect)\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"invalid redirect address: \", c.Redirect, \": \", err).Base(err)\n\t\t}\n\t\tport, err := v2net.PortFromString(portStr)\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"invalid redirect port: \", c.Redirect, \": \", err).Base(err)\n\t\t}\n\t\tconfig.DestinationOverride = &freedom.DestinationOverride{\n\t\t\tServer: &protocol.ServerEndpoint{\n\t\t\t\tPort: uint32(port),\n\t\t\t},\n\t\t}\n\n\t\tif len(host) > 0 {\n\t\t\tconfig.DestinationOverride.Server.Address = v2net.NewIPOrDomain(v2net.ParseAddress(host))\n\t\t}\n\t}\n\treturn config, nil\n}\n"
  },
  {
    "path": "infra/conf/freedom_test.go",
    "content": "package conf_test\n\nimport (\n\t\"testing\"\n\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t. \"v2ray.com/core/infra/conf\"\n\t\"v2ray.com/core/proxy/freedom\"\n)\n\nfunc TestFreedomConfig(t *testing.T) {\n\tcreator := func() Buildable {\n\t\treturn new(FreedomConfig)\n\t}\n\n\trunMultiTestCase(t, []TestCase{\n\t\t{\n\t\t\tInput: `{\n\t\t\t\t\"domainStrategy\": \"AsIs\",\n\t\t\t\t\"timeout\": 10,\n\t\t\t\t\"redirect\": \"127.0.0.1:3366\",\n\t\t\t\t\"userLevel\": 1\n\t\t\t}`,\n\t\t\tParser: loadJSON(creator),\n\t\t\tOutput: &freedom.Config{\n\t\t\t\tDomainStrategy: freedom.Config_AS_IS,\n\t\t\t\tTimeout:        10,\n\t\t\t\tDestinationOverride: &freedom.DestinationOverride{\n\t\t\t\t\tServer: &protocol.ServerEndpoint{\n\t\t\t\t\t\tAddress: &net.IPOrDomain{\n\t\t\t\t\t\t\tAddress: &net.IPOrDomain_Ip{\n\t\t\t\t\t\t\t\tIp: []byte{127, 0, 0, 1},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tPort: 3366,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tUserLevel: 1,\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "infra/conf/general_test.go",
    "content": "package conf_test\n\nimport (\n\t\"encoding/json\"\n\t\"testing\"\n\n\t\"github.com/golang/protobuf/proto\"\n\t\"v2ray.com/core/common\"\n\t. \"v2ray.com/core/infra/conf\"\n)\n\nfunc loadJSON(creator func() Buildable) func(string) (proto.Message, error) {\n\treturn func(s string) (proto.Message, error) {\n\t\tinstance := creator()\n\t\tif err := json.Unmarshal([]byte(s), instance); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn instance.Build()\n\t}\n}\n\ntype TestCase struct {\n\tInput  string\n\tParser func(string) (proto.Message, error)\n\tOutput proto.Message\n}\n\nfunc runMultiTestCase(t *testing.T, testCases []TestCase) {\n\tfor _, testCase := range testCases {\n\t\tactual, err := testCase.Parser(testCase.Input)\n\t\tcommon.Must(err)\n\t\tif !proto.Equal(actual, testCase.Output) {\n\t\t\tt.Fatalf(\"Failed in test case:\\n%s\\nActual:\\n%v\\nExpected:\\n%v\", testCase.Input, actual, testCase.Output)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "infra/conf/http.go",
    "content": "package conf\n\nimport (\n\t\"encoding/json\"\n\n\t\"github.com/golang/protobuf/proto\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/serial\"\n\t\"v2ray.com/core/proxy/http\"\n)\n\ntype HttpAccount struct {\n\tUsername string `json:\"user\"`\n\tPassword string `json:\"pass\"`\n}\n\nfunc (v *HttpAccount) Build() *http.Account {\n\treturn &http.Account{\n\t\tUsername: v.Username,\n\t\tPassword: v.Password,\n\t}\n}\n\ntype HttpServerConfig struct {\n\tTimeout     uint32         `json:\"timeout\"`\n\tAccounts    []*HttpAccount `json:\"accounts\"`\n\tTransparent bool           `json:\"allowTransparent\"`\n\tUserLevel   uint32         `json:\"userLevel\"`\n}\n\nfunc (c *HttpServerConfig) Build() (proto.Message, error) {\n\tconfig := &http.ServerConfig{\n\t\tTimeout:          c.Timeout,\n\t\tAllowTransparent: c.Transparent,\n\t\tUserLevel:        c.UserLevel,\n\t}\n\n\tif len(c.Accounts) > 0 {\n\t\tconfig.Accounts = make(map[string]string)\n\t\tfor _, account := range c.Accounts {\n\t\t\tconfig.Accounts[account.Username] = account.Password\n\t\t}\n\t}\n\n\treturn config, nil\n}\n\ntype HttpRemoteConfig struct {\n\tAddress *Address          `json:\"address\"`\n\tPort    uint16            `json:\"port\"`\n\tUsers   []json.RawMessage `json:\"users\"`\n}\ntype HttpClientConfig struct {\n\tServers []*HttpRemoteConfig `json:\"servers\"`\n}\n\nfunc (v *HttpClientConfig) Build() (proto.Message, error) {\n\tconfig := new(http.ClientConfig)\n\tconfig.Server = make([]*protocol.ServerEndpoint, len(v.Servers))\n\tfor idx, serverConfig := range v.Servers {\n\t\tserver := &protocol.ServerEndpoint{\n\t\t\tAddress: serverConfig.Address.Build(),\n\t\t\tPort:    uint32(serverConfig.Port),\n\t\t}\n\t\tfor _, rawUser := range serverConfig.Users {\n\t\t\tuser := new(protocol.User)\n\t\t\tif err := json.Unmarshal(rawUser, user); err != nil {\n\t\t\t\treturn nil, newError(\"failed to parse HTTP user\").Base(err).AtError()\n\t\t\t}\n\t\t\taccount := new(HttpAccount)\n\t\t\tif err := json.Unmarshal(rawUser, account); err != nil {\n\t\t\t\treturn nil, newError(\"failed to parse HTTP account\").Base(err).AtError()\n\t\t\t}\n\t\t\tuser.Account = serial.ToTypedMessage(account.Build())\n\t\t\tserver.User = append(server.User, user)\n\t\t}\n\t\tconfig.Server[idx] = server\n\t}\n\treturn config, nil\n}\n"
  },
  {
    "path": "infra/conf/http_test.go",
    "content": "package conf_test\n\nimport (\n\t\"testing\"\n\n\t. \"v2ray.com/core/infra/conf\"\n\t\"v2ray.com/core/proxy/http\"\n)\n\nfunc TestHttpServerConfig(t *testing.T) {\n\tcreator := func() Buildable {\n\t\treturn new(HttpServerConfig)\n\t}\n\n\trunMultiTestCase(t, []TestCase{\n\t\t{\n\t\t\tInput: `{\n\t\t\t\t\"timeout\": 10,\n\t\t\t\t\"accounts\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"user\": \"my-username\",\n\t\t\t\t\t\t\"pass\": \"my-password\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"allowTransparent\": true,\n\t\t\t\t\"userLevel\": 1\n\t\t\t}`,\n\t\t\tParser: loadJSON(creator),\n\t\t\tOutput: &http.ServerConfig{\n\t\t\t\tAccounts: map[string]string{\n\t\t\t\t\t\"my-username\": \"my-password\",\n\t\t\t\t},\n\t\t\t\tAllowTransparent: true,\n\t\t\t\tUserLevel:        1,\n\t\t\t\tTimeout:          10,\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "infra/conf/json/reader.go",
    "content": "package json\n\nimport (\n\t\"io\"\n\n\t\"v2ray.com/core/common/buf\"\n)\n\n// State is the internal state of parser.\ntype State byte\n\nconst (\n\tStateContent State = iota\n\tStateEscape\n\tStateDoubleQuote\n\tStateDoubleQuoteEscape\n\tStateSingleQuote\n\tStateSingleQuoteEscape\n\tStateComment\n\tStateSlash\n\tStateMultilineComment\n\tStateMultilineCommentStar\n)\n\n// Reader is a reader for filtering comments.\n// It supports Java style single and multi line comment syntax, and Python style single line comment syntax.\ntype Reader struct {\n\tio.Reader\n\n\tstate State\n\tbr    *buf.BufferedReader\n}\n\n// Read implements io.Reader.Read(). Buffer must be at least 3 bytes.\nfunc (v *Reader) Read(b []byte) (int, error) {\n\tif v.br == nil {\n\t\tv.br = &buf.BufferedReader{Reader: buf.NewReader(v.Reader)}\n\t}\n\n\tp := b[:0]\n\tfor len(p) < len(b)-2 {\n\t\tx, err := v.br.ReadByte()\n\t\tif err != nil {\n\t\t\tif len(p) == 0 {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\treturn len(p), nil\n\t\t}\n\t\tswitch v.state {\n\t\tcase StateContent:\n\t\t\tswitch x {\n\t\t\tcase '\"':\n\t\t\t\tv.state = StateDoubleQuote\n\t\t\t\tp = append(p, x)\n\t\t\tcase '\\'':\n\t\t\t\tv.state = StateSingleQuote\n\t\t\t\tp = append(p, x)\n\t\t\tcase '\\\\':\n\t\t\t\tv.state = StateEscape\n\t\t\tcase '#':\n\t\t\t\tv.state = StateComment\n\t\t\tcase '/':\n\t\t\t\tv.state = StateSlash\n\t\t\tdefault:\n\t\t\t\tp = append(p, x)\n\t\t\t}\n\t\tcase StateEscape:\n\t\t\tp = append(p, '\\\\', x)\n\t\t\tv.state = StateContent\n\t\tcase StateDoubleQuote:\n\t\t\tswitch x {\n\t\t\tcase '\"':\n\t\t\t\tv.state = StateContent\n\t\t\t\tp = append(p, x)\n\t\t\tcase '\\\\':\n\t\t\t\tv.state = StateDoubleQuoteEscape\n\t\t\tdefault:\n\t\t\t\tp = append(p, x)\n\t\t\t}\n\t\tcase StateDoubleQuoteEscape:\n\t\t\tp = append(p, '\\\\', x)\n\t\t\tv.state = StateDoubleQuote\n\t\tcase StateSingleQuote:\n\t\t\tswitch x {\n\t\t\tcase '\\'':\n\t\t\t\tv.state = StateContent\n\t\t\t\tp = append(p, x)\n\t\t\tcase '\\\\':\n\t\t\t\tv.state = StateSingleQuoteEscape\n\t\t\tdefault:\n\t\t\t\tp = append(p, x)\n\t\t\t}\n\t\tcase StateSingleQuoteEscape:\n\t\t\tp = append(p, '\\\\', x)\n\t\t\tv.state = StateSingleQuote\n\t\tcase StateComment:\n\t\t\tif x == '\\n' {\n\t\t\t\tv.state = StateContent\n\t\t\t\tp = append(p, '\\n')\n\t\t\t}\n\t\tcase StateSlash:\n\t\t\tswitch x {\n\t\t\tcase '/':\n\t\t\t\tv.state = StateComment\n\t\t\tcase '*':\n\t\t\t\tv.state = StateMultilineComment\n\t\t\tdefault:\n\t\t\t\tp = append(p, '/', x)\n\t\t\t}\n\t\tcase StateMultilineComment:\n\t\t\tswitch x {\n\t\t\tcase '*':\n\t\t\t\tv.state = StateMultilineCommentStar\n\t\t\tcase '\\n':\n\t\t\t\tp = append(p, '\\n')\n\t\t\t}\n\t\tcase StateMultilineCommentStar:\n\t\t\tswitch x {\n\t\t\tcase '/':\n\t\t\t\tv.state = StateContent\n\t\t\tcase '*':\n\t\t\t\t// Stay\n\t\t\tcase '\\n':\n\t\t\t\tp = append(p, '\\n')\n\t\t\tdefault:\n\t\t\t\tv.state = StateMultilineComment\n\t\t\t}\n\t\tdefault:\n\t\t\tpanic(\"Unknown state.\")\n\t\t}\n\t}\n\treturn len(p), nil\n}\n"
  },
  {
    "path": "infra/conf/json/reader_test.go",
    "content": "package json_test\n\nimport (\n\t\"bytes\"\n\t\"io\"\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\n\t\"v2ray.com/core/common\"\n\t. \"v2ray.com/core/infra/conf/json\"\n)\n\nfunc TestReader(t *testing.T) {\n\tdata := []struct {\n\t\tinput  string\n\t\toutput string\n\t}{\n\t\t{\n\t\t\t`\ncontent #comment 1\n#comment 2\ncontent 2`,\n\t\t\t`\ncontent \n\ncontent 2`},\n\t\t{`content`, `content`},\n\t\t{\" \", \" \"},\n\t\t{`con/*abcd*/tent`, \"content\"},\n\t\t{`\ntext // adlkhdf /*\n//comment adfkj\ntext 2*/`, `\ntext \n\ntext 2*`},\n\t\t{`\"//\"content`, `\"//\"content`},\n\t\t{`abcd'//'abcd`, `abcd'//'abcd`},\n\t\t{`\"\\\"\"`, `\"\\\"\"`},\n\t\t{`\\\"/*abcd*/\\\"`, `\\\"\\\"`},\n\t}\n\n\tfor _, testCase := range data {\n\t\treader := &Reader{\n\t\t\tReader: bytes.NewReader([]byte(testCase.input)),\n\t\t}\n\n\t\tactual := make([]byte, 1024)\n\t\tn, err := reader.Read(actual)\n\t\tcommon.Must(err)\n\t\tif r := cmp.Diff(string(actual[:n]), testCase.output); r != \"\" {\n\t\t\tt.Error(r)\n\t\t}\n\t}\n}\n\nfunc TestReader1(t *testing.T) {\n\ttype dataStruct struct {\n\t\tinput  string\n\t\toutput string\n\t}\n\n\tbufLen := 8\n\n\tdata := []dataStruct{\n\t\t{\"loooooooooooooooooooooooooooooooooooooooog\", \"loooooooooooooooooooooooooooooooooooooooog\"},\n\t\t{`{\"t\": \"\\/testlooooooooooooooooooooooooooooong\"}`, `{\"t\": \"\\/testlooooooooooooooooooooooooooooong\"}`},\n\t\t{`{\"t\": \"\\/test\"}`, `{\"t\": \"\\/test\"}`},\n\t\t{`\"\\// fake comment\"`, `\"\\// fake comment\"`},\n\t\t{`\"\\/\\/\\/\\/\\/\"`, `\"\\/\\/\\/\\/\\/\"`},\n\t}\n\n\tfor _, testCase := range data {\n\t\treader := &Reader{\n\t\t\tReader: bytes.NewReader([]byte(testCase.input)),\n\t\t}\n\t\ttarget := make([]byte, 0)\n\t\tbuf := make([]byte, bufLen)\n\t\tvar n int\n\t\tvar err error\n\t\tfor n, err = reader.Read(buf); err == nil; n, err = reader.Read(buf) {\n\t\t\tif n > len(buf) {\n\t\t\t\tt.Error(\"n: \", n)\n\t\t\t}\n\t\t\ttarget = append(target, buf[:n]...)\n\t\t\tbuf = make([]byte, bufLen)\n\t\t}\n\t\tif err != nil && err != io.EOF {\n\t\t\tt.Error(\"error: \", err)\n\t\t}\n\t\tif string(target) != testCase.output {\n\t\t\tt.Error(\"got \", string(target), \" want \", testCase.output)\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "infra/conf/loader.go",
    "content": "package conf\n\nimport (\n\t\"encoding/json\"\n\t\"strings\"\n)\n\ntype ConfigCreator func() interface{}\n\ntype ConfigCreatorCache map[string]ConfigCreator\n\nfunc (v ConfigCreatorCache) RegisterCreator(id string, creator ConfigCreator) error {\n\tif _, found := v[id]; found {\n\t\treturn newError(id, \" already registered.\").AtError()\n\t}\n\n\tv[id] = creator\n\treturn nil\n}\n\nfunc (v ConfigCreatorCache) CreateConfig(id string) (interface{}, error) {\n\tcreator, found := v[id]\n\tif !found {\n\t\treturn nil, newError(\"unknown config id: \", id)\n\t}\n\treturn creator(), nil\n}\n\ntype JSONConfigLoader struct {\n\tcache     ConfigCreatorCache\n\tidKey     string\n\tconfigKey string\n}\n\nfunc NewJSONConfigLoader(cache ConfigCreatorCache, idKey string, configKey string) *JSONConfigLoader {\n\treturn &JSONConfigLoader{\n\t\tidKey:     idKey,\n\t\tconfigKey: configKey,\n\t\tcache:     cache,\n\t}\n}\n\nfunc (v *JSONConfigLoader) LoadWithID(raw []byte, id string) (interface{}, error) {\n\tid = strings.ToLower(id)\n\tconfig, err := v.cache.CreateConfig(id)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif err := json.Unmarshal(raw, config); err != nil {\n\t\treturn nil, err\n\t}\n\treturn config, nil\n}\n\nfunc (v *JSONConfigLoader) Load(raw []byte) (interface{}, string, error) {\n\tvar obj map[string]json.RawMessage\n\tif err := json.Unmarshal(raw, &obj); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\trawID, found := obj[v.idKey]\n\tif !found {\n\t\treturn nil, \"\", newError(v.idKey, \" not found in JSON context\").AtError()\n\t}\n\tvar id string\n\tif err := json.Unmarshal(rawID, &id); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\trawConfig := json.RawMessage(raw)\n\tif len(v.configKey) > 0 {\n\t\tconfigValue, found := obj[v.configKey]\n\t\tif found {\n\t\t\trawConfig = configValue\n\t\t} else {\n\t\t\t// Default to empty json object.\n\t\t\trawConfig = json.RawMessage([]byte(\"{}\"))\n\t\t}\n\t}\n\tconfig, err := v.LoadWithID([]byte(rawConfig), id)\n\tif err != nil {\n\t\treturn nil, id, err\n\t}\n\treturn config, id, nil\n}\n"
  },
  {
    "path": "infra/conf/log.go",
    "content": "package conf\n\nimport (\n\t\"strings\"\n\n\t\"v2ray.com/core/app/log\"\n\tclog \"v2ray.com/core/common/log\"\n)\n\nfunc DefaultLogConfig() *log.Config {\n\treturn &log.Config{\n\t\tAccessLogType: log.LogType_None,\n\t\tErrorLogType:  log.LogType_Console,\n\t\tErrorLogLevel: clog.Severity_Warning,\n\t}\n}\n\ntype LogConfig struct {\n\tAccessLog string `json:\"access\"`\n\tErrorLog  string `json:\"error\"`\n\tLogLevel  string `json:\"loglevel\"`\n}\n\nfunc (v *LogConfig) Build() *log.Config {\n\tif v == nil {\n\t\treturn nil\n\t}\n\tconfig := &log.Config{\n\t\tErrorLogType:  log.LogType_Console,\n\t\tAccessLogType: log.LogType_Console,\n\t}\n\n\tif v.AccessLog == \"none\" {\n\t\tconfig.AccessLogType = log.LogType_None\n\t} else if len(v.AccessLog) > 0 {\n\t\tconfig.AccessLogPath = v.AccessLog\n\t\tconfig.AccessLogType = log.LogType_File\n\t}\n\tif v.ErrorLog == \"none\" {\n\t\tconfig.ErrorLogType = log.LogType_None\n\t} else if len(v.ErrorLog) > 0 {\n\t\tconfig.ErrorLogPath = v.ErrorLog\n\t\tconfig.ErrorLogType = log.LogType_File\n\t}\n\n\tlevel := strings.ToLower(v.LogLevel)\n\tswitch level {\n\tcase \"debug\":\n\t\tconfig.ErrorLogLevel = clog.Severity_Debug\n\tcase \"info\":\n\t\tconfig.ErrorLogLevel = clog.Severity_Info\n\tcase \"error\":\n\t\tconfig.ErrorLogLevel = clog.Severity_Error\n\tcase \"none\":\n\t\tconfig.ErrorLogType = log.LogType_None\n\t\tconfig.AccessLogType = log.LogType_None\n\tdefault:\n\t\tconfig.ErrorLogLevel = clog.Severity_Warning\n\t}\n\treturn config\n}\n"
  },
  {
    "path": "infra/conf/mtproto.go",
    "content": "package conf\n\nimport (\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\n\t\"github.com/golang/protobuf/proto\"\n\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/serial\"\n\t\"v2ray.com/core/proxy/mtproto\"\n)\n\ntype MTProtoAccount struct {\n\tSecret string `json:\"secret\"`\n}\n\n// Build implements Buildable\nfunc (a *MTProtoAccount) Build() (*mtproto.Account, error) {\n\tif len(a.Secret) != 32 {\n\t\treturn nil, newError(\"MTProto secret must have 32 chars\")\n\t}\n\tsecret, err := hex.DecodeString(a.Secret)\n\tif err != nil {\n\t\treturn nil, newError(\"failed to decode secret: \", a.Secret).Base(err)\n\t}\n\treturn &mtproto.Account{\n\t\tSecret: secret,\n\t}, nil\n}\n\ntype MTProtoServerConfig struct {\n\tUsers []json.RawMessage `json:\"users\"`\n}\n\nfunc (c *MTProtoServerConfig) Build() (proto.Message, error) {\n\tconfig := &mtproto.ServerConfig{}\n\n\tif len(c.Users) == 0 {\n\t\treturn nil, newError(\"zero MTProto users configured.\")\n\t}\n\tconfig.User = make([]*protocol.User, len(c.Users))\n\tfor idx, rawData := range c.Users {\n\t\tuser := new(protocol.User)\n\t\tif err := json.Unmarshal(rawData, user); err != nil {\n\t\t\treturn nil, newError(\"invalid MTProto user\").Base(err)\n\t\t}\n\t\taccount := new(MTProtoAccount)\n\t\tif err := json.Unmarshal(rawData, account); err != nil {\n\t\t\treturn nil, newError(\"invalid MTProto user\").Base(err)\n\t\t}\n\t\taccountProto, err := account.Build()\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"failed to parse MTProto user\").Base(err)\n\t\t}\n\t\tuser.Account = serial.ToTypedMessage(accountProto)\n\t\tconfig.User[idx] = user\n\t}\n\n\treturn config, nil\n}\n\ntype MTProtoClientConfig struct {\n}\n\nfunc (c *MTProtoClientConfig) Build() (proto.Message, error) {\n\tconfig := new(mtproto.ClientConfig)\n\treturn config, nil\n}\n"
  },
  {
    "path": "infra/conf/mtproto_test.go",
    "content": "package conf_test\n\nimport (\n\t\"testing\"\n\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/serial\"\n\t. \"v2ray.com/core/infra/conf\"\n\t\"v2ray.com/core/proxy/mtproto\"\n)\n\nfunc TestMTProtoServerConfig(t *testing.T) {\n\tcreator := func() Buildable {\n\t\treturn new(MTProtoServerConfig)\n\t}\n\n\trunMultiTestCase(t, []TestCase{\n\t\t{\n\t\t\tInput: `{\n\t\t\t\t\"users\": [{\n\t\t\t\t\t\"email\": \"love@v2ray.com\",\n\t\t\t\t\t\"level\": 1,\n\t\t\t\t\t\"secret\": \"b0cbcef5a486d9636472ac27f8e11a9d\"\n\t\t\t\t}]\n\t\t\t}`,\n\t\t\tParser: loadJSON(creator),\n\t\t\tOutput: &mtproto.ServerConfig{\n\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t{\n\t\t\t\t\t\tEmail: \"love@v2ray.com\",\n\t\t\t\t\t\tLevel: 1,\n\t\t\t\t\t\tAccount: serial.ToTypedMessage(&mtproto.Account{\n\t\t\t\t\t\t\tSecret: []byte{176, 203, 206, 245, 164, 134, 217, 99, 100, 114, 172, 39, 248, 225, 26, 157},\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"
  },
  {
    "path": "infra/conf/policy.go",
    "content": "package conf\n\nimport (\n\t\"v2ray.com/core/app/policy\"\n)\n\ntype Policy struct {\n\tHandshake         *uint32 `json:\"handshake\"`\n\tConnectionIdle    *uint32 `json:\"connIdle\"`\n\tUplinkOnly        *uint32 `json:\"uplinkOnly\"`\n\tDownlinkOnly      *uint32 `json:\"downlinkOnly\"`\n\tStatsUserUplink   bool    `json:\"statsUserUplink\"`\n\tStatsUserDownlink bool    `json:\"statsUserDownlink\"`\n\tBufferSize        *int32  `json:\"bufferSize\"`\n}\n\nfunc (t *Policy) Build() (*policy.Policy, error) {\n\tconfig := new(policy.Policy_Timeout)\n\tif t.Handshake != nil {\n\t\tconfig.Handshake = &policy.Second{Value: *t.Handshake}\n\t}\n\tif t.ConnectionIdle != nil {\n\t\tconfig.ConnectionIdle = &policy.Second{Value: *t.ConnectionIdle}\n\t}\n\tif t.UplinkOnly != nil {\n\t\tconfig.UplinkOnly = &policy.Second{Value: *t.UplinkOnly}\n\t}\n\tif t.DownlinkOnly != nil {\n\t\tconfig.DownlinkOnly = &policy.Second{Value: *t.DownlinkOnly}\n\t}\n\n\tp := &policy.Policy{\n\t\tTimeout: config,\n\t\tStats: &policy.Policy_Stats{\n\t\t\tUserUplink:   t.StatsUserUplink,\n\t\t\tUserDownlink: t.StatsUserDownlink,\n\t\t},\n\t}\n\n\tif t.BufferSize != nil {\n\t\tbs := int32(-1)\n\t\tif *t.BufferSize >= 0 {\n\t\t\tbs = (*t.BufferSize) * 1024\n\t\t}\n\t\tp.Buffer = &policy.Policy_Buffer{\n\t\t\tConnection: bs,\n\t\t}\n\t}\n\n\treturn p, nil\n}\n\ntype SystemPolicy struct {\n\tStatsInboundUplink    bool `json:\"statsInboundUplink\"`\n\tStatsInboundDownlink  bool `json:\"statsInboundDownlink\"`\n\tStatsOutboundUplink   bool `json:\"statsOutboundUplink\"`\n\tStatsOutboundDownlink bool `json:\"statsOutboundDownlink\"`\n}\n\nfunc (p *SystemPolicy) Build() (*policy.SystemPolicy, error) {\n\treturn &policy.SystemPolicy{\n\t\tStats: &policy.SystemPolicy_Stats{\n\t\t\tInboundUplink:    p.StatsInboundUplink,\n\t\t\tInboundDownlink:  p.StatsInboundDownlink,\n\t\t\tOutboundUplink:   p.StatsOutboundUplink,\n\t\t\tOutboundDownlink: p.StatsOutboundDownlink,\n\t\t},\n\t}, nil\n}\n\ntype PolicyConfig struct {\n\tLevels map[uint32]*Policy `json:\"levels\"`\n\tSystem *SystemPolicy      `json:\"system\"`\n}\n\nfunc (c *PolicyConfig) Build() (*policy.Config, error) {\n\tlevels := make(map[uint32]*policy.Policy)\n\tfor l, p := range c.Levels {\n\t\tif p != nil {\n\t\t\tpp, err := p.Build()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tlevels[l] = pp\n\t\t}\n\t}\n\tconfig := &policy.Config{\n\t\tLevel: levels,\n\t}\n\n\tif c.System != nil {\n\t\tsc, err := c.System.Build()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tconfig.System = sc\n\t}\n\n\treturn config, nil\n}\n"
  },
  {
    "path": "infra/conf/policy_test.go",
    "content": "package conf_test\n\nimport (\n\t\"testing\"\n\n\t\"v2ray.com/core/common\"\n\t. \"v2ray.com/core/infra/conf\"\n)\n\nfunc TestBufferSize(t *testing.T) {\n\tcases := []struct {\n\t\tInput  int32\n\t\tOutput int32\n\t}{\n\t\t{\n\t\t\tInput:  0,\n\t\t\tOutput: 0,\n\t\t},\n\t\t{\n\t\t\tInput:  -1,\n\t\t\tOutput: -1,\n\t\t},\n\t\t{\n\t\t\tInput:  1,\n\t\t\tOutput: 1024,\n\t\t},\n\t}\n\n\tfor _, c := range cases {\n\t\tbs := int32(c.Input)\n\t\tpConf := Policy{\n\t\t\tBufferSize: &bs,\n\t\t}\n\t\tp, err := pConf.Build()\n\t\tcommon.Must(err)\n\t\tif p.Buffer.Connection != c.Output {\n\t\t\tt.Error(\"expected buffer size \", c.Output, \" but got \", p.Buffer.Connection)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "infra/conf/reverse.go",
    "content": "package conf\n\nimport (\n\t\"github.com/golang/protobuf/proto\"\n\t\"v2ray.com/core/app/reverse\"\n)\n\ntype BridgeConfig struct {\n\tTag    string `json:\"tag\"`\n\tDomain string `json:\"domain\"`\n}\n\nfunc (c *BridgeConfig) Build() (*reverse.BridgeConfig, error) {\n\treturn &reverse.BridgeConfig{\n\t\tTag:    c.Tag,\n\t\tDomain: c.Domain,\n\t}, nil\n}\n\ntype PortalConfig struct {\n\tTag    string `json:\"tag\"`\n\tDomain string `json:\"domain\"`\n}\n\nfunc (c *PortalConfig) Build() (*reverse.PortalConfig, error) {\n\treturn &reverse.PortalConfig{\n\t\tTag:    c.Tag,\n\t\tDomain: c.Domain,\n\t}, nil\n}\n\ntype ReverseConfig struct {\n\tBridges []BridgeConfig `json:\"bridges\"`\n\tPortals []PortalConfig `json:\"portals\"`\n}\n\nfunc (c *ReverseConfig) Build() (proto.Message, error) {\n\tconfig := &reverse.Config{}\n\tfor _, bconfig := range c.Bridges {\n\t\tb, err := bconfig.Build()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tconfig.BridgeConfig = append(config.BridgeConfig, b)\n\t}\n\n\tfor _, pconfig := range c.Portals {\n\t\tp, err := pconfig.Build()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tconfig.PortalConfig = append(config.PortalConfig, p)\n\t}\n\n\treturn config, nil\n}\n"
  },
  {
    "path": "infra/conf/reverse_test.go",
    "content": "package conf_test\n\nimport (\n\t\"testing\"\n\n\t\"v2ray.com/core/app/reverse\"\n\t\"v2ray.com/core/infra/conf\"\n)\n\nfunc TestReverseConfig(t *testing.T) {\n\tcreator := func() conf.Buildable {\n\t\treturn new(conf.ReverseConfig)\n\t}\n\n\trunMultiTestCase(t, []TestCase{\n\t\t{\n\t\t\tInput: `{\n\t\t\t\t\"bridges\": [{\n\t\t\t\t\t\"tag\": \"test\",\n\t\t\t\t\t\"domain\": \"test.v2ray.com\"\n\t\t\t\t}]\n\t\t\t}`,\n\t\t\tParser: loadJSON(creator),\n\t\t\tOutput: &reverse.Config{\n\t\t\t\tBridgeConfig: []*reverse.BridgeConfig{\n\t\t\t\t\t{Tag: \"test\", Domain: \"test.v2ray.com\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tInput: `{\n\t\t\t\t\"portals\": [{\n\t\t\t\t\t\"tag\": \"test\",\n\t\t\t\t\t\"domain\": \"test.v2ray.com\"\n\t\t\t\t}]\n\t\t\t}`,\n\t\t\tParser: loadJSON(creator),\n\t\t\tOutput: &reverse.Config{\n\t\t\t\tPortalConfig: []*reverse.PortalConfig{\n\t\t\t\t\t{Tag: \"test\", Domain: \"test.v2ray.com\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "infra/conf/router.go",
    "content": "package conf\n\nimport (\n\t\"encoding/json\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"v2ray.com/core/app/router\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/platform/filesystem\"\n\n\t\"github.com/golang/protobuf/proto\"\n)\n\ntype RouterRulesConfig struct {\n\tRuleList       []json.RawMessage `json:\"rules\"`\n\tDomainStrategy string            `json:\"domainStrategy\"`\n}\n\ntype BalancingRule struct {\n\tTag       string     `json:\"tag\"`\n\tSelectors StringList `json:\"selector\"`\n}\n\nfunc (r *BalancingRule) Build() (*router.BalancingRule, error) {\n\tif r.Tag == \"\" {\n\t\treturn nil, newError(\"empty balancer tag\")\n\t}\n\tif len(r.Selectors) == 0 {\n\t\treturn nil, newError(\"empty selector list\")\n\t}\n\n\treturn &router.BalancingRule{\n\t\tTag:              r.Tag,\n\t\tOutboundSelector: []string(r.Selectors),\n\t}, nil\n}\n\ntype RouterConfig struct {\n\tSettings       *RouterRulesConfig `json:\"settings\"` // Deprecated\n\tRuleList       []json.RawMessage  `json:\"rules\"`\n\tDomainStrategy *string            `json:\"domainStrategy\"`\n\tBalancers      []*BalancingRule   `json:\"balancers\"`\n}\n\nfunc (c *RouterConfig) getDomainStrategy() router.Config_DomainStrategy {\n\tds := \"\"\n\tif c.DomainStrategy != nil {\n\t\tds = *c.DomainStrategy\n\t} else if c.Settings != nil {\n\t\tds = c.Settings.DomainStrategy\n\t}\n\n\tswitch strings.ToLower(ds) {\n\tcase \"alwaysip\":\n\t\treturn router.Config_UseIp\n\tcase \"ipifnonmatch\":\n\t\treturn router.Config_IpIfNonMatch\n\tcase \"ipondemand\":\n\t\treturn router.Config_IpOnDemand\n\tdefault:\n\t\treturn router.Config_AsIs\n\t}\n}\n\nfunc (c *RouterConfig) Build() (*router.Config, error) {\n\tconfig := new(router.Config)\n\tconfig.DomainStrategy = c.getDomainStrategy()\n\n\trawRuleList := c.RuleList\n\tif c.Settings != nil {\n\t\trawRuleList = append(c.RuleList, c.Settings.RuleList...)\n\t}\n\tfor _, rawRule := range rawRuleList {\n\t\trule, err := ParseRule(rawRule)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tconfig.Rule = append(config.Rule, rule)\n\t}\n\tfor _, rawBalancer := range c.Balancers {\n\t\tbalancer, err := rawBalancer.Build()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tconfig.BalancingRule = append(config.BalancingRule, balancer)\n\t}\n\treturn config, nil\n}\n\ntype RouterRule struct {\n\tType        string `json:\"type\"`\n\tOutboundTag string `json:\"outboundTag\"`\n\tBalancerTag string `json:\"balancerTag\"`\n}\n\nfunc ParseIP(s string) (*router.CIDR, error) {\n\tvar addr, mask string\n\ti := strings.Index(s, \"/\")\n\tif i < 0 {\n\t\taddr = s\n\t} else {\n\t\taddr = s[:i]\n\t\tmask = s[i+1:]\n\t}\n\tip := net.ParseAddress(addr)\n\tswitch ip.Family() {\n\tcase net.AddressFamilyIPv4:\n\t\tbits := uint32(32)\n\t\tif len(mask) > 0 {\n\t\t\tbits64, err := strconv.ParseUint(mask, 10, 32)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, newError(\"invalid network mask for router: \", mask).Base(err)\n\t\t\t}\n\t\t\tbits = uint32(bits64)\n\t\t}\n\t\tif bits > 32 {\n\t\t\treturn nil, newError(\"invalid network mask for router: \", bits)\n\t\t}\n\t\treturn &router.CIDR{\n\t\t\tIp:     []byte(ip.IP()),\n\t\t\tPrefix: bits,\n\t\t}, nil\n\tcase net.AddressFamilyIPv6:\n\t\tbits := uint32(128)\n\t\tif len(mask) > 0 {\n\t\t\tbits64, err := strconv.ParseUint(mask, 10, 32)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, newError(\"invalid network mask for router: \", mask).Base(err)\n\t\t\t}\n\t\t\tbits = uint32(bits64)\n\t\t}\n\t\tif bits > 128 {\n\t\t\treturn nil, newError(\"invalid network mask for router: \", bits)\n\t\t}\n\t\treturn &router.CIDR{\n\t\t\tIp:     []byte(ip.IP()),\n\t\t\tPrefix: bits,\n\t\t}, nil\n\tdefault:\n\t\treturn nil, newError(\"unsupported address for router: \", s)\n\t}\n}\n\nfunc loadGeoIP(country string) ([]*router.CIDR, error) {\n\treturn loadIP(\"geoip.dat\", country)\n}\n\nfunc loadIP(filename, country string) ([]*router.CIDR, error) {\n\tgeoipBytes, err := filesystem.ReadAsset(filename)\n\tif err != nil {\n\t\treturn nil, newError(\"failed to open file: \", filename).Base(err)\n\t}\n\tvar geoipList router.GeoIPList\n\tif err := proto.Unmarshal(geoipBytes, &geoipList); err != nil {\n\t\treturn nil, err\n\t}\n\n\tfor _, geoip := range geoipList.Entry {\n\t\tif geoip.CountryCode == country {\n\t\t\treturn geoip.Cidr, nil\n\t\t}\n\t}\n\n\treturn nil, newError(\"country not found in \", filename, \": \", country)\n}\n\nfunc loadSite(filename, country string) ([]*router.Domain, error) {\n\tgeositeBytes, err := filesystem.ReadAsset(filename)\n\tif err != nil {\n\t\treturn nil, newError(\"failed to open file: \", filename).Base(err)\n\t}\n\tvar geositeList router.GeoSiteList\n\tif err := proto.Unmarshal(geositeBytes, &geositeList); err != nil {\n\t\treturn nil, err\n\t}\n\n\tfor _, site := range geositeList.Entry {\n\t\tif site.CountryCode == country {\n\t\t\treturn site.Domain, nil\n\t\t}\n\t}\n\n\treturn nil, newError(\"list not found in \", filename, \": \", country)\n}\n\ntype AttributeMatcher interface {\n\tMatch(*router.Domain) bool\n}\n\ntype BooleanMatcher string\n\nfunc (m BooleanMatcher) Match(domain *router.Domain) bool {\n\tfor _, attr := range domain.Attribute {\n\t\tif attr.Key == string(m) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\ntype AttributeList struct {\n\tmatcher []AttributeMatcher\n}\n\nfunc (al *AttributeList) Match(domain *router.Domain) bool {\n\tfor _, matcher := range al.matcher {\n\t\tif !matcher.Match(domain) {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\nfunc (al *AttributeList) IsEmpty() bool {\n\treturn len(al.matcher) == 0\n}\n\nfunc parseAttrs(attrs []string) *AttributeList {\n\tal := new(AttributeList)\n\tfor _, attr := range attrs {\n\t\tlc := strings.ToLower(attr)\n\t\tal.matcher = append(al.matcher, BooleanMatcher(lc))\n\t}\n\treturn al\n}\n\nfunc loadGeositeWithAttr(file string, siteWithAttr string) ([]*router.Domain, error) {\n\tparts := strings.Split(siteWithAttr, \"@\")\n\tif len(parts) == 0 {\n\t\treturn nil, newError(\"empty site\")\n\t}\n\tcountry := strings.ToUpper(parts[0])\n\tattrs := parseAttrs(parts[1:])\n\tdomains, err := loadSite(file, country)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif attrs.IsEmpty() {\n\t\treturn domains, nil\n\t}\n\n\tfilteredDomains := make([]*router.Domain, 0, len(domains))\n\tfor _, domain := range domains {\n\t\tif attrs.Match(domain) {\n\t\t\tfilteredDomains = append(filteredDomains, domain)\n\t\t}\n\t}\n\n\treturn filteredDomains, nil\n}\n\nfunc parseDomainRule(domain string) ([]*router.Domain, error) {\n\tif strings.HasPrefix(domain, \"geosite:\") {\n\t\tcountry := strings.ToUpper(domain[8:])\n\t\tdomains, err := loadGeositeWithAttr(\"geosite.dat\", country)\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"failed to load geosite: \", country).Base(err)\n\t\t}\n\t\treturn domains, nil\n\t}\n\tvar isExtDatFile = 0\n\t{\n\t\tconst prefix = \"ext:\"\n\t\tif strings.HasPrefix(domain, prefix) {\n\t\t\tisExtDatFile = len(prefix)\n\t\t}\n\t\tconst prefixQualified = \"ext-domain:\"\n\t\tif strings.HasPrefix(domain, prefixQualified) {\n\t\t\tisExtDatFile = len(prefixQualified)\n\t\t}\n\t}\n\tif isExtDatFile != 0 {\n\t\tkv := strings.Split(domain[isExtDatFile:], \":\")\n\t\tif len(kv) != 2 {\n\t\t\treturn nil, newError(\"invalid external resource: \", domain)\n\t\t}\n\t\tfilename := kv[0]\n\t\tcountry := kv[1]\n\t\tdomains, err := loadGeositeWithAttr(filename, country)\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"failed to load external sites: \", country, \" from \", filename).Base(err)\n\t\t}\n\t\treturn domains, nil\n\t}\n\n\tdomainRule := new(router.Domain)\n\tswitch {\n\tcase strings.HasPrefix(domain, \"regexp:\"):\n\t\tdomainRule.Type = router.Domain_Regex\n\t\tdomainRule.Value = domain[7:]\n\tcase strings.HasPrefix(domain, \"domain:\"):\n\t\tdomainRule.Type = router.Domain_Domain\n\t\tdomainRule.Value = domain[7:]\n\tcase strings.HasPrefix(domain, \"full:\"):\n\t\tdomainRule.Type = router.Domain_Full\n\t\tdomainRule.Value = domain[5:]\n\tcase strings.HasPrefix(domain, \"keyword:\"):\n\t\tdomainRule.Type = router.Domain_Plain\n\t\tdomainRule.Value = domain[8:]\n\tcase strings.HasPrefix(domain, \"dotless:\"):\n\t\tdomainRule.Type = router.Domain_Regex\n\t\tswitch substr := domain[8:]; {\n\t\tcase substr == \"\":\n\t\t\tdomainRule.Value = \"^[^.]*$\"\n\t\tcase !strings.Contains(substr, \".\"):\n\t\t\tdomainRule.Value = \"^[^.]*\" + substr + \"[^.]*$\"\n\t\tdefault:\n\t\t\treturn nil, newError(\"substr in dotless rule should not contain a dot: \", substr)\n\t\t}\n\tdefault:\n\t\tdomainRule.Type = router.Domain_Plain\n\t\tdomainRule.Value = domain\n\t}\n\treturn []*router.Domain{domainRule}, nil\n}\n\nfunc toCidrList(ips StringList) ([]*router.GeoIP, error) {\n\tvar geoipList []*router.GeoIP\n\tvar customCidrs []*router.CIDR\n\n\tfor _, ip := range ips {\n\t\tif strings.HasPrefix(ip, \"geoip:\") {\n\t\t\tcountry := ip[6:]\n\t\t\tgeoip, err := loadGeoIP(strings.ToUpper(country))\n\t\t\tif err != nil {\n\t\t\t\treturn nil, newError(\"failed to load GeoIP: \", country).Base(err)\n\t\t\t}\n\n\t\t\tgeoipList = append(geoipList, &router.GeoIP{\n\t\t\t\tCountryCode: strings.ToUpper(country),\n\t\t\t\tCidr:        geoip,\n\t\t\t})\n\t\t\tcontinue\n\t\t}\n\t\tvar isExtDatFile = 0\n\t\t{\n\t\t\tconst prefix = \"ext:\"\n\t\t\tif strings.HasPrefix(ip, prefix) {\n\t\t\t\tisExtDatFile = len(prefix)\n\t\t\t}\n\t\t\tconst prefixQualified = \"ext-ip:\"\n\t\t\tif strings.HasPrefix(ip, prefixQualified) {\n\t\t\t\tisExtDatFile = len(prefixQualified)\n\t\t\t}\n\t\t}\n\t\tif isExtDatFile != 0 {\n\t\t\tkv := strings.Split(ip[isExtDatFile:], \":\")\n\t\t\tif len(kv) != 2 {\n\t\t\t\treturn nil, newError(\"invalid external resource: \", ip)\n\t\t\t}\n\n\t\t\tfilename := kv[0]\n\t\t\tcountry := kv[1]\n\t\t\tgeoip, err := loadIP(filename, strings.ToUpper(country))\n\t\t\tif err != nil {\n\t\t\t\treturn nil, newError(\"failed to load IPs: \", country, \" from \", filename).Base(err)\n\t\t\t}\n\n\t\t\tgeoipList = append(geoipList, &router.GeoIP{\n\t\t\t\tCountryCode: strings.ToUpper(filename + \"_\" + country),\n\t\t\t\tCidr:        geoip,\n\t\t\t})\n\n\t\t\tcontinue\n\t\t}\n\n\t\tipRule, err := ParseIP(ip)\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"invalid IP: \", ip).Base(err)\n\t\t}\n\t\tcustomCidrs = append(customCidrs, ipRule)\n\t}\n\n\tif len(customCidrs) > 0 {\n\t\tgeoipList = append(geoipList, &router.GeoIP{\n\t\t\tCidr: customCidrs,\n\t\t})\n\t}\n\n\treturn geoipList, nil\n}\n\nfunc parseFieldRule(msg json.RawMessage) (*router.RoutingRule, error) {\n\ttype RawFieldRule struct {\n\t\tRouterRule\n\t\tDomain     *StringList  `json:\"domain\"`\n\t\tIP         *StringList  `json:\"ip\"`\n\t\tPort       *PortList    `json:\"port\"`\n\t\tNetwork    *NetworkList `json:\"network\"`\n\t\tSourceIP   *StringList  `json:\"source\"`\n\t\tSourcePort *PortList    `json:\"sourcePort\"`\n\t\tUser       *StringList  `json:\"user\"`\n\t\tInboundTag *StringList  `json:\"inboundTag\"`\n\t\tProtocols  *StringList  `json:\"protocol\"`\n\t\tAttributes string       `json:\"attrs\"`\n\t}\n\trawFieldRule := new(RawFieldRule)\n\terr := json.Unmarshal(msg, rawFieldRule)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\trule := new(router.RoutingRule)\n\tif len(rawFieldRule.OutboundTag) > 0 {\n\t\trule.TargetTag = &router.RoutingRule_Tag{\n\t\t\tTag: rawFieldRule.OutboundTag,\n\t\t}\n\t} else if len(rawFieldRule.BalancerTag) > 0 {\n\t\trule.TargetTag = &router.RoutingRule_BalancingTag{\n\t\t\tBalancingTag: rawFieldRule.BalancerTag,\n\t\t}\n\t} else {\n\t\treturn nil, newError(\"neither outboundTag nor balancerTag is specified in routing rule\")\n\t}\n\n\tif rawFieldRule.Domain != nil {\n\t\tfor _, domain := range *rawFieldRule.Domain {\n\t\t\trules, err := parseDomainRule(domain)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, newError(\"failed to parse domain rule: \", domain).Base(err)\n\t\t\t}\n\t\t\trule.Domain = append(rule.Domain, rules...)\n\t\t}\n\t}\n\n\tif rawFieldRule.IP != nil {\n\t\tgeoipList, err := toCidrList(*rawFieldRule.IP)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\trule.Geoip = geoipList\n\t}\n\n\tif rawFieldRule.Port != nil {\n\t\trule.PortList = rawFieldRule.Port.Build()\n\t}\n\n\tif rawFieldRule.Network != nil {\n\t\trule.Networks = rawFieldRule.Network.Build()\n\t}\n\n\tif rawFieldRule.SourceIP != nil {\n\t\tgeoipList, err := toCidrList(*rawFieldRule.SourceIP)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\trule.SourceGeoip = geoipList\n\t}\n\n\tif rawFieldRule.SourcePort != nil {\n\t\trule.SourcePortList = rawFieldRule.SourcePort.Build()\n\t}\n\n\tif rawFieldRule.User != nil {\n\t\tfor _, s := range *rawFieldRule.User {\n\t\t\trule.UserEmail = append(rule.UserEmail, s)\n\t\t}\n\t}\n\n\tif rawFieldRule.InboundTag != nil {\n\t\tfor _, s := range *rawFieldRule.InboundTag {\n\t\t\trule.InboundTag = append(rule.InboundTag, s)\n\t\t}\n\t}\n\n\tif rawFieldRule.Protocols != nil {\n\t\tfor _, s := range *rawFieldRule.Protocols {\n\t\t\trule.Protocol = append(rule.Protocol, s)\n\t\t}\n\t}\n\n\tif len(rawFieldRule.Attributes) > 0 {\n\t\trule.Attributes = rawFieldRule.Attributes\n\t}\n\n\treturn rule, nil\n}\n\nfunc ParseRule(msg json.RawMessage) (*router.RoutingRule, error) {\n\trawRule := new(RouterRule)\n\terr := json.Unmarshal(msg, rawRule)\n\tif err != nil {\n\t\treturn nil, newError(\"invalid router rule\").Base(err)\n\t}\n\tif rawRule.Type == \"field\" {\n\t\tfieldrule, err := parseFieldRule(msg)\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"invalid field rule\").Base(err)\n\t\t}\n\t\treturn fieldrule, nil\n\t}\n\tif rawRule.Type == \"chinaip\" {\n\t\tchinaiprule, err := parseChinaIPRule(msg)\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"invalid chinaip rule\").Base(err)\n\t\t}\n\t\treturn chinaiprule, nil\n\t}\n\tif rawRule.Type == \"chinasites\" {\n\t\tchinasitesrule, err := parseChinaSitesRule(msg)\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"invalid chinasites rule\").Base(err)\n\t\t}\n\t\treturn chinasitesrule, nil\n\t}\n\treturn nil, newError(\"unknown router rule type: \", rawRule.Type)\n}\n\nfunc parseChinaIPRule(data []byte) (*router.RoutingRule, error) {\n\trawRule := new(RouterRule)\n\terr := json.Unmarshal(data, rawRule)\n\tif err != nil {\n\t\treturn nil, newError(\"invalid router rule\").Base(err)\n\t}\n\tchinaIPs, err := loadGeoIP(\"CN\")\n\tif err != nil {\n\t\treturn nil, newError(\"failed to load geoip:cn\").Base(err)\n\t}\n\treturn &router.RoutingRule{\n\t\tTargetTag: &router.RoutingRule_Tag{\n\t\t\tTag: rawRule.OutboundTag,\n\t\t},\n\t\tCidr: chinaIPs,\n\t}, nil\n}\n\nfunc parseChinaSitesRule(data []byte) (*router.RoutingRule, error) {\n\trawRule := new(RouterRule)\n\terr := json.Unmarshal(data, rawRule)\n\tif err != nil {\n\t\treturn nil, newError(\"invalid router rule\").Base(err).AtError()\n\t}\n\tdomains, err := loadGeositeWithAttr(\"geosite.dat\", \"CN\")\n\tif err != nil {\n\t\treturn nil, newError(\"failed to load geosite:cn.\").Base(err)\n\t}\n\treturn &router.RoutingRule{\n\t\tTargetTag: &router.RoutingRule_Tag{\n\t\t\tTag: rawRule.OutboundTag,\n\t\t},\n\t\tDomain: domains,\n\t}, nil\n}\n"
  },
  {
    "path": "infra/conf/router_test.go",
    "content": "package conf_test\n\nimport (\n\t\"encoding/json\"\n\t\"testing\"\n\n\t\"github.com/golang/protobuf/proto\"\n\n\t\"v2ray.com/core/app/router\"\n\t\"v2ray.com/core/common/net\"\n\t. \"v2ray.com/core/infra/conf\"\n)\n\nfunc TestRouterConfig(t *testing.T) {\n\tcreateParser := func() func(string) (proto.Message, error) {\n\t\treturn func(s string) (proto.Message, error) {\n\t\t\tconfig := new(RouterConfig)\n\t\t\tif err := json.Unmarshal([]byte(s), config); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn config.Build()\n\t\t}\n\t}\n\n\trunMultiTestCase(t, []TestCase{\n\t\t{\n\t\t\tInput: `{\n\t\t\t\t\"strategy\": \"rules\",\n\t\t\t\t\"settings\": {\n\t\t\t\t\t\"domainStrategy\": \"AsIs\",\n\t\t\t\t\t\"rules\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"field\",\n\t\t\t\t\t\t\t\"domain\": [\n\t\t\t\t\t\t\t\t\"baidu.com\",\n\t\t\t\t\t\t\t\t\"qq.com\"\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"outboundTag\": \"direct\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"field\",\n\t\t\t\t\t\t\t\"ip\": [\n\t\t\t\t\t\t\t\t\"10.0.0.0/8\",\n\t\t\t\t\t\t\t\t\"::1/128\"\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"outboundTag\": \"test\"\n\t\t\t\t\t\t},{\n\t\t\t\t\t\t\t\"type\": \"field\",\n\t\t\t\t\t\t\t\"port\": \"53, 443, 1000-2000\",\n\t\t\t\t\t\t\t\"outboundTag\": \"test\"\n\t\t\t\t\t\t},{\n\t\t\t\t\t\t\t\"type\": \"field\",\n\t\t\t\t\t\t\t\"port\": 123,\n\t\t\t\t\t\t\t\"outboundTag\": \"test\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"balancers\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"tag\": \"b1\",\n\t\t\t\t\t\t\"selector\": [\"test\"]\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}`,\n\t\t\tParser: createParser(),\n\t\t\tOutput: &router.Config{\n\t\t\t\tDomainStrategy: router.Config_AsIs,\n\t\t\t\tBalancingRule: []*router.BalancingRule{\n\t\t\t\t\t{\n\t\t\t\t\t\tTag:              \"b1\",\n\t\t\t\t\t\tOutboundSelector: []string{\"test\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tRule: []*router.RoutingRule{\n\t\t\t\t\t{\n\t\t\t\t\t\tDomain: []*router.Domain{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tType:  router.Domain_Plain,\n\t\t\t\t\t\t\t\tValue: \"baidu.com\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tType:  router.Domain_Plain,\n\t\t\t\t\t\t\t\tValue: \"qq.com\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tTargetTag: &router.RoutingRule_Tag{\n\t\t\t\t\t\t\tTag: \"direct\",\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\tGeoip: []*router.GeoIP{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tCidr: []*router.CIDR{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tIp:     []byte{10, 0, 0, 0},\n\t\t\t\t\t\t\t\t\t\tPrefix: 8,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tIp:     []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},\n\t\t\t\t\t\t\t\t\t\tPrefix: 128,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tTargetTag: &router.RoutingRule_Tag{\n\t\t\t\t\t\t\tTag: \"test\",\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\tPortList: &net.PortList{\n\t\t\t\t\t\t\tRange: []*net.PortRange{\n\t\t\t\t\t\t\t\t{From: 53, To: 53},\n\t\t\t\t\t\t\t\t{From: 443, To: 443},\n\t\t\t\t\t\t\t\t{From: 1000, To: 2000},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tTargetTag: &router.RoutingRule_Tag{\n\t\t\t\t\t\t\tTag: \"test\",\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\tPortList: &net.PortList{\n\t\t\t\t\t\t\tRange: []*net.PortRange{\n\t\t\t\t\t\t\t\t{From: 123, To: 123},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tTargetTag: &router.RoutingRule_Tag{\n\t\t\t\t\t\t\tTag: \"test\",\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\t{\n\t\t\tInput: `{\n\t\t\t\t\"strategy\": \"rules\",\n\t\t\t\t\"settings\": {\n\t\t\t\t\t\"domainStrategy\": \"IPIfNonMatch\",\n\t\t\t\t\t\"rules\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"field\",\n\t\t\t\t\t\t\t\"domain\": [\n\t\t\t\t\t\t\t\t\"baidu.com\",\n\t\t\t\t\t\t\t\t\"qq.com\"\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"outboundTag\": \"direct\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"field\",\n\t\t\t\t\t\t\t\"ip\": [\n\t\t\t\t\t\t\t\t\"10.0.0.0/8\",\n\t\t\t\t\t\t\t\t\"::1/128\"\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"outboundTag\": \"test\"\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\tParser: createParser(),\n\t\t\tOutput: &router.Config{\n\t\t\t\tDomainStrategy: router.Config_IpIfNonMatch,\n\t\t\t\tRule: []*router.RoutingRule{\n\t\t\t\t\t{\n\t\t\t\t\t\tDomain: []*router.Domain{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tType:  router.Domain_Plain,\n\t\t\t\t\t\t\t\tValue: \"baidu.com\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tType:  router.Domain_Plain,\n\t\t\t\t\t\t\t\tValue: \"qq.com\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tTargetTag: &router.RoutingRule_Tag{\n\t\t\t\t\t\t\tTag: \"direct\",\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\tGeoip: []*router.GeoIP{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tCidr: []*router.CIDR{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tIp:     []byte{10, 0, 0, 0},\n\t\t\t\t\t\t\t\t\t\tPrefix: 8,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tIp:     []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},\n\t\t\t\t\t\t\t\t\t\tPrefix: 128,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tTargetTag: &router.RoutingRule_Tag{\n\t\t\t\t\t\t\tTag: \"test\",\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\t{\n\t\t\tInput: `{\n\t\t\t\t\"domainStrategy\": \"AsIs\",\n\t\t\t\t\"rules\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"type\": \"field\",\n\t\t\t\t\t\t\"domain\": [\n\t\t\t\t\t\t\t\"baidu.com\",\n\t\t\t\t\t\t\t\"qq.com\"\n\t\t\t\t\t\t],\n\t\t\t\t\t\t\"outboundTag\": \"direct\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"type\": \"field\",\n\t\t\t\t\t\t\"ip\": [\n\t\t\t\t\t\t\t\"10.0.0.0/8\",\n\t\t\t\t\t\t\t\"::1/128\"\n\t\t\t\t\t\t],\n\t\t\t\t\t\t\"outboundTag\": \"test\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}`,\n\t\t\tParser: createParser(),\n\t\t\tOutput: &router.Config{\n\t\t\t\tDomainStrategy: router.Config_AsIs,\n\t\t\t\tRule: []*router.RoutingRule{\n\t\t\t\t\t{\n\t\t\t\t\t\tDomain: []*router.Domain{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tType:  router.Domain_Plain,\n\t\t\t\t\t\t\t\tValue: \"baidu.com\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tType:  router.Domain_Plain,\n\t\t\t\t\t\t\t\tValue: \"qq.com\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tTargetTag: &router.RoutingRule_Tag{\n\t\t\t\t\t\t\tTag: \"direct\",\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\tGeoip: []*router.GeoIP{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tCidr: []*router.CIDR{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tIp:     []byte{10, 0, 0, 0},\n\t\t\t\t\t\t\t\t\t\tPrefix: 8,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tIp:     []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},\n\t\t\t\t\t\t\t\t\t\tPrefix: 128,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tTargetTag: &router.RoutingRule_Tag{\n\t\t\t\t\t\t\tTag: \"test\",\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"
  },
  {
    "path": "infra/conf/serial/errors.generated.go",
    "content": "package serial\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "infra/conf/serial/loader.go",
    "content": "package serial\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"io\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/common/errors\"\n\t\"v2ray.com/core/infra/conf\"\n\tjson_reader \"v2ray.com/core/infra/conf/json\"\n)\n\ntype offset struct {\n\tline int\n\tchar int\n}\n\nfunc findOffset(b []byte, o int) *offset {\n\tif o >= len(b) || o < 0 {\n\t\treturn nil\n\t}\n\n\tline := 1\n\tchar := 0\n\tfor i, x := range b {\n\t\tif i == o {\n\t\t\tbreak\n\t\t}\n\t\tif x == '\\n' {\n\t\t\tline++\n\t\t\tchar = 0\n\t\t} else {\n\t\t\tchar++\n\t\t}\n\t}\n\n\treturn &offset{line: line, char: char}\n}\n\n// DecodeJSONConfig reads from reader and decode the config into *conf.Config\n// syntax error could be detected.\nfunc DecodeJSONConfig(reader io.Reader) (*conf.Config, error) {\n\tjsonConfig := &conf.Config{}\n\n\tjsonContent := bytes.NewBuffer(make([]byte, 0, 10240))\n\tjsonReader := io.TeeReader(&json_reader.Reader{\n\t\tReader: reader,\n\t}, jsonContent)\n\tdecoder := json.NewDecoder(jsonReader)\n\n\tif err := decoder.Decode(jsonConfig); err != nil {\n\t\tvar pos *offset\n\t\tcause := errors.Cause(err)\n\t\tswitch tErr := cause.(type) {\n\t\tcase *json.SyntaxError:\n\t\t\tpos = findOffset(jsonContent.Bytes(), int(tErr.Offset))\n\t\tcase *json.UnmarshalTypeError:\n\t\t\tpos = findOffset(jsonContent.Bytes(), int(tErr.Offset))\n\t\t}\n\t\tif pos != nil {\n\t\t\treturn nil, newError(\"failed to read config file at line \", pos.line, \" char \", pos.char).Base(err)\n\t\t}\n\t\treturn nil, newError(\"failed to read config file\").Base(err)\n\t}\n\n\treturn jsonConfig, nil\n}\n\nfunc LoadJSONConfig(reader io.Reader) (*core.Config, error) {\n\tjsonConfig, err := DecodeJSONConfig(reader)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tpbConfig, err := jsonConfig.Build()\n\tif err != nil {\n\t\treturn nil, newError(\"failed to parse json config\").Base(err)\n\t}\n\n\treturn pbConfig, nil\n}\n"
  },
  {
    "path": "infra/conf/serial/loader_test.go",
    "content": "package serial_test\n\nimport (\n\t\"bytes\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"v2ray.com/core/infra/conf/serial\"\n)\n\nfunc TestLoaderError(t *testing.T) {\n\ttestCases := []struct {\n\t\tInput  string\n\t\tOutput string\n\t}{\n\t\t{\n\t\t\tInput: `{\n\t\t\t\t\"log\": {\n\t\t\t\t\t// abcd\n\t\t\t\t\t0,\n\t\t\t\t\t\"loglevel\": \"info\"\n\t\t\t\t}\n\t\t}`,\n\t\t\tOutput: \"line 4 char 6\",\n\t\t},\n\t\t{\n\t\t\tInput: `{\n\t\t\t\t\"log\": {\n\t\t\t\t\t// abcd\n\t\t\t\t\t\"loglevel\": \"info\",\n\t\t\t\t}\n\t\t}`,\n\t\t\tOutput: \"line 5 char 5\",\n\t\t},\n\t\t{\n\t\t\tInput: `{\n\t\t\t\t\"port\": 1,\n\t\t\t\t\"inbounds\": [{\n\t\t\t\t\t\"protocol\": \"test\"\n\t\t\t\t}]\n\t\t}`,\n\t\t\tOutput: \"parse json config\",\n\t\t},\n\t\t{\n\t\t\tInput: `{\n\t\t\t\t\"inbounds\": [{\n\t\t\t\t\t\"port\": 1,\n\t\t\t\t\t\"listen\": 0,\n\t\t\t\t\t\"protocol\": \"test\"\n\t\t\t\t}]\n\t\t}`,\n\t\t\tOutput: \"line 1 char 1\",\n\t\t},\n\t}\n\tfor _, testCase := range testCases {\n\t\treader := bytes.NewReader([]byte(testCase.Input))\n\t\t_, err := serial.LoadJSONConfig(reader)\n\t\terrString := err.Error()\n\t\tif !strings.Contains(errString, testCase.Output) {\n\t\t\tt.Error(\"unexpected output from json: \", testCase.Input, \". expected \", testCase.Output, \", but actually \", errString)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "infra/conf/serial/serial.go",
    "content": "package serial\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n"
  },
  {
    "path": "infra/conf/shadowsocks.go",
    "content": "package conf\n\nimport (\n\t\"strings\"\n\n\t\"github.com/golang/protobuf/proto\"\n\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/serial\"\n\t\"v2ray.com/core/proxy/shadowsocks\"\n)\n\nfunc cipherFromString(c string) shadowsocks.CipherType {\n\tswitch strings.ToLower(c) {\n\tcase \"aes-256-cfb\":\n\t\treturn shadowsocks.CipherType_AES_256_CFB\n\tcase \"aes-128-cfb\":\n\t\treturn shadowsocks.CipherType_AES_128_CFB\n\tcase \"chacha20\":\n\t\treturn shadowsocks.CipherType_CHACHA20\n\tcase \"chacha20-ietf\":\n\t\treturn shadowsocks.CipherType_CHACHA20_IETF\n\tcase \"aes-128-gcm\", \"aead_aes_128_gcm\":\n\t\treturn shadowsocks.CipherType_AES_128_GCM\n\tcase \"aes-256-gcm\", \"aead_aes_256_gcm\":\n\t\treturn shadowsocks.CipherType_AES_256_GCM\n\tcase \"chacha20-poly1305\", \"aead_chacha20_poly1305\", \"chacha20-ietf-poly1305\":\n\t\treturn shadowsocks.CipherType_CHACHA20_POLY1305\n\tcase \"none\", \"plain\":\n\t\treturn shadowsocks.CipherType_NONE\n\tdefault:\n\t\treturn shadowsocks.CipherType_UNKNOWN\n\t}\n}\n\ntype ShadowsocksServerConfig struct {\n\tCipher      string       `json:\"method\"`\n\tPassword    string       `json:\"password\"`\n\tUDP         bool         `json:\"udp\"`\n\tLevel       byte         `json:\"level\"`\n\tEmail       string       `json:\"email\"`\n\tNetworkList *NetworkList `json:\"network\"`\n}\n\nfunc (v *ShadowsocksServerConfig) Build() (proto.Message, error) {\n\tconfig := new(shadowsocks.ServerConfig)\n\tconfig.UdpEnabled = v.UDP\n\tconfig.Network = v.NetworkList.Build()\n\n\tif v.Password == \"\" {\n\t\treturn nil, newError(\"Shadowsocks password is not specified.\")\n\t}\n\taccount := &shadowsocks.Account{\n\t\tPassword: v.Password,\n\t}\n\taccount.CipherType = cipherFromString(v.Cipher)\n\tif account.CipherType == shadowsocks.CipherType_UNKNOWN {\n\t\treturn nil, newError(\"unknown cipher method: \", v.Cipher)\n\t}\n\n\tconfig.User = &protocol.User{\n\t\tEmail:   v.Email,\n\t\tLevel:   uint32(v.Level),\n\t\tAccount: serial.ToTypedMessage(account),\n\t}\n\n\treturn config, nil\n}\n\ntype ShadowsocksServerTarget struct {\n\tAddress  *Address `json:\"address\"`\n\tPort     uint16   `json:\"port\"`\n\tCipher   string   `json:\"method\"`\n\tPassword string   `json:\"password\"`\n\tEmail    string   `json:\"email\"`\n\tOta      bool     `json:\"ota\"`\n\tLevel    byte     `json:\"level\"`\n}\n\ntype ShadowsocksClientConfig struct {\n\tServers []*ShadowsocksServerTarget `json:\"servers\"`\n}\n\nfunc (v *ShadowsocksClientConfig) Build() (proto.Message, error) {\n\tconfig := new(shadowsocks.ClientConfig)\n\n\tif len(v.Servers) == 0 {\n\t\treturn nil, newError(\"0 Shadowsocks server configured.\")\n\t}\n\n\tserverSpecs := make([]*protocol.ServerEndpoint, len(v.Servers))\n\tfor idx, server := range v.Servers {\n\t\tif server.Address == nil {\n\t\t\treturn nil, newError(\"Shadowsocks server address is not set.\")\n\t\t}\n\t\tif server.Port == 0 {\n\t\t\treturn nil, newError(\"Invalid Shadowsocks port.\")\n\t\t}\n\t\tif server.Password == \"\" {\n\t\t\treturn nil, newError(\"Shadowsocks password is not specified.\")\n\t\t}\n\t\taccount := &shadowsocks.Account{\n\t\t\tPassword: server.Password,\n\t\t}\n\t\taccount.CipherType = cipherFromString(server.Cipher)\n\t\tif account.CipherType == shadowsocks.CipherType_UNKNOWN {\n\t\t\treturn nil, newError(\"unknown cipher method: \", server.Cipher)\n\t\t}\n\n\t\tss := &protocol.ServerEndpoint{\n\t\t\tAddress: server.Address.Build(),\n\t\t\tPort:    uint32(server.Port),\n\t\t\tUser: []*protocol.User{\n\t\t\t\t{\n\t\t\t\t\tLevel:   uint32(server.Level),\n\t\t\t\t\tEmail:   server.Email,\n\t\t\t\t\tAccount: serial.ToTypedMessage(account),\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\n\t\tserverSpecs[idx] = ss\n\t}\n\n\tconfig.Server = serverSpecs\n\n\treturn config, nil\n}\n"
  },
  {
    "path": "infra/conf/shadowsocks_test.go",
    "content": "package conf_test\n\nimport (\n\t\"testing\"\n\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/serial\"\n\t. \"v2ray.com/core/infra/conf\"\n\t\"v2ray.com/core/proxy/shadowsocks\"\n)\n\nfunc TestShadowsocksServerConfigParsing(t *testing.T) {\n\tcreator := func() Buildable {\n\t\treturn new(ShadowsocksServerConfig)\n\t}\n\n\trunMultiTestCase(t, []TestCase{\n\t\t{\n\t\t\tInput: `{\n\t\t\t\t\"method\": \"aes-128-cfb\",\n\t\t\t\t\"password\": \"v2ray-password\"\n\t\t\t}`,\n\t\t\tParser: loadJSON(creator),\n\t\t\tOutput: &shadowsocks.ServerConfig{\n\t\t\t\tUser: &protocol.User{\n\t\t\t\t\tAccount: serial.ToTypedMessage(&shadowsocks.Account{\n\t\t\t\t\t\tCipherType: shadowsocks.CipherType_AES_128_CFB,\n\t\t\t\t\t\tPassword:   \"v2ray-password\",\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "infra/conf/socks.go",
    "content": "package conf\n\nimport (\n\t\"encoding/json\"\n\n\t\"github.com/golang/protobuf/proto\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/serial\"\n\t\"v2ray.com/core/proxy/socks\"\n)\n\ntype SocksAccount struct {\n\tUsername string `json:\"user\"`\n\tPassword string `json:\"pass\"`\n}\n\nfunc (v *SocksAccount) Build() *socks.Account {\n\treturn &socks.Account{\n\t\tUsername: v.Username,\n\t\tPassword: v.Password,\n\t}\n}\n\nconst (\n\tAuthMethodNoAuth   = \"noauth\"\n\tAuthMethodUserPass = \"password\"\n)\n\ntype SocksServerConfig struct {\n\tAuthMethod string          `json:\"auth\"`\n\tAccounts   []*SocksAccount `json:\"accounts\"`\n\tUDP        bool            `json:\"udp\"`\n\tHost       *Address        `json:\"ip\"`\n\tTimeout    uint32          `json:\"timeout\"`\n\tUserLevel  uint32          `json:\"userLevel\"`\n}\n\nfunc (v *SocksServerConfig) Build() (proto.Message, error) {\n\tconfig := new(socks.ServerConfig)\n\tswitch v.AuthMethod {\n\tcase AuthMethodNoAuth:\n\t\tconfig.AuthType = socks.AuthType_NO_AUTH\n\tcase AuthMethodUserPass:\n\t\tconfig.AuthType = socks.AuthType_PASSWORD\n\tdefault:\n\t\t//newError(\"unknown socks auth method: \", v.AuthMethod, \". Default to noauth.\").AtWarning().WriteToLog()\n\t\tconfig.AuthType = socks.AuthType_NO_AUTH\n\t}\n\n\tif len(v.Accounts) > 0 {\n\t\tconfig.Accounts = make(map[string]string, len(v.Accounts))\n\t\tfor _, account := range v.Accounts {\n\t\t\tconfig.Accounts[account.Username] = account.Password\n\t\t}\n\t}\n\n\tconfig.UdpEnabled = v.UDP\n\tif v.Host != nil {\n\t\tconfig.Address = v.Host.Build()\n\t}\n\n\tconfig.Timeout = v.Timeout\n\tconfig.UserLevel = v.UserLevel\n\treturn config, nil\n}\n\ntype SocksRemoteConfig struct {\n\tAddress *Address          `json:\"address\"`\n\tPort    uint16            `json:\"port\"`\n\tUsers   []json.RawMessage `json:\"users\"`\n}\ntype SocksClientConfig struct {\n\tServers []*SocksRemoteConfig `json:\"servers\"`\n}\n\nfunc (v *SocksClientConfig) Build() (proto.Message, error) {\n\tconfig := new(socks.ClientConfig)\n\tconfig.Server = make([]*protocol.ServerEndpoint, len(v.Servers))\n\tfor idx, serverConfig := range v.Servers {\n\t\tserver := &protocol.ServerEndpoint{\n\t\t\tAddress: serverConfig.Address.Build(),\n\t\t\tPort:    uint32(serverConfig.Port),\n\t\t}\n\t\tfor _, rawUser := range serverConfig.Users {\n\t\t\tuser := new(protocol.User)\n\t\t\tif err := json.Unmarshal(rawUser, user); err != nil {\n\t\t\t\treturn nil, newError(\"failed to parse Socks user\").Base(err).AtError()\n\t\t\t}\n\t\t\taccount := new(SocksAccount)\n\t\t\tif err := json.Unmarshal(rawUser, account); err != nil {\n\t\t\t\treturn nil, newError(\"failed to parse socks account\").Base(err).AtError()\n\t\t\t}\n\t\t\tuser.Account = serial.ToTypedMessage(account.Build())\n\t\t\tserver.User = append(server.User, user)\n\t\t}\n\t\tconfig.Server[idx] = server\n\t}\n\treturn config, nil\n}\n"
  },
  {
    "path": "infra/conf/socks_test.go",
    "content": "package conf_test\n\nimport (\n\t\"testing\"\n\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/serial\"\n\t. \"v2ray.com/core/infra/conf\"\n\t\"v2ray.com/core/proxy/socks\"\n)\n\nfunc TestSocksInboundConfig(t *testing.T) {\n\tcreator := func() Buildable {\n\t\treturn new(SocksServerConfig)\n\t}\n\n\trunMultiTestCase(t, []TestCase{\n\t\t{\n\t\t\tInput: `{\n\t\t\t\t\"auth\": \"password\",\n\t\t\t\t\"accounts\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"user\": \"my-username\",\n\t\t\t\t\t\t\"pass\": \"my-password\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"udp\": false,\n\t\t\t\t\"ip\": \"127.0.0.1\",\n\t\t\t\t\"timeout\": 5,\n\t\t\t\t\"userLevel\": 1\n\t\t\t}`,\n\t\t\tParser: loadJSON(creator),\n\t\t\tOutput: &socks.ServerConfig{\n\t\t\t\tAuthType: socks.AuthType_PASSWORD,\n\t\t\t\tAccounts: map[string]string{\n\t\t\t\t\t\"my-username\": \"my-password\",\n\t\t\t\t},\n\t\t\t\tUdpEnabled: false,\n\t\t\t\tAddress: &net.IPOrDomain{\n\t\t\t\t\tAddress: &net.IPOrDomain_Ip{\n\t\t\t\t\t\tIp: []byte{127, 0, 0, 1},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tTimeout:   5,\n\t\t\t\tUserLevel: 1,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestSocksOutboundConfig(t *testing.T) {\n\tcreator := func() Buildable {\n\t\treturn new(SocksClientConfig)\n\t}\n\n\trunMultiTestCase(t, []TestCase{\n\t\t{\n\t\t\tInput: `{\n\t\t\t\t\"servers\": [{\n\t\t\t\t\t\"address\": \"127.0.0.1\",\n\t\t\t\t\t\"port\": 1234,\n\t\t\t\t\t\"users\": [\n\t\t\t\t\t\t{\"user\": \"test user\", \"pass\": \"test pass\", \"email\": \"test@email.com\"}\n\t\t\t\t\t]\n\t\t\t\t}]\n\t\t\t}`,\n\t\t\tParser: loadJSON(creator),\n\t\t\tOutput: &socks.ClientConfig{\n\t\t\t\tServer: []*protocol.ServerEndpoint{\n\t\t\t\t\t{\n\t\t\t\t\t\tAddress: &net.IPOrDomain{\n\t\t\t\t\t\t\tAddress: &net.IPOrDomain_Ip{\n\t\t\t\t\t\t\t\tIp: []byte{127, 0, 0, 1},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tPort: 1234,\n\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tEmail: \"test@email.com\",\n\t\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&socks.Account{\n\t\t\t\t\t\t\t\t\tUsername: \"test user\",\n\t\t\t\t\t\t\t\t\tPassword: \"test pass\",\n\t\t\t\t\t\t\t\t}),\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},\n\t})\n}\n"
  },
  {
    "path": "infra/conf/transport.go",
    "content": "package conf\n\nimport (\n\t\"v2ray.com/core/common/serial\"\n\t\"v2ray.com/core/transport\"\n\t\"v2ray.com/core/transport/internet\"\n)\n\ntype TransportConfig struct {\n\tTCPConfig  *TCPConfig          `json:\"tcpSettings\"`\n\tKCPConfig  *KCPConfig          `json:\"kcpSettings\"`\n\tWSConfig   *WebSocketConfig    `json:\"wsSettings\"`\n\tHTTPConfig *HTTPConfig         `json:\"httpSettings\"`\n\tDSConfig   *DomainSocketConfig `json:\"dsSettings\"`\n\tQUICConfig *QUICConfig         `json:\"quicSettings\"`\n}\n\n// Build implements Buildable.\nfunc (c *TransportConfig) Build() (*transport.Config, error) {\n\tconfig := new(transport.Config)\n\n\tif c.TCPConfig != nil {\n\t\tts, err := c.TCPConfig.Build()\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"failed to build TCP config\").Base(err).AtError()\n\t\t}\n\t\tconfig.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{\n\t\t\tProtocolName: \"tcp\",\n\t\t\tSettings:     serial.ToTypedMessage(ts),\n\t\t})\n\t}\n\n\tif c.KCPConfig != nil {\n\t\tts, err := c.KCPConfig.Build()\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"failed to build mKCP config\").Base(err).AtError()\n\t\t}\n\t\tconfig.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{\n\t\t\tProtocolName: \"mkcp\",\n\t\t\tSettings:     serial.ToTypedMessage(ts),\n\t\t})\n\t}\n\n\tif c.WSConfig != nil {\n\t\tts, err := c.WSConfig.Build()\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"failed to build WebSocket config\").Base(err)\n\t\t}\n\t\tconfig.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{\n\t\t\tProtocolName: \"websocket\",\n\t\t\tSettings:     serial.ToTypedMessage(ts),\n\t\t})\n\t}\n\n\tif c.HTTPConfig != nil {\n\t\tts, err := c.HTTPConfig.Build()\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"Failed to build HTTP config.\").Base(err)\n\t\t}\n\t\tconfig.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{\n\t\t\tProtocolName: \"http\",\n\t\t\tSettings:     serial.ToTypedMessage(ts),\n\t\t})\n\t}\n\n\tif c.DSConfig != nil {\n\t\tds, err := c.DSConfig.Build()\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"Failed to build DomainSocket config.\").Base(err)\n\t\t}\n\t\tconfig.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{\n\t\t\tProtocolName: \"domainsocket\",\n\t\t\tSettings:     serial.ToTypedMessage(ds),\n\t\t})\n\t}\n\n\tif c.QUICConfig != nil {\n\t\tqs, err := c.QUICConfig.Build()\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"Failed to build QUIC config.\").Base(err)\n\t\t}\n\t\tconfig.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{\n\t\t\tProtocolName: \"quic\",\n\t\t\tSettings:     serial.ToTypedMessage(qs),\n\t\t})\n\t}\n\n\treturn config, nil\n}\n"
  },
  {
    "path": "infra/conf/transport_authenticators.go",
    "content": "package conf\n\nimport (\n\t\"sort\"\n\n\t\"github.com/golang/protobuf/proto\"\n\n\t\"v2ray.com/core/transport/internet/headers/http\"\n\t\"v2ray.com/core/transport/internet/headers/noop\"\n\t\"v2ray.com/core/transport/internet/headers/srtp\"\n\t\"v2ray.com/core/transport/internet/headers/tls\"\n\t\"v2ray.com/core/transport/internet/headers/utp\"\n\t\"v2ray.com/core/transport/internet/headers/wechat\"\n\t\"v2ray.com/core/transport/internet/headers/wireguard\"\n)\n\ntype NoOpAuthenticator struct{}\n\nfunc (NoOpAuthenticator) Build() (proto.Message, error) {\n\treturn new(noop.Config), nil\n}\n\ntype NoOpConnectionAuthenticator struct{}\n\nfunc (NoOpConnectionAuthenticator) Build() (proto.Message, error) {\n\treturn new(noop.ConnectionConfig), nil\n}\n\ntype SRTPAuthenticator struct{}\n\nfunc (SRTPAuthenticator) Build() (proto.Message, error) {\n\treturn new(srtp.Config), nil\n}\n\ntype UTPAuthenticator struct{}\n\nfunc (UTPAuthenticator) Build() (proto.Message, error) {\n\treturn new(utp.Config), nil\n}\n\ntype WechatVideoAuthenticator struct{}\n\nfunc (WechatVideoAuthenticator) Build() (proto.Message, error) {\n\treturn new(wechat.VideoConfig), nil\n}\n\ntype WireguardAuthenticator struct{}\n\nfunc (WireguardAuthenticator) Build() (proto.Message, error) {\n\treturn new(wireguard.WireguardConfig), nil\n}\n\ntype DTLSAuthenticator struct{}\n\nfunc (DTLSAuthenticator) Build() (proto.Message, error) {\n\treturn new(tls.PacketConfig), nil\n}\n\ntype HTTPAuthenticatorRequest struct {\n\tVersion string                 `json:\"version\"`\n\tMethod  string                 `json:\"method\"`\n\tPath    StringList             `json:\"path\"`\n\tHeaders map[string]*StringList `json:\"headers\"`\n}\n\nfunc sortMapKeys(m map[string]*StringList) []string {\n\tvar keys []string\n\tfor key := range m {\n\t\tkeys = append(keys, key)\n\t}\n\tsort.Strings(keys)\n\treturn keys\n}\n\nfunc (v *HTTPAuthenticatorRequest) Build() (*http.RequestConfig, error) {\n\tconfig := &http.RequestConfig{\n\t\tUri: []string{\"/\"},\n\t\tHeader: []*http.Header{\n\t\t\t{\n\t\t\t\tName:  \"Host\",\n\t\t\t\tValue: []string{\"www.baidu.com\", \"www.bing.com\"},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"User-Agent\",\n\t\t\t\tValue: []string{\n\t\t\t\t\t\"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36\",\n\t\t\t\t\t\"Mozilla/5.0 (iPhone; CPU iPhone OS 10_0_2 like Mac OS X) AppleWebKit/601.1 (KHTML, like Gecko) CriOS/53.0.2785.109 Mobile/14A456 Safari/601.1.46\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:  \"Accept-Encoding\",\n\t\t\t\tValue: []string{\"gzip, deflate\"},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:  \"Connection\",\n\t\t\t\tValue: []string{\"keep-alive\"},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:  \"Pragma\",\n\t\t\t\tValue: []string{\"no-cache\"},\n\t\t\t},\n\t\t},\n\t}\n\n\tif len(v.Version) > 0 {\n\t\tconfig.Version = &http.Version{Value: v.Version}\n\t}\n\n\tif len(v.Method) > 0 {\n\t\tconfig.Method = &http.Method{Value: v.Method}\n\t}\n\n\tif len(v.Path) > 0 {\n\t\tconfig.Uri = append([]string(nil), (v.Path)...)\n\t}\n\n\tif len(v.Headers) > 0 {\n\t\tconfig.Header = make([]*http.Header, 0, len(v.Headers))\n\t\theaderNames := sortMapKeys(v.Headers)\n\t\tfor _, key := range headerNames {\n\t\t\tvalue := v.Headers[key]\n\t\t\tif value == nil {\n\t\t\t\treturn nil, newError(\"empty HTTP header value: \" + key).AtError()\n\t\t\t}\n\t\t\tconfig.Header = append(config.Header, &http.Header{\n\t\t\t\tName:  key,\n\t\t\t\tValue: append([]string(nil), (*value)...),\n\t\t\t})\n\t\t}\n\t}\n\n\treturn config, nil\n}\n\ntype HTTPAuthenticatorResponse struct {\n\tVersion string                 `json:\"version\"`\n\tStatus  string                 `json:\"status\"`\n\tReason  string                 `json:\"reason\"`\n\tHeaders map[string]*StringList `json:\"headers\"`\n}\n\nfunc (v *HTTPAuthenticatorResponse) Build() (*http.ResponseConfig, error) {\n\tconfig := &http.ResponseConfig{\n\t\tHeader: []*http.Header{\n\t\t\t{\n\t\t\t\tName:  \"Content-Type\",\n\t\t\t\tValue: []string{\"application/octet-stream\", \"video/mpeg\"},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:  \"Transfer-Encoding\",\n\t\t\t\tValue: []string{\"chunked\"},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:  \"Connection\",\n\t\t\t\tValue: []string{\"keep-alive\"},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:  \"Pragma\",\n\t\t\t\tValue: []string{\"no-cache\"},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:  \"Cache-Control\",\n\t\t\t\tValue: []string{\"private\", \"no-cache\"},\n\t\t\t},\n\t\t},\n\t}\n\n\tif len(v.Version) > 0 {\n\t\tconfig.Version = &http.Version{Value: v.Version}\n\t}\n\n\tif len(v.Status) > 0 || len(v.Reason) > 0 {\n\t\tconfig.Status = &http.Status{\n\t\t\tCode:   \"200\",\n\t\t\tReason: \"OK\",\n\t\t}\n\t\tif len(v.Status) > 0 {\n\t\t\tconfig.Status.Code = v.Status\n\t\t}\n\t\tif len(v.Reason) > 0 {\n\t\t\tconfig.Status.Reason = v.Reason\n\t\t}\n\t}\n\n\tif len(v.Headers) > 0 {\n\t\tconfig.Header = make([]*http.Header, 0, len(v.Headers))\n\t\theaderNames := sortMapKeys(v.Headers)\n\t\tfor _, key := range headerNames {\n\t\t\tvalue := v.Headers[key]\n\t\t\tif value == nil {\n\t\t\t\treturn nil, newError(\"empty HTTP header value: \" + key).AtError()\n\t\t\t}\n\t\t\tconfig.Header = append(config.Header, &http.Header{\n\t\t\t\tName:  key,\n\t\t\t\tValue: append([]string(nil), (*value)...),\n\t\t\t})\n\t\t}\n\t}\n\n\treturn config, nil\n}\n\ntype HTTPAuthenticator struct {\n\tRequest  HTTPAuthenticatorRequest  `json:\"request\"`\n\tResponse HTTPAuthenticatorResponse `json:\"response\"`\n}\n\nfunc (v *HTTPAuthenticator) Build() (proto.Message, error) {\n\tconfig := new(http.Config)\n\trequestConfig, err := v.Request.Build()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tconfig.Request = requestConfig\n\n\tresponseConfig, err := v.Response.Build()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tconfig.Response = responseConfig\n\n\treturn config, nil\n}\n"
  },
  {
    "path": "infra/conf/transport_internet.go",
    "content": "package conf\n\nimport (\n\t\"encoding/json\"\n\t\"strings\"\n\n\t\"github.com/golang/protobuf/proto\"\n\t\"v2ray.com/core/common/platform/filesystem\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/serial\"\n\t\"v2ray.com/core/transport/internet\"\n\t\"v2ray.com/core/transport/internet/domainsocket\"\n\t\"v2ray.com/core/transport/internet/http\"\n\t\"v2ray.com/core/transport/internet/kcp\"\n\t\"v2ray.com/core/transport/internet/quic\"\n\t\"v2ray.com/core/transport/internet/tcp\"\n\t\"v2ray.com/core/transport/internet/tls\"\n\t\"v2ray.com/core/transport/internet/websocket\"\n\t\"v2ray.com/core/transport/internet/xtls\"\n)\n\nvar (\n\tkcpHeaderLoader = NewJSONConfigLoader(ConfigCreatorCache{\n\t\t\"none\":         func() interface{} { return new(NoOpAuthenticator) },\n\t\t\"srtp\":         func() interface{} { return new(SRTPAuthenticator) },\n\t\t\"utp\":          func() interface{} { return new(UTPAuthenticator) },\n\t\t\"wechat-video\": func() interface{} { return new(WechatVideoAuthenticator) },\n\t\t\"dtls\":         func() interface{} { return new(DTLSAuthenticator) },\n\t\t\"wireguard\":    func() interface{} { return new(WireguardAuthenticator) },\n\t}, \"type\", \"\")\n\n\ttcpHeaderLoader = NewJSONConfigLoader(ConfigCreatorCache{\n\t\t\"none\": func() interface{} { return new(NoOpConnectionAuthenticator) },\n\t\t\"http\": func() interface{} { return new(HTTPAuthenticator) },\n\t}, \"type\", \"\")\n)\n\ntype KCPConfig struct {\n\tMtu             *uint32         `json:\"mtu\"`\n\tTti             *uint32         `json:\"tti\"`\n\tUpCap           *uint32         `json:\"uplinkCapacity\"`\n\tDownCap         *uint32         `json:\"downlinkCapacity\"`\n\tCongestion      *bool           `json:\"congestion\"`\n\tReadBufferSize  *uint32         `json:\"readBufferSize\"`\n\tWriteBufferSize *uint32         `json:\"writeBufferSize\"`\n\tHeaderConfig    json.RawMessage `json:\"header\"`\n\tSeed            *string         `json:\"seed\"`\n}\n\n// Build implements Buildable.\nfunc (c *KCPConfig) Build() (proto.Message, error) {\n\tconfig := new(kcp.Config)\n\n\tif c.Mtu != nil {\n\t\tmtu := *c.Mtu\n\t\tif mtu < 576 || mtu > 1460 {\n\t\t\treturn nil, newError(\"invalid mKCP MTU size: \", mtu).AtError()\n\t\t}\n\t\tconfig.Mtu = &kcp.MTU{Value: mtu}\n\t}\n\tif c.Tti != nil {\n\t\ttti := *c.Tti\n\t\tif tti < 10 || tti > 100 {\n\t\t\treturn nil, newError(\"invalid mKCP TTI: \", tti).AtError()\n\t\t}\n\t\tconfig.Tti = &kcp.TTI{Value: tti}\n\t}\n\tif c.UpCap != nil {\n\t\tconfig.UplinkCapacity = &kcp.UplinkCapacity{Value: *c.UpCap}\n\t}\n\tif c.DownCap != nil {\n\t\tconfig.DownlinkCapacity = &kcp.DownlinkCapacity{Value: *c.DownCap}\n\t}\n\tif c.Congestion != nil {\n\t\tconfig.Congestion = *c.Congestion\n\t}\n\tif c.ReadBufferSize != nil {\n\t\tsize := *c.ReadBufferSize\n\t\tif size > 0 {\n\t\t\tconfig.ReadBuffer = &kcp.ReadBuffer{Size: size * 1024 * 1024}\n\t\t} else {\n\t\t\tconfig.ReadBuffer = &kcp.ReadBuffer{Size: 512 * 1024}\n\t\t}\n\t}\n\tif c.WriteBufferSize != nil {\n\t\tsize := *c.WriteBufferSize\n\t\tif size > 0 {\n\t\t\tconfig.WriteBuffer = &kcp.WriteBuffer{Size: size * 1024 * 1024}\n\t\t} else {\n\t\t\tconfig.WriteBuffer = &kcp.WriteBuffer{Size: 512 * 1024}\n\t\t}\n\t}\n\tif len(c.HeaderConfig) > 0 {\n\t\theaderConfig, _, err := kcpHeaderLoader.Load(c.HeaderConfig)\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"invalid mKCP header config.\").Base(err).AtError()\n\t\t}\n\t\tts, err := headerConfig.(Buildable).Build()\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"invalid mKCP header config\").Base(err).AtError()\n\t\t}\n\t\tconfig.HeaderConfig = serial.ToTypedMessage(ts)\n\t}\n\n\tif c.Seed != nil {\n\t\tconfig.Seed = &kcp.EncryptionSeed{Seed: *c.Seed}\n\t}\n\n\treturn config, nil\n}\n\ntype TCPConfig struct {\n\tHeaderConfig        json.RawMessage `json:\"header\"`\n\tAcceptProxyProtocol bool            `json:\"acceptProxyProtocol\"`\n}\n\n// Build implements Buildable.\nfunc (c *TCPConfig) Build() (proto.Message, error) {\n\tconfig := new(tcp.Config)\n\tif len(c.HeaderConfig) > 0 {\n\t\theaderConfig, _, err := tcpHeaderLoader.Load(c.HeaderConfig)\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"invalid TCP header config\").Base(err).AtError()\n\t\t}\n\t\tts, err := headerConfig.(Buildable).Build()\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"invalid TCP header config\").Base(err).AtError()\n\t\t}\n\t\tconfig.HeaderSettings = serial.ToTypedMessage(ts)\n\t}\n\tif c.AcceptProxyProtocol {\n\t\tconfig.AcceptProxyProtocol = c.AcceptProxyProtocol\n\t}\n\treturn config, nil\n}\n\ntype WebSocketConfig struct {\n\tPath                string            `json:\"path\"`\n\tPath2               string            `json:\"Path\"` // The key was misspelled. For backward compatibility, we have to keep track the old key.\n\tHeaders             map[string]string `json:\"headers\"`\n\tAcceptProxyProtocol bool              `json:\"acceptProxyProtocol\"`\n}\n\n// Build implements Buildable.\nfunc (c *WebSocketConfig) Build() (proto.Message, error) {\n\tpath := c.Path\n\tif path == \"\" && c.Path2 != \"\" {\n\t\tpath = c.Path2\n\t}\n\theader := make([]*websocket.Header, 0, 32)\n\tfor key, value := range c.Headers {\n\t\theader = append(header, &websocket.Header{\n\t\t\tKey:   key,\n\t\t\tValue: value,\n\t\t})\n\t}\n\tconfig := &websocket.Config{\n\t\tPath:   path,\n\t\tHeader: header,\n\t}\n\tif c.AcceptProxyProtocol {\n\t\tconfig.AcceptProxyProtocol = c.AcceptProxyProtocol\n\t}\n\treturn config, nil\n}\n\ntype HTTPConfig struct {\n\tHost *StringList `json:\"host\"`\n\tPath string      `json:\"path\"`\n}\n\n// Build implements Buildable.\nfunc (c *HTTPConfig) Build() (proto.Message, error) {\n\tconfig := &http.Config{\n\t\tPath: c.Path,\n\t}\n\tif c.Host != nil {\n\t\tconfig.Host = []string(*c.Host)\n\t}\n\treturn config, nil\n}\n\ntype QUICConfig struct {\n\tHeader   json.RawMessage `json:\"header\"`\n\tSecurity string          `json:\"security\"`\n\tKey      string          `json:\"key\"`\n}\n\n// Build implements Buildable.\nfunc (c *QUICConfig) Build() (proto.Message, error) {\n\tconfig := &quic.Config{\n\t\tKey: c.Key,\n\t}\n\n\tif len(c.Header) > 0 {\n\t\theaderConfig, _, err := kcpHeaderLoader.Load(c.Header)\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"invalid QUIC header config.\").Base(err).AtError()\n\t\t}\n\t\tts, err := headerConfig.(Buildable).Build()\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"invalid QUIC header config\").Base(err).AtError()\n\t\t}\n\t\tconfig.Header = serial.ToTypedMessage(ts)\n\t}\n\n\tvar st protocol.SecurityType\n\tswitch strings.ToLower(c.Security) {\n\tcase \"aes-128-gcm\":\n\t\tst = protocol.SecurityType_AES128_GCM\n\tcase \"chacha20-poly1305\":\n\t\tst = protocol.SecurityType_CHACHA20_POLY1305\n\tdefault:\n\t\tst = protocol.SecurityType_NONE\n\t}\n\n\tconfig.Security = &protocol.SecurityConfig{\n\t\tType: st,\n\t}\n\n\treturn config, nil\n}\n\ntype DomainSocketConfig struct {\n\tPath                string `json:\"path\"`\n\tAbstract            bool   `json:\"abstract\"`\n\tPadding             bool   `json:\"padding\"`\n\tAcceptProxyProtocol bool   `json:\"acceptProxyProtocol\"`\n}\n\n// Build implements Buildable.\nfunc (c *DomainSocketConfig) Build() (proto.Message, error) {\n\treturn &domainsocket.Config{\n\t\tPath:                c.Path,\n\t\tAbstract:            c.Abstract,\n\t\tPadding:             c.Padding,\n\t\tAcceptProxyProtocol: c.AcceptProxyProtocol,\n\t}, nil\n}\n\nfunc readFileOrString(f string, s []string) ([]byte, error) {\n\tif len(f) > 0 {\n\t\treturn filesystem.ReadFile(f)\n\t}\n\tif len(s) > 0 {\n\t\treturn []byte(strings.Join(s, \"\\n\")), nil\n\t}\n\treturn nil, newError(\"both file and bytes are empty.\")\n}\n\ntype TLSCertConfig struct {\n\tCertFile string   `json:\"certificateFile\"`\n\tCertStr  []string `json:\"certificate\"`\n\tKeyFile  string   `json:\"keyFile\"`\n\tKeyStr   []string `json:\"key\"`\n\tUsage    string   `json:\"usage\"`\n}\n\n// Build implements Buildable.\nfunc (c *TLSCertConfig) Build() (*tls.Certificate, error) {\n\tcertificate := new(tls.Certificate)\n\n\tcert, err := readFileOrString(c.CertFile, c.CertStr)\n\tif err != nil {\n\t\treturn nil, newError(\"failed to parse certificate\").Base(err)\n\t}\n\tcertificate.Certificate = cert\n\n\tif len(c.KeyFile) > 0 || len(c.KeyStr) > 0 {\n\t\tkey, err := readFileOrString(c.KeyFile, c.KeyStr)\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"failed to parse key\").Base(err)\n\t\t}\n\t\tcertificate.Key = key\n\t}\n\n\tswitch strings.ToLower(c.Usage) {\n\tcase \"encipherment\":\n\t\tcertificate.Usage = tls.Certificate_ENCIPHERMENT\n\tcase \"verify\":\n\t\tcertificate.Usage = tls.Certificate_AUTHORITY_VERIFY\n\tcase \"issue\":\n\t\tcertificate.Usage = tls.Certificate_AUTHORITY_ISSUE\n\tdefault:\n\t\tcertificate.Usage = tls.Certificate_ENCIPHERMENT\n\t}\n\n\treturn certificate, nil\n}\n\ntype TLSConfig struct {\n\tInsecure                 bool             `json:\"allowInsecure\"`\n\tInsecureCiphers          bool             `json:\"allowInsecureCiphers\"`\n\tCerts                    []*TLSCertConfig `json:\"certificates\"`\n\tServerName               string           `json:\"serverName\"`\n\tALPN                     *StringList      `json:\"alpn\"`\n\tDisableSessionResumption bool             `json:\"disableSessionResumption\"`\n\tDisableSystemRoot        bool             `json:\"disableSystemRoot\"`\n}\n\n// Build implements Buildable.\nfunc (c *TLSConfig) Build() (proto.Message, error) {\n\tconfig := new(tls.Config)\n\tconfig.Certificate = make([]*tls.Certificate, len(c.Certs))\n\tfor idx, certConf := range c.Certs {\n\t\tcert, err := certConf.Build()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tconfig.Certificate[idx] = cert\n\t}\n\tserverName := c.ServerName\n\tconfig.AllowInsecure = c.Insecure\n\tconfig.AllowInsecureCiphers = c.InsecureCiphers\n\tif len(c.ServerName) > 0 {\n\t\tconfig.ServerName = serverName\n\t}\n\tif c.ALPN != nil && len(*c.ALPN) > 0 {\n\t\tconfig.NextProtocol = []string(*c.ALPN)\n\t}\n\tconfig.DisableSessionResumption = c.DisableSessionResumption\n\tconfig.DisableSystemRoot = c.DisableSystemRoot\n\treturn config, nil\n}\n\ntype XTLSCertConfig struct {\n\tCertFile string   `json:\"certificateFile\"`\n\tCertStr  []string `json:\"certificate\"`\n\tKeyFile  string   `json:\"keyFile\"`\n\tKeyStr   []string `json:\"key\"`\n\tUsage    string   `json:\"usage\"`\n}\n\n// Build implements Buildable.\nfunc (c *XTLSCertConfig) Build() (*xtls.Certificate, error) {\n\tcertificate := new(xtls.Certificate)\n\n\tcert, err := readFileOrString(c.CertFile, c.CertStr)\n\tif err != nil {\n\t\treturn nil, newError(\"failed to parse certificate\").Base(err)\n\t}\n\tcertificate.Certificate = cert\n\n\tif len(c.KeyFile) > 0 || len(c.KeyStr) > 0 {\n\t\tkey, err := readFileOrString(c.KeyFile, c.KeyStr)\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"failed to parse key\").Base(err)\n\t\t}\n\t\tcertificate.Key = key\n\t}\n\n\tswitch strings.ToLower(c.Usage) {\n\tcase \"encipherment\":\n\t\tcertificate.Usage = xtls.Certificate_ENCIPHERMENT\n\tcase \"verify\":\n\t\tcertificate.Usage = xtls.Certificate_AUTHORITY_VERIFY\n\tcase \"issue\":\n\t\tcertificate.Usage = xtls.Certificate_AUTHORITY_ISSUE\n\tdefault:\n\t\tcertificate.Usage = xtls.Certificate_ENCIPHERMENT\n\t}\n\n\treturn certificate, nil\n}\n\ntype XTLSConfig struct {\n\tInsecure                 bool              `json:\"allowInsecure\"`\n\tInsecureCiphers          bool              `json:\"allowInsecureCiphers\"`\n\tCerts                    []*XTLSCertConfig `json:\"certificates\"`\n\tServerName               string            `json:\"serverName\"`\n\tALPN                     *StringList       `json:\"alpn\"`\n\tDisableSessionResumption bool              `json:\"disableSessionResumption\"`\n\tDisableSystemRoot        bool              `json:\"disableSystemRoot\"`\n}\n\n// Build implements Buildable.\nfunc (c *XTLSConfig) Build() (proto.Message, error) {\n\tconfig := new(xtls.Config)\n\tconfig.Certificate = make([]*xtls.Certificate, len(c.Certs))\n\tfor idx, certConf := range c.Certs {\n\t\tcert, err := certConf.Build()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tconfig.Certificate[idx] = cert\n\t}\n\tserverName := c.ServerName\n\tconfig.AllowInsecure = c.Insecure\n\tconfig.AllowInsecureCiphers = c.InsecureCiphers\n\tif len(c.ServerName) > 0 {\n\t\tconfig.ServerName = serverName\n\t}\n\tif c.ALPN != nil && len(*c.ALPN) > 0 {\n\t\tconfig.NextProtocol = []string(*c.ALPN)\n\t}\n\tconfig.DisableSessionResumption = c.DisableSessionResumption\n\tconfig.DisableSystemRoot = c.DisableSystemRoot\n\treturn config, nil\n}\n\ntype TransportProtocol string\n\n// Build implements Buildable.\nfunc (p TransportProtocol) Build() (string, error) {\n\tswitch strings.ToLower(string(p)) {\n\tcase \"tcp\":\n\t\treturn \"tcp\", nil\n\tcase \"kcp\", \"mkcp\":\n\t\treturn \"mkcp\", nil\n\tcase \"ws\", \"websocket\":\n\t\treturn \"websocket\", nil\n\tcase \"h2\", \"http\":\n\t\treturn \"http\", nil\n\tcase \"ds\", \"domainsocket\":\n\t\treturn \"domainsocket\", nil\n\tcase \"quic\":\n\t\treturn \"quic\", nil\n\tdefault:\n\t\treturn \"\", newError(\"Config: unknown transport protocol: \", p)\n\t}\n}\n\ntype SocketConfig struct {\n\tMark   int32  `json:\"mark\"`\n\tTFO    *bool  `json:\"tcpFastOpen\"`\n\tTProxy string `json:\"tproxy\"`\n}\n\n// Build implements Buildable.\nfunc (c *SocketConfig) Build() (*internet.SocketConfig, error) {\n\tvar tfoSettings internet.SocketConfig_TCPFastOpenState\n\tif c.TFO != nil {\n\t\tif *c.TFO {\n\t\t\ttfoSettings = internet.SocketConfig_Enable\n\t\t} else {\n\t\t\ttfoSettings = internet.SocketConfig_Disable\n\t\t}\n\t}\n\tvar tproxy internet.SocketConfig_TProxyMode\n\tswitch strings.ToLower(c.TProxy) {\n\tcase \"tproxy\":\n\t\ttproxy = internet.SocketConfig_TProxy\n\tcase \"redirect\":\n\t\ttproxy = internet.SocketConfig_Redirect\n\tdefault:\n\t\ttproxy = internet.SocketConfig_Off\n\t}\n\n\treturn &internet.SocketConfig{\n\t\tMark:   c.Mark,\n\t\tTfo:    tfoSettings,\n\t\tTproxy: tproxy,\n\t}, nil\n}\n\ntype StreamConfig struct {\n\tNetwork        *TransportProtocol  `json:\"network\"`\n\tSecurity       string              `json:\"security\"`\n\tTLSSettings    *TLSConfig          `json:\"tlsSettings\"`\n\tXTLSSettings   *XTLSConfig         `json:\"xtlsSettings\"`\n\tTCPSettings    *TCPConfig          `json:\"tcpSettings\"`\n\tKCPSettings    *KCPConfig          `json:\"kcpSettings\"`\n\tWSSettings     *WebSocketConfig    `json:\"wsSettings\"`\n\tHTTPSettings   *HTTPConfig         `json:\"httpSettings\"`\n\tDSSettings     *DomainSocketConfig `json:\"dsSettings\"`\n\tQUICSettings   *QUICConfig         `json:\"quicSettings\"`\n\tSocketSettings *SocketConfig       `json:\"sockopt\"`\n}\n\n// Build implements Buildable.\nfunc (c *StreamConfig) Build() (*internet.StreamConfig, error) {\n\tconfig := &internet.StreamConfig{\n\t\tProtocolName: \"tcp\",\n\t}\n\tif c.Network != nil {\n\t\tprotocol, err := (*c.Network).Build()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tconfig.ProtocolName = protocol\n\t}\n\tif strings.EqualFold(c.Security, \"tls\") {\n\t\ttlsSettings := c.TLSSettings\n\t\tif tlsSettings == nil {\n\t\t\tif c.XTLSSettings != nil {\n\t\t\t\treturn nil, newError(`TLS: Please use \"tlsSettings\" instead of \"xtlsSettings\".`)\n\t\t\t}\n\t\t\ttlsSettings = &TLSConfig{}\n\t\t}\n\t\tts, err := tlsSettings.Build()\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"Failed to build TLS config.\").Base(err)\n\t\t}\n\t\ttm := serial.ToTypedMessage(ts)\n\t\tconfig.SecuritySettings = append(config.SecuritySettings, tm)\n\t\tconfig.SecurityType = tm.Type\n\t}\n\tif strings.EqualFold(c.Security, \"xtls\") {\n\t\tif config.ProtocolName != \"tcp\" && config.ProtocolName != \"mkcp\" && config.ProtocolName != \"domainsocket\" {\n\t\t\treturn nil, newError(\"XTLS only supports TCP, mKCP and DomainSocket for now.\")\n\t\t}\n\t\txtlsSettings := c.XTLSSettings\n\t\tif xtlsSettings == nil {\n\t\t\tif c.TLSSettings != nil {\n\t\t\t\treturn nil, newError(`XTLS: Please use \"xtlsSettings\" instead of \"tlsSettings\".`)\n\t\t\t}\n\t\t\txtlsSettings = &XTLSConfig{}\n\t\t}\n\t\tts, err := xtlsSettings.Build()\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"Failed to build XTLS config.\").Base(err)\n\t\t}\n\t\ttm := serial.ToTypedMessage(ts)\n\t\tconfig.SecuritySettings = append(config.SecuritySettings, tm)\n\t\tconfig.SecurityType = tm.Type\n\t}\n\tif c.TCPSettings != nil {\n\t\tts, err := c.TCPSettings.Build()\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"Failed to build TCP config.\").Base(err)\n\t\t}\n\t\tconfig.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{\n\t\t\tProtocolName: \"tcp\",\n\t\t\tSettings:     serial.ToTypedMessage(ts),\n\t\t})\n\t}\n\tif c.KCPSettings != nil {\n\t\tts, err := c.KCPSettings.Build()\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"Failed to build mKCP config.\").Base(err)\n\t\t}\n\t\tconfig.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{\n\t\t\tProtocolName: \"mkcp\",\n\t\t\tSettings:     serial.ToTypedMessage(ts),\n\t\t})\n\t}\n\tif c.WSSettings != nil {\n\t\tts, err := c.WSSettings.Build()\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"Failed to build WebSocket config.\").Base(err)\n\t\t}\n\t\tconfig.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{\n\t\t\tProtocolName: \"websocket\",\n\t\t\tSettings:     serial.ToTypedMessage(ts),\n\t\t})\n\t}\n\tif c.HTTPSettings != nil {\n\t\tts, err := c.HTTPSettings.Build()\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"Failed to build HTTP config.\").Base(err)\n\t\t}\n\t\tconfig.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{\n\t\t\tProtocolName: \"http\",\n\t\t\tSettings:     serial.ToTypedMessage(ts),\n\t\t})\n\t}\n\tif c.DSSettings != nil {\n\t\tds, err := c.DSSettings.Build()\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"Failed to build DomainSocket config.\").Base(err)\n\t\t}\n\t\tconfig.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{\n\t\t\tProtocolName: \"domainsocket\",\n\t\t\tSettings:     serial.ToTypedMessage(ds),\n\t\t})\n\t}\n\tif c.QUICSettings != nil {\n\t\tqs, err := c.QUICSettings.Build()\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"Failed to build QUIC config\").Base(err)\n\t\t}\n\t\tconfig.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{\n\t\t\tProtocolName: \"quic\",\n\t\t\tSettings:     serial.ToTypedMessage(qs),\n\t\t})\n\t}\n\tif c.SocketSettings != nil {\n\t\tss, err := c.SocketSettings.Build()\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"Failed to build sockopt\").Base(err)\n\t\t}\n\t\tconfig.SocketSettings = ss\n\t}\n\treturn config, nil\n}\n\ntype ProxyConfig struct {\n\tTag string `json:\"tag\"`\n}\n\n// Build implements Buildable.\nfunc (v *ProxyConfig) Build() (*internet.ProxyConfig, error) {\n\tif v.Tag == \"\" {\n\t\treturn nil, newError(\"Proxy tag is not set.\")\n\t}\n\treturn &internet.ProxyConfig{\n\t\tTag: v.Tag,\n\t}, nil\n}\n"
  },
  {
    "path": "infra/conf/transport_test.go",
    "content": "package conf_test\n\nimport (\n\t\"encoding/json\"\n\t\"testing\"\n\n\t\"github.com/golang/protobuf/proto\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/serial\"\n\t. \"v2ray.com/core/infra/conf\"\n\t\"v2ray.com/core/transport\"\n\t\"v2ray.com/core/transport/internet\"\n\t\"v2ray.com/core/transport/internet/headers/http\"\n\t\"v2ray.com/core/transport/internet/headers/noop\"\n\t\"v2ray.com/core/transport/internet/headers/tls\"\n\t\"v2ray.com/core/transport/internet/kcp\"\n\t\"v2ray.com/core/transport/internet/quic\"\n\t\"v2ray.com/core/transport/internet/tcp\"\n\t\"v2ray.com/core/transport/internet/websocket\"\n)\n\nfunc TestSocketConfig(t *testing.T) {\n\tcreateParser := func() func(string) (proto.Message, error) {\n\t\treturn func(s string) (proto.Message, error) {\n\t\t\tconfig := new(SocketConfig)\n\t\t\tif err := json.Unmarshal([]byte(s), config); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn config.Build()\n\t\t}\n\t}\n\n\trunMultiTestCase(t, []TestCase{\n\t\t{\n\t\t\tInput: `{\n\t\t\t\t\"mark\": 1,\n\t\t\t\t\"tcpFastOpen\": true\n\t\t\t}`,\n\t\t\tParser: createParser(),\n\t\t\tOutput: &internet.SocketConfig{\n\t\t\t\tMark: 1,\n\t\t\t\tTfo:  internet.SocketConfig_Enable,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestTransportConfig(t *testing.T) {\n\tcreateParser := func() func(string) (proto.Message, error) {\n\t\treturn func(s string) (proto.Message, error) {\n\t\t\tconfig := new(TransportConfig)\n\t\t\tif err := json.Unmarshal([]byte(s), config); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn config.Build()\n\t\t}\n\t}\n\n\trunMultiTestCase(t, []TestCase{\n\t\t{\n\t\t\tInput: `{\n\t\t\t\t\"tcpSettings\": {\n\t\t\t\t\t\"header\": {\n\t\t\t\t\t\t\"type\": \"http\",\n\t\t\t\t\t\t\"request\": {\n\t\t\t\t\t\t\t\"version\": \"1.1\",\n\t\t\t\t\t\t\t\"method\": \"GET\",\n\t\t\t\t\t\t\t\"path\": \"/b\",\n\t\t\t\t\t\t\t\"headers\": {\n\t\t\t\t\t\t\t\t\"a\": \"b\",\n\t\t\t\t\t\t\t\t\"c\": \"d\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"response\": {\n\t\t\t\t\t\t\t\"version\": \"1.0\",\n\t\t\t\t\t\t\t\"status\": \"404\",\n\t\t\t\t\t\t\t\"reason\": \"Not Found\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"kcpSettings\": {\n\t\t\t\t\t\"mtu\": 1200,\n\t\t\t\t\t\"header\": {\n\t\t\t\t\t\t\"type\": \"none\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"wsSettings\": {\n\t\t\t\t\t\"path\": \"/t\"\n\t\t\t\t},\n\t\t\t\t\"quicSettings\": {\n\t\t\t\t\t\"key\": \"abcd\",\n\t\t\t\t\t\"header\": {\n\t\t\t\t\t\t\"type\": \"dtls\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}`,\n\t\t\tParser: createParser(),\n\t\t\tOutput: &transport.Config{\n\t\t\t\tTransportSettings: []*internet.TransportConfig{\n\t\t\t\t\t{\n\t\t\t\t\t\tProtocolName: \"tcp\",\n\t\t\t\t\t\tSettings: serial.ToTypedMessage(&tcp.Config{\n\t\t\t\t\t\t\tHeaderSettings: serial.ToTypedMessage(&http.Config{\n\t\t\t\t\t\t\t\tRequest: &http.RequestConfig{\n\t\t\t\t\t\t\t\t\tVersion: &http.Version{Value: \"1.1\"},\n\t\t\t\t\t\t\t\t\tMethod:  &http.Method{Value: \"GET\"},\n\t\t\t\t\t\t\t\t\tUri:     []string{\"/b\"},\n\t\t\t\t\t\t\t\t\tHeader: []*http.Header{\n\t\t\t\t\t\t\t\t\t\t{Name: \"a\", Value: []string{\"b\"}},\n\t\t\t\t\t\t\t\t\t\t{Name: \"c\", Value: []string{\"d\"}},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tResponse: &http.ResponseConfig{\n\t\t\t\t\t\t\t\t\tVersion: &http.Version{Value: \"1.0\"},\n\t\t\t\t\t\t\t\t\tStatus:  &http.Status{Code: \"404\", Reason: \"Not Found\"},\n\t\t\t\t\t\t\t\t\tHeader: []*http.Header{\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tName:  \"Content-Type\",\n\t\t\t\t\t\t\t\t\t\t\tValue: []string{\"application/octet-stream\", \"video/mpeg\"},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tName:  \"Transfer-Encoding\",\n\t\t\t\t\t\t\t\t\t\t\tValue: []string{\"chunked\"},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tName:  \"Connection\",\n\t\t\t\t\t\t\t\t\t\t\tValue: []string{\"keep-alive\"},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tName:  \"Pragma\",\n\t\t\t\t\t\t\t\t\t\t\tValue: []string{\"no-cache\"},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tName:  \"Cache-Control\",\n\t\t\t\t\t\t\t\t\t\t\tValue: []string{\"private\", \"no-cache\"},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\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\t{\n\t\t\t\t\t\tProtocolName: \"mkcp\",\n\t\t\t\t\t\tSettings: serial.ToTypedMessage(&kcp.Config{\n\t\t\t\t\t\t\tMtu:          &kcp.MTU{Value: 1200},\n\t\t\t\t\t\t\tHeaderConfig: serial.ToTypedMessage(&noop.Config{}),\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\tProtocolName: \"websocket\",\n\t\t\t\t\t\tSettings: serial.ToTypedMessage(&websocket.Config{\n\t\t\t\t\t\t\tPath: \"/t\",\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\tProtocolName: \"quic\",\n\t\t\t\t\t\tSettings: serial.ToTypedMessage(&quic.Config{\n\t\t\t\t\t\t\tKey: \"abcd\",\n\t\t\t\t\t\t\tSecurity: &protocol.SecurityConfig{\n\t\t\t\t\t\t\t\tType: protocol.SecurityType_NONE,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tHeader: serial.ToTypedMessage(&tls.PacketConfig{}),\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"
  },
  {
    "path": "infra/conf/trojan.go",
    "content": "package conf\n\nimport (\n\t\"encoding/json\"\n\t\"runtime\"\n\t\"strconv\"\n\t\"syscall\"\n\n\t\"github.com/golang/protobuf/proto\" // nolint: staticcheck\n\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/serial\"\n\t\"v2ray.com/core/proxy/trojan\"\n)\n\n// TrojanServerTarget is configuration of a single trojan server\ntype TrojanServerTarget struct {\n\tAddress  *Address `json:\"address\"`\n\tPort     uint16   `json:\"port\"`\n\tPassword string   `json:\"password\"`\n\tEmail    string   `json:\"email\"`\n\tLevel    byte     `json:\"level\"`\n}\n\n// TrojanClientConfig is configuration of trojan servers\ntype TrojanClientConfig struct {\n\tServers []*TrojanServerTarget `json:\"servers\"`\n}\n\n// Build implements Buildable\nfunc (c *TrojanClientConfig) Build() (proto.Message, error) {\n\tconfig := new(trojan.ClientConfig)\n\n\tif len(c.Servers) == 0 {\n\t\treturn nil, newError(\"0 Trojan server configured.\")\n\t}\n\n\tserverSpecs := make([]*protocol.ServerEndpoint, len(c.Servers))\n\tfor idx, rec := range c.Servers {\n\t\tif rec.Address == nil {\n\t\t\treturn nil, newError(\"Trojan server address is not set.\")\n\t\t}\n\t\tif rec.Port == 0 {\n\t\t\treturn nil, newError(\"Invalid Trojan port.\")\n\t\t}\n\t\tif rec.Password == \"\" {\n\t\t\treturn nil, newError(\"Trojan password is not specified.\")\n\t\t}\n\t\taccount := &trojan.Account{\n\t\t\tPassword: rec.Password,\n\t\t}\n\t\ttrojan := &protocol.ServerEndpoint{\n\t\t\tAddress: rec.Address.Build(),\n\t\t\tPort:    uint32(rec.Port),\n\t\t\tUser: []*protocol.User{\n\t\t\t\t{\n\t\t\t\t\tLevel:   uint32(rec.Level),\n\t\t\t\t\tEmail:   rec.Email,\n\t\t\t\t\tAccount: serial.ToTypedMessage(account),\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\n\t\tserverSpecs[idx] = trojan\n\t}\n\n\tconfig.Server = serverSpecs\n\n\treturn config, nil\n}\n\n// TrojanInboundFallback is fallback configuration\ntype TrojanInboundFallback struct {\n\tAlpn string          `json:\"alpn\"`\n\tPath string          `json:\"path\"`\n\tType string          `json:\"type\"`\n\tDest json.RawMessage `json:\"dest\"`\n\tXver uint64          `json:\"xver\"`\n}\n\n// TrojanUserConfig is user configuration\ntype TrojanUserConfig struct {\n\tPassword string `json:\"password\"`\n\tLevel    byte   `json:\"level\"`\n\tEmail    string `json:\"email\"`\n}\n\n// TrojanServerConfig is Inbound configuration\ntype TrojanServerConfig struct {\n\tClients   []*TrojanUserConfig      `json:\"clients\"`\n\tFallback  json.RawMessage          `json:\"fallback\"`\n\tFallbacks []*TrojanInboundFallback `json:\"fallbacks\"`\n}\n\n// Build implements Buildable\nfunc (c *TrojanServerConfig) Build() (proto.Message, error) {\n\tconfig := new(trojan.ServerConfig)\n\n\tif len(c.Clients) == 0 {\n\t\treturn nil, newError(\"No trojan user settings.\")\n\t}\n\n\tconfig.Users = make([]*protocol.User, len(c.Clients))\n\tfor idx, rawUser := range c.Clients {\n\t\tuser := new(protocol.User)\n\t\taccount := &trojan.Account{\n\t\t\tPassword: rawUser.Password,\n\t\t}\n\n\t\tuser.Email = rawUser.Email\n\t\tuser.Level = uint32(rawUser.Level)\n\t\tuser.Account = serial.ToTypedMessage(account)\n\t\tconfig.Users[idx] = user\n\t}\n\n\tif c.Fallback != nil {\n\t\treturn nil, newError(`Trojan settings: please use \"fallbacks\":[{}] instead of \"fallback\":{}`)\n\t}\n\tfor _, fb := range c.Fallbacks {\n\t\tvar i uint16\n\t\tvar s string\n\t\tif err := json.Unmarshal(fb.Dest, &i); err == nil {\n\t\t\ts = strconv.Itoa(int(i))\n\t\t} else {\n\t\t\t_ = json.Unmarshal(fb.Dest, &s)\n\t\t}\n\t\tconfig.Fallbacks = append(config.Fallbacks, &trojan.Fallback{\n\t\t\tAlpn: fb.Alpn,\n\t\t\tPath: fb.Path,\n\t\t\tType: fb.Type,\n\t\t\tDest: s,\n\t\t\tXver: fb.Xver,\n\t\t})\n\t}\n\tfor _, fb := range config.Fallbacks {\n\t\t/*\n\t\t\tif fb.Alpn == \"h2\" && fb.Path != \"\" {\n\t\t\t\treturn nil, newError(`Trojan fallbacks: \"alpn\":\"h2\" doesn't support \"path\"`)\n\t\t\t}\n\t\t*/\n\t\tif fb.Path != \"\" && fb.Path[0] != '/' {\n\t\t\treturn nil, newError(`Trojan fallbacks: \"path\" must be empty or start with \"/\"`)\n\t\t}\n\t\tif fb.Type == \"\" && fb.Dest != \"\" {\n\t\t\tif fb.Dest == \"serve-ws-none\" {\n\t\t\t\tfb.Type = \"serve\"\n\t\t\t} else {\n\t\t\t\tswitch fb.Dest[0] {\n\t\t\t\tcase '@', '/':\n\t\t\t\t\tfb.Type = \"unix\"\n\t\t\t\t\tif fb.Dest[0] == '@' && len(fb.Dest) > 1 && fb.Dest[1] == '@' && runtime.GOOS == \"linux\" {\n\t\t\t\t\t\tfullAddr := make([]byte, len(syscall.RawSockaddrUnix{}.Path)) // may need padding to work in front of haproxy\n\t\t\t\t\t\tcopy(fullAddr, fb.Dest[1:])\n\t\t\t\t\t\tfb.Dest = string(fullAddr)\n\t\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\tif _, err := strconv.Atoi(fb.Dest); err == nil {\n\t\t\t\t\t\tfb.Dest = \"127.0.0.1:\" + fb.Dest\n\t\t\t\t\t}\n\t\t\t\t\tif _, _, err := net.SplitHostPort(fb.Dest); err == nil {\n\t\t\t\t\t\tfb.Type = \"tcp\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif fb.Type == \"\" {\n\t\t\treturn nil, newError(`Trojan fallbacks: please fill in a valid value for every \"dest\"`)\n\t\t}\n\t\tif fb.Xver > 2 {\n\t\t\treturn nil, newError(`Trojan fallbacks: invalid PROXY protocol version, \"xver\" only accepts 0, 1, 2`)\n\t\t}\n\t}\n\n\treturn config, nil\n}\n"
  },
  {
    "path": "infra/conf/v2ray.go",
    "content": "package conf\n\nimport (\n\t\"encoding/json\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/app/dispatcher\"\n\t\"v2ray.com/core/app/proxyman\"\n\t\"v2ray.com/core/app/stats\"\n\t\"v2ray.com/core/common/serial\"\n\t\"v2ray.com/core/transport/internet/xtls\"\n)\n\nvar (\n\tinboundConfigLoader = NewJSONConfigLoader(ConfigCreatorCache{\n\t\t\"dokodemo-door\": func() interface{} { return new(DokodemoConfig) },\n\t\t\"http\":          func() interface{} { return new(HttpServerConfig) },\n\t\t\"shadowsocks\":   func() interface{} { return new(ShadowsocksServerConfig) },\n\t\t\"socks\":         func() interface{} { return new(SocksServerConfig) },\n\t\t\"vless\":         func() interface{} { return new(VLessInboundConfig) },\n\t\t\"vmess\":         func() interface{} { return new(VMessInboundConfig) },\n\t\t\"trojan\":        func() interface{} { return new(TrojanServerConfig) },\n\t\t\"mtproto\":       func() interface{} { return new(MTProtoServerConfig) },\n\t}, \"protocol\", \"settings\")\n\n\toutboundConfigLoader = NewJSONConfigLoader(ConfigCreatorCache{\n\t\t\"blackhole\":   func() interface{} { return new(BlackholeConfig) },\n\t\t\"freedom\":     func() interface{} { return new(FreedomConfig) },\n\t\t\"http\":        func() interface{} { return new(HttpClientConfig) },\n\t\t\"shadowsocks\": func() interface{} { return new(ShadowsocksClientConfig) },\n\t\t\"socks\":       func() interface{} { return new(SocksClientConfig) },\n\t\t\"vless\":       func() interface{} { return new(VLessOutboundConfig) },\n\t\t\"vmess\":       func() interface{} { return new(VMessOutboundConfig) },\n\t\t\"trojan\":      func() interface{} { return new(TrojanClientConfig) },\n\t\t\"mtproto\":     func() interface{} { return new(MTProtoClientConfig) },\n\t\t\"dns\":         func() interface{} { return new(DnsOutboundConfig) },\n\t}, \"protocol\", \"settings\")\n\n\tctllog = log.New(os.Stderr, \"v2ctl> \", 0)\n)\n\nfunc toProtocolList(s []string) ([]proxyman.KnownProtocols, error) {\n\tkp := make([]proxyman.KnownProtocols, 0, 8)\n\tfor _, p := range s {\n\t\tswitch strings.ToLower(p) {\n\t\tcase \"http\":\n\t\t\tkp = append(kp, proxyman.KnownProtocols_HTTP)\n\t\tcase \"https\", \"tls\", \"ssl\":\n\t\t\tkp = append(kp, proxyman.KnownProtocols_TLS)\n\t\tdefault:\n\t\t\treturn nil, newError(\"Unknown protocol: \", p)\n\t\t}\n\t}\n\treturn kp, nil\n}\n\ntype SniffingConfig struct {\n\tEnabled      bool        `json:\"enabled\"`\n\tDestOverride *StringList `json:\"destOverride\"`\n}\n\n// Build implements Buildable.\nfunc (c *SniffingConfig) Build() (*proxyman.SniffingConfig, error) {\n\tvar p []string\n\tif c.DestOverride != nil {\n\t\tfor _, domainOverride := range *c.DestOverride {\n\t\t\tswitch strings.ToLower(domainOverride) {\n\t\t\tcase \"http\":\n\t\t\t\tp = append(p, \"http\")\n\t\t\tcase \"tls\", \"https\", \"ssl\":\n\t\t\t\tp = append(p, \"tls\")\n\t\t\tdefault:\n\t\t\t\treturn nil, newError(\"unknown protocol: \", domainOverride)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn &proxyman.SniffingConfig{\n\t\tEnabled:             c.Enabled,\n\t\tDestinationOverride: p,\n\t}, nil\n}\n\ntype MuxConfig struct {\n\tEnabled     bool  `json:\"enabled\"`\n\tConcurrency int16 `json:\"concurrency\"`\n}\n\n// Build creates MultiplexingConfig, Concurrency < 0 completely disables mux.\nfunc (m *MuxConfig) Build() *proxyman.MultiplexingConfig {\n\tif m.Concurrency < 0 {\n\t\treturn nil\n\t}\n\n\tvar con uint32 = 8\n\tif m.Concurrency > 0 {\n\t\tcon = uint32(m.Concurrency)\n\t}\n\n\treturn &proxyman.MultiplexingConfig{\n\t\tEnabled:     m.Enabled,\n\t\tConcurrency: con,\n\t}\n}\n\ntype InboundDetourAllocationConfig struct {\n\tStrategy    string  `json:\"strategy\"`\n\tConcurrency *uint32 `json:\"concurrency\"`\n\tRefreshMin  *uint32 `json:\"refresh\"`\n}\n\n// Build implements Buildable.\nfunc (c *InboundDetourAllocationConfig) Build() (*proxyman.AllocationStrategy, error) {\n\tconfig := new(proxyman.AllocationStrategy)\n\tswitch strings.ToLower(c.Strategy) {\n\tcase \"always\":\n\t\tconfig.Type = proxyman.AllocationStrategy_Always\n\tcase \"random\":\n\t\tconfig.Type = proxyman.AllocationStrategy_Random\n\tcase \"external\":\n\t\tconfig.Type = proxyman.AllocationStrategy_External\n\tdefault:\n\t\treturn nil, newError(\"unknown allocation strategy: \", c.Strategy)\n\t}\n\tif c.Concurrency != nil {\n\t\tconfig.Concurrency = &proxyman.AllocationStrategy_AllocationStrategyConcurrency{\n\t\t\tValue: *c.Concurrency,\n\t\t}\n\t}\n\n\tif c.RefreshMin != nil {\n\t\tconfig.Refresh = &proxyman.AllocationStrategy_AllocationStrategyRefresh{\n\t\t\tValue: *c.RefreshMin,\n\t\t}\n\t}\n\n\treturn config, nil\n}\n\ntype InboundDetourConfig struct {\n\tProtocol       string                         `json:\"protocol\"`\n\tPortRange      *PortRange                     `json:\"port\"`\n\tListenOn       *Address                       `json:\"listen\"`\n\tSettings       *json.RawMessage               `json:\"settings\"`\n\tTag            string                         `json:\"tag\"`\n\tAllocation     *InboundDetourAllocationConfig `json:\"allocate\"`\n\tStreamSetting  *StreamConfig                  `json:\"streamSettings\"`\n\tDomainOverride *StringList                    `json:\"domainOverride\"`\n\tSniffingConfig *SniffingConfig                `json:\"sniffing\"`\n}\n\n// Build implements Buildable.\nfunc (c *InboundDetourConfig) Build() (*core.InboundHandlerConfig, error) {\n\treceiverSettings := &proxyman.ReceiverConfig{}\n\n\tif c.PortRange == nil {\n\t\treturn nil, newError(\"port range not specified in InboundDetour.\")\n\t}\n\treceiverSettings.PortRange = c.PortRange.Build()\n\n\tif c.ListenOn != nil {\n\t\tif c.ListenOn.Family().IsDomain() {\n\t\t\treturn nil, newError(\"unable to listen on domain address: \", c.ListenOn.Domain())\n\t\t}\n\t\treceiverSettings.Listen = c.ListenOn.Build()\n\t}\n\tif c.Allocation != nil {\n\t\tconcurrency := -1\n\t\tif c.Allocation.Concurrency != nil && c.Allocation.Strategy == \"random\" {\n\t\t\tconcurrency = int(*c.Allocation.Concurrency)\n\t\t}\n\t\tportRange := int(c.PortRange.To - c.PortRange.From + 1)\n\t\tif concurrency >= 0 && concurrency >= portRange {\n\t\t\treturn nil, newError(\"not enough ports. concurrency = \", concurrency, \" ports: \", c.PortRange.From, \" - \", c.PortRange.To)\n\t\t}\n\n\t\tas, err := c.Allocation.Build()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treceiverSettings.AllocationStrategy = as\n\t}\n\tif c.StreamSetting != nil {\n\t\tss, err := c.StreamSetting.Build()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif ss.SecurityType == serial.GetMessageType(&xtls.Config{}) && !strings.EqualFold(c.Protocol, \"vless\") {\n\t\t\treturn nil, newError(\"XTLS only supports VLESS for now.\")\n\t\t}\n\t\treceiverSettings.StreamSettings = ss\n\t}\n\tif c.SniffingConfig != nil {\n\t\ts, err := c.SniffingConfig.Build()\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"failed to build sniffing config\").Base(err)\n\t\t}\n\t\treceiverSettings.SniffingSettings = s\n\t}\n\tif c.DomainOverride != nil {\n\t\tkp, err := toProtocolList(*c.DomainOverride)\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"failed to parse inbound detour config\").Base(err)\n\t\t}\n\t\treceiverSettings.DomainOverride = kp\n\t}\n\n\tsettings := []byte(\"{}\")\n\tif c.Settings != nil {\n\t\tsettings = ([]byte)(*c.Settings)\n\t}\n\trawConfig, err := inboundConfigLoader.LoadWithID(settings, c.Protocol)\n\tif err != nil {\n\t\treturn nil, newError(\"failed to load inbound detour config.\").Base(err)\n\t}\n\tif dokodemoConfig, ok := rawConfig.(*DokodemoConfig); ok {\n\t\treceiverSettings.ReceiveOriginalDestination = dokodemoConfig.Redirect\n\t}\n\tts, err := rawConfig.(Buildable).Build()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &core.InboundHandlerConfig{\n\t\tTag:              c.Tag,\n\t\tReceiverSettings: serial.ToTypedMessage(receiverSettings),\n\t\tProxySettings:    serial.ToTypedMessage(ts),\n\t}, nil\n}\n\ntype OutboundDetourConfig struct {\n\tProtocol      string           `json:\"protocol\"`\n\tSendThrough   *Address         `json:\"sendThrough\"`\n\tTag           string           `json:\"tag\"`\n\tSettings      *json.RawMessage `json:\"settings\"`\n\tStreamSetting *StreamConfig    `json:\"streamSettings\"`\n\tProxySettings *ProxyConfig     `json:\"proxySettings\"`\n\tMuxSettings   *MuxConfig       `json:\"mux\"`\n}\n\n// Build implements Buildable.\nfunc (c *OutboundDetourConfig) Build() (*core.OutboundHandlerConfig, error) {\n\tsenderSettings := &proxyman.SenderConfig{}\n\n\tif c.SendThrough != nil {\n\t\taddress := c.SendThrough\n\t\tif address.Family().IsDomain() {\n\t\t\treturn nil, newError(\"unable to send through: \" + address.String())\n\t\t}\n\t\tsenderSettings.Via = address.Build()\n\t}\n\n\tif c.StreamSetting != nil {\n\t\tss, err := c.StreamSetting.Build()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif ss.SecurityType == serial.GetMessageType(&xtls.Config{}) && !strings.EqualFold(c.Protocol, \"vless\") {\n\t\t\treturn nil, newError(\"XTLS only supports VLESS for now.\")\n\t\t}\n\t\tsenderSettings.StreamSettings = ss\n\t}\n\n\tif c.ProxySettings != nil {\n\t\tps, err := c.ProxySettings.Build()\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"invalid outbound detour proxy settings.\").Base(err)\n\t\t}\n\t\tsenderSettings.ProxySettings = ps\n\t}\n\n\tif c.MuxSettings != nil {\n\t\tms := c.MuxSettings.Build()\n\t\tif ms != nil && ms.Enabled {\n\t\t\tif ss := senderSettings.StreamSettings; ss != nil {\n\t\t\t\tif ss.SecurityType == serial.GetMessageType(&xtls.Config{}) {\n\t\t\t\t\treturn nil, newError(\"XTLS doesn't support Mux for now.\")\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tsenderSettings.MultiplexSettings = ms\n\t}\n\n\tsettings := []byte(\"{}\")\n\tif c.Settings != nil {\n\t\tsettings = ([]byte)(*c.Settings)\n\t}\n\trawConfig, err := outboundConfigLoader.LoadWithID(settings, c.Protocol)\n\tif err != nil {\n\t\treturn nil, newError(\"failed to parse to outbound detour config.\").Base(err)\n\t}\n\tts, err := rawConfig.(Buildable).Build()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &core.OutboundHandlerConfig{\n\t\tSenderSettings: serial.ToTypedMessage(senderSettings),\n\t\tTag:            c.Tag,\n\t\tProxySettings:  serial.ToTypedMessage(ts),\n\t}, nil\n}\n\ntype StatsConfig struct{}\n\n// Build implements Buildable.\nfunc (c *StatsConfig) Build() (*stats.Config, error) {\n\treturn &stats.Config{}, nil\n}\n\ntype Config struct {\n\tPort            uint16                 `json:\"port\"` // Port of this Point server. Deprecated.\n\tLogConfig       *LogConfig             `json:\"log\"`\n\tRouterConfig    *RouterConfig          `json:\"routing\"`\n\tDNSConfig       *DnsConfig             `json:\"dns\"`\n\tInboundConfigs  []InboundDetourConfig  `json:\"inbounds\"`\n\tOutboundConfigs []OutboundDetourConfig `json:\"outbounds\"`\n\tInboundConfig   *InboundDetourConfig   `json:\"inbound\"`        // Deprecated.\n\tOutboundConfig  *OutboundDetourConfig  `json:\"outbound\"`       // Deprecated.\n\tInboundDetours  []InboundDetourConfig  `json:\"inboundDetour\"`  // Deprecated.\n\tOutboundDetours []OutboundDetourConfig `json:\"outboundDetour\"` // Deprecated.\n\tTransport       *TransportConfig       `json:\"transport\"`\n\tPolicy          *PolicyConfig          `json:\"policy\"`\n\tApi             *ApiConfig             `json:\"api\"`\n\tStats           *StatsConfig           `json:\"stats\"`\n\tReverse         *ReverseConfig         `json:\"reverse\"`\n}\n\nfunc (c *Config) findInboundTag(tag string) int {\n\tfound := -1\n\tfor idx, ib := range c.InboundConfigs {\n\t\tif ib.Tag == tag {\n\t\t\tfound = idx\n\t\t\tbreak\n\t\t}\n\t}\n\treturn found\n}\n\nfunc (c *Config) findOutboundTag(tag string) int {\n\tfound := -1\n\tfor idx, ob := range c.OutboundConfigs {\n\t\tif ob.Tag == tag {\n\t\t\tfound = idx\n\t\t\tbreak\n\t\t}\n\t}\n\treturn found\n}\n\n// Override method accepts another Config overrides the current attribute\nfunc (c *Config) Override(o *Config, fn string) {\n\n\t// only process the non-deprecated members\n\n\tif o.LogConfig != nil {\n\t\tc.LogConfig = o.LogConfig\n\t}\n\tif o.RouterConfig != nil {\n\t\tc.RouterConfig = o.RouterConfig\n\t}\n\tif o.DNSConfig != nil {\n\t\tc.DNSConfig = o.DNSConfig\n\t}\n\tif o.Transport != nil {\n\t\tc.Transport = o.Transport\n\t}\n\tif o.Policy != nil {\n\t\tc.Policy = o.Policy\n\t}\n\tif o.Api != nil {\n\t\tc.Api = o.Api\n\t}\n\tif o.Stats != nil {\n\t\tc.Stats = o.Stats\n\t}\n\tif o.Reverse != nil {\n\t\tc.Reverse = o.Reverse\n\t}\n\n\t// deprecated attrs... keep them for now\n\tif o.InboundConfig != nil {\n\t\tc.InboundConfig = o.InboundConfig\n\t}\n\tif o.OutboundConfig != nil {\n\t\tc.OutboundConfig = o.OutboundConfig\n\t}\n\tif o.InboundDetours != nil {\n\t\tc.InboundDetours = o.InboundDetours\n\t}\n\tif o.OutboundDetours != nil {\n\t\tc.OutboundDetours = o.OutboundDetours\n\t}\n\t// deprecated attrs\n\n\t// update the Inbound in slice if the only one in overide config has same tag\n\tif len(o.InboundConfigs) > 0 {\n\t\tif len(c.InboundConfigs) > 0 && len(o.InboundConfigs) == 1 {\n\t\t\tif idx := c.findInboundTag(o.InboundConfigs[0].Tag); idx > -1 {\n\t\t\t\tc.InboundConfigs[idx] = o.InboundConfigs[0]\n\t\t\t\tctllog.Println(\"[\", fn, \"] updated inbound with tag: \", o.InboundConfigs[0].Tag)\n\t\t\t} else {\n\t\t\t\tc.InboundConfigs = append(c.InboundConfigs, o.InboundConfigs[0])\n\t\t\t\tctllog.Println(\"[\", fn, \"] appended inbound with tag: \", o.InboundConfigs[0].Tag)\n\t\t\t}\n\t\t} else {\n\t\t\tc.InboundConfigs = o.InboundConfigs\n\t\t}\n\t}\n\n\t// update the Outbound in slice if the only one in overide config has same tag\n\tif len(o.OutboundConfigs) > 0 {\n\t\tif len(c.OutboundConfigs) > 0 && len(o.OutboundConfigs) == 1 {\n\t\t\tif idx := c.findOutboundTag(o.OutboundConfigs[0].Tag); idx > -1 {\n\t\t\t\tc.OutboundConfigs[idx] = o.OutboundConfigs[0]\n\t\t\t\tctllog.Println(\"[\", fn, \"] updated outbound with tag: \", o.OutboundConfigs[0].Tag)\n\t\t\t} else {\n\t\t\t\tif strings.Contains(strings.ToLower(fn), \"tail\") {\n\t\t\t\t\tc.OutboundConfigs = append(c.OutboundConfigs, o.OutboundConfigs[0])\n\t\t\t\t\tctllog.Println(\"[\", fn, \"] appended outbound with tag: \", o.OutboundConfigs[0].Tag)\n\t\t\t\t} else {\n\t\t\t\t\tc.OutboundConfigs = append(o.OutboundConfigs, c.OutboundConfigs...)\n\t\t\t\t\tctllog.Println(\"[\", fn, \"] prepended outbound with tag: \", o.OutboundConfigs[0].Tag)\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tc.OutboundConfigs = o.OutboundConfigs\n\t\t}\n\t}\n}\n\nfunc applyTransportConfig(s *StreamConfig, t *TransportConfig) {\n\tif s.TCPSettings == nil {\n\t\ts.TCPSettings = t.TCPConfig\n\t}\n\tif s.KCPSettings == nil {\n\t\ts.KCPSettings = t.KCPConfig\n\t}\n\tif s.WSSettings == nil {\n\t\ts.WSSettings = t.WSConfig\n\t}\n\tif s.HTTPSettings == nil {\n\t\ts.HTTPSettings = t.HTTPConfig\n\t}\n\tif s.DSSettings == nil {\n\t\ts.DSSettings = t.DSConfig\n\t}\n}\n\n// Build implements Buildable.\nfunc (c *Config) Build() (*core.Config, error) {\n\tconfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&dispatcher.Config{}),\n\t\t\tserial.ToTypedMessage(&proxyman.InboundConfig{}),\n\t\t\tserial.ToTypedMessage(&proxyman.OutboundConfig{}),\n\t\t},\n\t}\n\n\tif c.Api != nil {\n\t\tapiConf, err := c.Api.Build()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tconfig.App = append(config.App, serial.ToTypedMessage(apiConf))\n\t}\n\n\tif c.Stats != nil {\n\t\tstatsConf, err := c.Stats.Build()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tconfig.App = append(config.App, serial.ToTypedMessage(statsConf))\n\t}\n\n\tvar logConfMsg *serial.TypedMessage\n\tif c.LogConfig != nil {\n\t\tlogConfMsg = serial.ToTypedMessage(c.LogConfig.Build())\n\t} else {\n\t\tlogConfMsg = serial.ToTypedMessage(DefaultLogConfig())\n\t}\n\t// let logger module be the first App to start,\n\t// so that other modules could print log during initiating\n\tconfig.App = append([]*serial.TypedMessage{logConfMsg}, config.App...)\n\n\tif c.RouterConfig != nil {\n\t\trouterConfig, err := c.RouterConfig.Build()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tconfig.App = append(config.App, serial.ToTypedMessage(routerConfig))\n\t}\n\n\tif c.DNSConfig != nil {\n\t\tdnsApp, err := c.DNSConfig.Build()\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"failed to parse DNS config\").Base(err)\n\t\t}\n\t\tconfig.App = append(config.App, serial.ToTypedMessage(dnsApp))\n\t}\n\n\tif c.Policy != nil {\n\t\tpc, err := c.Policy.Build()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tconfig.App = append(config.App, serial.ToTypedMessage(pc))\n\t}\n\n\tif c.Reverse != nil {\n\t\tr, err := c.Reverse.Build()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tconfig.App = append(config.App, serial.ToTypedMessage(r))\n\t}\n\n\tvar inbounds []InboundDetourConfig\n\n\tif c.InboundConfig != nil {\n\t\tinbounds = append(inbounds, *c.InboundConfig)\n\t}\n\n\tif len(c.InboundDetours) > 0 {\n\t\tinbounds = append(inbounds, c.InboundDetours...)\n\t}\n\n\tif len(c.InboundConfigs) > 0 {\n\t\tinbounds = append(inbounds, c.InboundConfigs...)\n\t}\n\n\t// Backward compatibility.\n\tif len(inbounds) > 0 && inbounds[0].PortRange == nil && c.Port > 0 {\n\t\tinbounds[0].PortRange = &PortRange{\n\t\t\tFrom: uint32(c.Port),\n\t\t\tTo:   uint32(c.Port),\n\t\t}\n\t}\n\n\tfor _, rawInboundConfig := range inbounds {\n\t\tif c.Transport != nil {\n\t\t\tif rawInboundConfig.StreamSetting == nil {\n\t\t\t\trawInboundConfig.StreamSetting = &StreamConfig{}\n\t\t\t}\n\t\t\tapplyTransportConfig(rawInboundConfig.StreamSetting, c.Transport)\n\t\t}\n\t\tic, err := rawInboundConfig.Build()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tconfig.Inbound = append(config.Inbound, ic)\n\t}\n\n\tvar outbounds []OutboundDetourConfig\n\n\tif c.OutboundConfig != nil {\n\t\toutbounds = append(outbounds, *c.OutboundConfig)\n\t}\n\n\tif len(c.OutboundDetours) > 0 {\n\t\toutbounds = append(outbounds, c.OutboundDetours...)\n\t}\n\n\tif len(c.OutboundConfigs) > 0 {\n\t\toutbounds = append(outbounds, c.OutboundConfigs...)\n\t}\n\n\tfor _, rawOutboundConfig := range outbounds {\n\t\tif c.Transport != nil {\n\t\t\tif rawOutboundConfig.StreamSetting == nil {\n\t\t\t\trawOutboundConfig.StreamSetting = &StreamConfig{}\n\t\t\t}\n\t\t\tapplyTransportConfig(rawOutboundConfig.StreamSetting, c.Transport)\n\t\t}\n\t\toc, err := rawOutboundConfig.Build()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tconfig.Outbound = append(config.Outbound, oc)\n\t}\n\n\treturn config, nil\n}\n"
  },
  {
    "path": "infra/conf/v2ray_test.go",
    "content": "package conf_test\n\nimport (\n\t\"encoding/json\"\n\t\"reflect\"\n\t\"testing\"\n\n\t\"github.com/golang/protobuf/proto\"\n\t\"github.com/google/go-cmp/cmp\"\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/app/dispatcher\"\n\t\"v2ray.com/core/app/log\"\n\t\"v2ray.com/core/app/proxyman\"\n\t\"v2ray.com/core/app/router\"\n\t\"v2ray.com/core/common\"\n\tclog \"v2ray.com/core/common/log\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/serial\"\n\t. \"v2ray.com/core/infra/conf\"\n\t\"v2ray.com/core/proxy/blackhole\"\n\tdns_proxy \"v2ray.com/core/proxy/dns\"\n\t\"v2ray.com/core/proxy/freedom\"\n\t\"v2ray.com/core/proxy/vmess\"\n\t\"v2ray.com/core/proxy/vmess/inbound\"\n\t\"v2ray.com/core/transport/internet\"\n\t\"v2ray.com/core/transport/internet/http\"\n\t\"v2ray.com/core/transport/internet/tls\"\n\t\"v2ray.com/core/transport/internet/websocket\"\n)\n\nfunc TestV2RayConfig(t *testing.T) {\n\tcreateParser := func() func(string) (proto.Message, error) {\n\t\treturn func(s string) (proto.Message, error) {\n\t\t\tconfig := new(Config)\n\t\t\tif err := json.Unmarshal([]byte(s), config); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn config.Build()\n\t\t}\n\t}\n\n\trunMultiTestCase(t, []TestCase{\n\t\t{\n\t\t\tInput: `{\n\t\t\t\t\"outbound\": {\n\t\t\t\t\t\"protocol\": \"freedom\",\n\t\t\t\t\t\"settings\": {}\n\t\t\t\t},\n\t\t\t\t\"log\": {\n\t\t\t\t\t\"access\": \"/var/log/v2ray/access.log\",\n\t\t\t\t\t\"loglevel\": \"error\",\n\t\t\t\t\t\"error\": \"/var/log/v2ray/error.log\"\n\t\t\t\t},\n\t\t\t\t\"inbound\": {\n\t\t\t\t\t\"streamSettings\": {\n\t\t\t\t\t\t\"network\": \"ws\",\n\t\t\t\t\t\t\"wsSettings\": {\n\t\t\t\t\t\t\t\"headers\": {\n\t\t\t\t\t\t\t\t\"host\": \"example.domain\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"path\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"tlsSettings\": {\n\t\t\t\t\t\t\t\"alpn\": \"h2\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"security\": \"tls\"\n\t\t\t\t\t},\n\t\t\t\t\t\"protocol\": \"vmess\",\n\t\t\t\t\t\"port\": 443,\n\t\t\t\t\t\"settings\": {\n\t\t\t\t\t\t\"clients\": [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\"alterId\": 100,\n\t\t\t\t\t\t\t\t\"security\": \"aes-128-gcm\",\n\t\t\t\t\t\t\t\t\"id\": \"0cdf8a45-303d-4fed-9780-29aa7f54175e\"\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\t\"inbounds\": [{\n\t\t\t\t\t\"streamSettings\": {\n\t\t\t\t\t\t\"network\": \"ws\",\n\t\t\t\t\t\t\"wsSettings\": {\n\t\t\t\t\t\t\t\"headers\": {\n\t\t\t\t\t\t\t\t\"host\": \"example.domain\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"path\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"tlsSettings\": {\n\t\t\t\t\t\t\t\"alpn\": \"h2\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"security\": \"tls\"\n\t\t\t\t\t},\n\t\t\t\t\t\"protocol\": \"vmess\",\n\t\t\t\t\t\"port\": \"443-500\",\n\t\t\t\t\t\"allocate\": {\n\t\t\t\t\t\t\"strategy\": \"random\",\n\t\t\t\t\t\t\"concurrency\": 3\n\t\t\t\t\t},\n\t\t\t\t\t\"settings\": {\n\t\t\t\t\t\t\"clients\": [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\"alterId\": 100,\n\t\t\t\t\t\t\t\t\"security\": \"aes-128-gcm\",\n\t\t\t\t\t\t\t\t\"id\": \"0cdf8a45-303d-4fed-9780-29aa7f54175e\"\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\t\"outboundDetour\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"tag\": \"blocked\",\n\t\t\t\t\t\t\"protocol\": \"blackhole\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"protocol\": \"dns\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"routing\": {\n\t\t\t\t\t\"strategy\": \"rules\",\n\t\t\t\t\t\"settings\": {\n\t\t\t\t\t\t\"rules\": [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\"ip\": [\n\t\t\t\t\t\t\t\t\t\"10.0.0.0/8\"\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\"type\": \"field\",\n\t\t\t\t\t\t\t\t\"outboundTag\": \"blocked\"\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\t\"transport\": {\n\t\t\t\t\t\"httpSettings\": {\n\t\t\t\t\t\t\"path\": \"/test\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}`,\n\t\t\tParser: createParser(),\n\t\t\tOutput: &core.Config{\n\t\t\t\tApp: []*serial.TypedMessage{\n\t\t\t\t\tserial.ToTypedMessage(&log.Config{\n\t\t\t\t\t\tErrorLogType:  log.LogType_File,\n\t\t\t\t\t\tErrorLogPath:  \"/var/log/v2ray/error.log\",\n\t\t\t\t\t\tErrorLogLevel: clog.Severity_Error,\n\t\t\t\t\t\tAccessLogType: log.LogType_File,\n\t\t\t\t\t\tAccessLogPath: \"/var/log/v2ray/access.log\",\n\t\t\t\t\t}),\n\t\t\t\t\tserial.ToTypedMessage(&dispatcher.Config{}),\n\t\t\t\t\tserial.ToTypedMessage(&proxyman.InboundConfig{}),\n\t\t\t\t\tserial.ToTypedMessage(&proxyman.OutboundConfig{}),\n\t\t\t\t\tserial.ToTypedMessage(&router.Config{\n\t\t\t\t\t\tDomainStrategy: router.Config_AsIs,\n\t\t\t\t\t\tRule: []*router.RoutingRule{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tGeoip: []*router.GeoIP{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tCidr: []*router.CIDR{\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tIp:     []byte{10, 0, 0, 0},\n\t\t\t\t\t\t\t\t\t\t\t\tPrefix: 8,\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tTargetTag: &router.RoutingRule_Tag{\n\t\t\t\t\t\t\t\t\tTag: \"blocked\",\n\t\t\t\t\t\t\t\t},\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\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t\t\t{\n\t\t\t\t\t\tSenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{\n\t\t\t\t\t\t\tStreamSettings: &internet.StreamConfig{\n\t\t\t\t\t\t\t\tProtocolName: \"tcp\",\n\t\t\t\t\t\t\t\tTransportSettings: []*internet.TransportConfig{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tProtocolName: \"http\",\n\t\t\t\t\t\t\t\t\t\tSettings: serial.ToTypedMessage(&http.Config{\n\t\t\t\t\t\t\t\t\t\t\tPath: \"/test\",\n\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}),\n\t\t\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{\n\t\t\t\t\t\t\tDomainStrategy: freedom.Config_AS_IS,\n\t\t\t\t\t\t\tUserLevel:      0,\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\tTag: \"blocked\",\n\t\t\t\t\t\tSenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{\n\t\t\t\t\t\t\tStreamSettings: &internet.StreamConfig{\n\t\t\t\t\t\t\t\tProtocolName: \"tcp\",\n\t\t\t\t\t\t\t\tTransportSettings: []*internet.TransportConfig{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tProtocolName: \"http\",\n\t\t\t\t\t\t\t\t\t\tSettings: serial.ToTypedMessage(&http.Config{\n\t\t\t\t\t\t\t\t\t\t\tPath: \"/test\",\n\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}),\n\t\t\t\t\t\tProxySettings: serial.ToTypedMessage(&blackhole.Config{}),\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tSenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{\n\t\t\t\t\t\t\tStreamSettings: &internet.StreamConfig{\n\t\t\t\t\t\t\t\tProtocolName: \"tcp\",\n\t\t\t\t\t\t\t\tTransportSettings: []*internet.TransportConfig{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tProtocolName: \"http\",\n\t\t\t\t\t\t\t\t\t\tSettings: serial.ToTypedMessage(&http.Config{\n\t\t\t\t\t\t\t\t\t\t\tPath: \"/test\",\n\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}),\n\t\t\t\t\t\tProxySettings: serial.ToTypedMessage(&dns_proxy.Config{\n\t\t\t\t\t\t\tServer: &net.Endpoint{},\n\t\t\t\t\t\t}),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t\t\t{\n\t\t\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\t\t\tPortRange: &net.PortRange{\n\t\t\t\t\t\t\t\tFrom: 443,\n\t\t\t\t\t\t\t\tTo:   443,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tStreamSettings: &internet.StreamConfig{\n\t\t\t\t\t\t\t\tProtocolName: \"websocket\",\n\t\t\t\t\t\t\t\tTransportSettings: []*internet.TransportConfig{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tProtocolName: \"websocket\",\n\t\t\t\t\t\t\t\t\t\tSettings: serial.ToTypedMessage(&websocket.Config{\n\t\t\t\t\t\t\t\t\t\t\tHeader: []*websocket.Header{\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\tKey:   \"host\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tValue: \"example.domain\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tProtocolName: \"http\",\n\t\t\t\t\t\t\t\t\t\tSettings: serial.ToTypedMessage(&http.Config{\n\t\t\t\t\t\t\t\t\t\t\tPath: \"/test\",\n\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tSecurityType: \"v2ray.core.transport.internet.tls.Config\",\n\t\t\t\t\t\t\t\tSecuritySettings: []*serial.TypedMessage{\n\t\t\t\t\t\t\t\t\tserial.ToTypedMessage(&tls.Config{\n\t\t\t\t\t\t\t\t\t\tNextProtocol: []string{\"h2\"},\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}),\n\t\t\t\t\t\tProxySettings: serial.ToTypedMessage(&inbound.Config{\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tLevel: 0,\n\t\t\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\t\t\tId:      \"0cdf8a45-303d-4fed-9780-29aa7f54175e\",\n\t\t\t\t\t\t\t\t\t\tAlterId: 100,\n\t\t\t\t\t\t\t\t\t\tSecuritySettings: &protocol.SecurityConfig{\n\t\t\t\t\t\t\t\t\t\t\tType: protocol.SecurityType_AES128_GCM,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t},\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\t{\n\t\t\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\t\t\tPortRange: &net.PortRange{\n\t\t\t\t\t\t\t\tFrom: 443,\n\t\t\t\t\t\t\t\tTo:   500,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tAllocationStrategy: &proxyman.AllocationStrategy{\n\t\t\t\t\t\t\t\tType: proxyman.AllocationStrategy_Random,\n\t\t\t\t\t\t\t\tConcurrency: &proxyman.AllocationStrategy_AllocationStrategyConcurrency{\n\t\t\t\t\t\t\t\t\tValue: 3,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tStreamSettings: &internet.StreamConfig{\n\t\t\t\t\t\t\t\tProtocolName: \"websocket\",\n\t\t\t\t\t\t\t\tTransportSettings: []*internet.TransportConfig{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tProtocolName: \"websocket\",\n\t\t\t\t\t\t\t\t\t\tSettings: serial.ToTypedMessage(&websocket.Config{\n\t\t\t\t\t\t\t\t\t\t\tHeader: []*websocket.Header{\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\tKey:   \"host\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tValue: \"example.domain\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tProtocolName: \"http\",\n\t\t\t\t\t\t\t\t\t\tSettings: serial.ToTypedMessage(&http.Config{\n\t\t\t\t\t\t\t\t\t\t\tPath: \"/test\",\n\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tSecurityType: \"v2ray.core.transport.internet.tls.Config\",\n\t\t\t\t\t\t\t\tSecuritySettings: []*serial.TypedMessage{\n\t\t\t\t\t\t\t\t\tserial.ToTypedMessage(&tls.Config{\n\t\t\t\t\t\t\t\t\t\tNextProtocol: []string{\"h2\"},\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}),\n\t\t\t\t\t\tProxySettings: serial.ToTypedMessage(&inbound.Config{\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tLevel: 0,\n\t\t\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\t\t\tId:      \"0cdf8a45-303d-4fed-9780-29aa7f54175e\",\n\t\t\t\t\t\t\t\t\t\tAlterId: 100,\n\t\t\t\t\t\t\t\t\t\tSecuritySettings: &protocol.SecurityConfig{\n\t\t\t\t\t\t\t\t\t\t\tType: protocol.SecurityType_AES128_GCM,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t},\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},\n\t})\n}\n\nfunc TestMuxConfig_Build(t *testing.T) {\n\ttests := []struct {\n\t\tname   string\n\t\tfields string\n\t\twant   *proxyman.MultiplexingConfig\n\t}{\n\t\t{\"default\", `{\"enabled\": true, \"concurrency\": 16}`, &proxyman.MultiplexingConfig{\n\t\t\tEnabled:     true,\n\t\t\tConcurrency: 16,\n\t\t}},\n\t\t{\"empty def\", `{}`, &proxyman.MultiplexingConfig{\n\t\t\tEnabled:     false,\n\t\t\tConcurrency: 8,\n\t\t}},\n\t\t{\"not enable\", `{\"enabled\": false, \"concurrency\": 4}`, &proxyman.MultiplexingConfig{\n\t\t\tEnabled:     false,\n\t\t\tConcurrency: 4,\n\t\t}},\n\t\t{\"forbidden\", `{\"enabled\": false, \"concurrency\": -1}`, nil},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tm := &MuxConfig{}\n\t\t\tcommon.Must(json.Unmarshal([]byte(tt.fields), m))\n\t\t\tif got := m.Build(); !reflect.DeepEqual(got, tt.want) {\n\t\t\t\tt.Errorf(\"MuxConfig.Build() = %v, want %v\", got, tt.want)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestConfig_Override(t *testing.T) {\n\ttests := []struct {\n\t\tname string\n\t\torig *Config\n\t\tover *Config\n\t\tfn   string\n\t\twant *Config\n\t}{\n\t\t{\"combine/empty\",\n\t\t\t&Config{},\n\t\t\t&Config{\n\t\t\t\tLogConfig:    &LogConfig{},\n\t\t\t\tRouterConfig: &RouterConfig{},\n\t\t\t\tDNSConfig:    &DnsConfig{},\n\t\t\t\tTransport:    &TransportConfig{},\n\t\t\t\tPolicy:       &PolicyConfig{},\n\t\t\t\tApi:          &ApiConfig{},\n\t\t\t\tStats:        &StatsConfig{},\n\t\t\t\tReverse:      &ReverseConfig{},\n\t\t\t},\n\t\t\t\"\",\n\t\t\t&Config{\n\t\t\t\tLogConfig:    &LogConfig{},\n\t\t\t\tRouterConfig: &RouterConfig{},\n\t\t\t\tDNSConfig:    &DnsConfig{},\n\t\t\t\tTransport:    &TransportConfig{},\n\t\t\t\tPolicy:       &PolicyConfig{},\n\t\t\t\tApi:          &ApiConfig{},\n\t\t\t\tStats:        &StatsConfig{},\n\t\t\t\tReverse:      &ReverseConfig{},\n\t\t\t},\n\t\t},\n\t\t{\"combine/newattr\",\n\t\t\t&Config{InboundConfigs: []InboundDetourConfig{{Tag: \"old\"}}},\n\t\t\t&Config{LogConfig: &LogConfig{}}, \"\",\n\t\t\t&Config{LogConfig: &LogConfig{}, InboundConfigs: []InboundDetourConfig{{Tag: \"old\"}}}},\n\t\t{\"replace/inbounds\",\n\t\t\t&Config{InboundConfigs: []InboundDetourConfig{{Tag: \"pos0\"}, {Protocol: \"vmess\", Tag: \"pos1\"}}},\n\t\t\t&Config{InboundConfigs: []InboundDetourConfig{{Tag: \"pos1\", Protocol: \"kcp\"}}},\n\t\t\t\"\",\n\t\t\t&Config{InboundConfigs: []InboundDetourConfig{{Tag: \"pos0\"}, {Tag: \"pos1\", Protocol: \"kcp\"}}}},\n\t\t{\"replace/inbounds-replaceall\",\n\t\t\t&Config{InboundConfigs: []InboundDetourConfig{{Tag: \"pos0\"}, {Protocol: \"vmess\", Tag: \"pos1\"}}},\n\t\t\t&Config{InboundConfigs: []InboundDetourConfig{{Tag: \"pos1\", Protocol: \"kcp\"}, {Tag: \"pos2\", Protocol: \"kcp\"}}},\n\t\t\t\"\",\n\t\t\t&Config{InboundConfigs: []InboundDetourConfig{{Tag: \"pos1\", Protocol: \"kcp\"}, {Tag: \"pos2\", Protocol: \"kcp\"}}}},\n\t\t{\"replace/notag-append\",\n\t\t\t&Config{InboundConfigs: []InboundDetourConfig{{}, {Protocol: \"vmess\"}}},\n\t\t\t&Config{InboundConfigs: []InboundDetourConfig{{Tag: \"pos1\", Protocol: \"kcp\"}}},\n\t\t\t\"\",\n\t\t\t&Config{InboundConfigs: []InboundDetourConfig{{}, {Protocol: \"vmess\"}, {Tag: \"pos1\", Protocol: \"kcp\"}}}},\n\t\t{\"replace/outbounds\",\n\t\t\t&Config{OutboundConfigs: []OutboundDetourConfig{{Tag: \"pos0\"}, {Protocol: \"vmess\", Tag: \"pos1\"}}},\n\t\t\t&Config{OutboundConfigs: []OutboundDetourConfig{{Tag: \"pos1\", Protocol: \"kcp\"}}},\n\t\t\t\"\",\n\t\t\t&Config{OutboundConfigs: []OutboundDetourConfig{{Tag: \"pos0\"}, {Tag: \"pos1\", Protocol: \"kcp\"}}}},\n\t\t{\"replace/outbounds-prepend\",\n\t\t\t&Config{OutboundConfigs: []OutboundDetourConfig{{Tag: \"pos0\"}, {Protocol: \"vmess\", Tag: \"pos1\"}}},\n\t\t\t&Config{OutboundConfigs: []OutboundDetourConfig{{Tag: \"pos1\", Protocol: \"kcp\"}, {Tag: \"pos2\", Protocol: \"kcp\"}}},\n\t\t\t\"config.json\",\n\t\t\t&Config{OutboundConfigs: []OutboundDetourConfig{{Tag: \"pos1\", Protocol: \"kcp\"}, {Tag: \"pos2\", Protocol: \"kcp\"}}}},\n\t\t{\"replace/outbounds-append\",\n\t\t\t&Config{OutboundConfigs: []OutboundDetourConfig{{Tag: \"pos0\"}, {Protocol: \"vmess\", Tag: \"pos1\"}}},\n\t\t\t&Config{OutboundConfigs: []OutboundDetourConfig{{Tag: \"pos2\", Protocol: \"kcp\"}}},\n\t\t\t\"config_tail.json\",\n\t\t\t&Config{OutboundConfigs: []OutboundDetourConfig{{Tag: \"pos0\"}, {Protocol: \"vmess\", Tag: \"pos1\"}, {Tag: \"pos2\", Protocol: \"kcp\"}}}},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\ttt.orig.Override(tt.over, tt.fn)\n\t\t\tif r := cmp.Diff(tt.orig, tt.want); r != \"\" {\n\t\t\t\tt.Error(r)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "infra/conf/vless.go",
    "content": "package conf\n\nimport (\n\t\"encoding/json\"\n\t\"runtime\"\n\t\"strconv\"\n\t\"syscall\"\n\n\t\"github.com/golang/protobuf/proto\"\n\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/serial\"\n\t\"v2ray.com/core/proxy/vless\"\n\t\"v2ray.com/core/proxy/vless/inbound\"\n\t\"v2ray.com/core/proxy/vless/outbound\"\n)\n\ntype VLessInboundFallback struct {\n\tAlpn string          `json:\"alpn\"`\n\tPath string          `json:\"path\"`\n\tType string          `json:\"type\"`\n\tDest json.RawMessage `json:\"dest\"`\n\tXver uint64          `json:\"xver\"`\n}\n\ntype VLessInboundConfig struct {\n\tClients    []json.RawMessage       `json:\"clients\"`\n\tDecryption string                  `json:\"decryption\"`\n\tFallback   json.RawMessage         `json:\"fallback\"`\n\tFallbacks  []*VLessInboundFallback `json:\"fallbacks\"`\n}\n\n// Build implements Buildable\nfunc (c *VLessInboundConfig) Build() (proto.Message, error) {\n\n\tconfig := new(inbound.Config)\n\n\tif len(c.Clients) == 0 {\n\t\t//return nil, newError(`VLESS settings: \"clients\" is empty`)\n\t}\n\tconfig.Clients = make([]*protocol.User, len(c.Clients))\n\tfor idx, rawUser := range c.Clients {\n\t\tuser := new(protocol.User)\n\t\tif err := json.Unmarshal(rawUser, user); err != nil {\n\t\t\treturn nil, newError(`VLESS clients: invalid user`).Base(err)\n\t\t}\n\t\taccount := new(vless.Account)\n\t\tif err := json.Unmarshal(rawUser, account); err != nil {\n\t\t\treturn nil, newError(`VLESS clients: invalid user`).Base(err)\n\t\t}\n\n\t\tswitch account.Flow {\n\t\tcase \"\", \"xtls-rprx-origin\", \"xtls-rprx-direct\":\n\t\tdefault:\n\t\t\treturn nil, newError(`VLESS clients: \"flow\" doesn't support \"` + account.Flow + `\" in this version`)\n\t\t}\n\n\t\tif account.Encryption != \"\" {\n\t\t\treturn nil, newError(`VLESS clients: \"encryption\" should not in inbound settings`)\n\t\t}\n\n\t\tuser.Account = serial.ToTypedMessage(account)\n\t\tconfig.Clients[idx] = user\n\t}\n\n\tif c.Decryption != \"none\" {\n\t\treturn nil, newError(`VLESS settings: please add/set \"decryption\":\"none\" to every settings`)\n\t}\n\tconfig.Decryption = c.Decryption\n\n\tif c.Fallback != nil {\n\t\treturn nil, newError(`VLESS settings: please use \"fallbacks\":[{}] instead of \"fallback\":{}`)\n\t}\n\tfor _, fb := range c.Fallbacks {\n\t\tvar i uint16\n\t\tvar s string\n\t\tif err := json.Unmarshal(fb.Dest, &i); err == nil {\n\t\t\ts = strconv.Itoa(int(i))\n\t\t} else {\n\t\t\t_ = json.Unmarshal(fb.Dest, &s)\n\t\t}\n\t\tconfig.Fallbacks = append(config.Fallbacks, &inbound.Fallback{\n\t\t\tAlpn: fb.Alpn,\n\t\t\tPath: fb.Path,\n\t\t\tType: fb.Type,\n\t\t\tDest: s,\n\t\t\tXver: fb.Xver,\n\t\t})\n\t}\n\tfor _, fb := range config.Fallbacks {\n\t\t/*\n\t\t\tif fb.Alpn == \"h2\" && fb.Path != \"\" {\n\t\t\t\treturn nil, newError(`VLESS fallbacks: \"alpn\":\"h2\" doesn't support \"path\"`)\n\t\t\t}\n\t\t*/\n\t\tif fb.Path != \"\" && fb.Path[0] != '/' {\n\t\t\treturn nil, newError(`VLESS fallbacks: \"path\" must be empty or start with \"/\"`)\n\t\t}\n\t\tif fb.Type == \"\" && fb.Dest != \"\" {\n\t\t\tif fb.Dest == \"serve-ws-none\" {\n\t\t\t\tfb.Type = \"serve\"\n\t\t\t} else {\n\t\t\t\tswitch fb.Dest[0] {\n\t\t\t\tcase '@', '/':\n\t\t\t\t\tfb.Type = \"unix\"\n\t\t\t\t\tif fb.Dest[0] == '@' && len(fb.Dest) > 1 && fb.Dest[1] == '@' && runtime.GOOS == \"linux\" {\n\t\t\t\t\t\tfullAddr := make([]byte, len(syscall.RawSockaddrUnix{}.Path)) // may need padding to work in front of haproxy\n\t\t\t\t\t\tcopy(fullAddr, fb.Dest[1:])\n\t\t\t\t\t\tfb.Dest = string(fullAddr)\n\t\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\tif _, err := strconv.Atoi(fb.Dest); err == nil {\n\t\t\t\t\t\tfb.Dest = \"127.0.0.1:\" + fb.Dest\n\t\t\t\t\t}\n\t\t\t\t\tif _, _, err := net.SplitHostPort(fb.Dest); err == nil {\n\t\t\t\t\t\tfb.Type = \"tcp\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif fb.Type == \"\" {\n\t\t\treturn nil, newError(`VLESS fallbacks: please fill in a valid value for every \"dest\"`)\n\t\t}\n\t\tif fb.Xver > 2 {\n\t\t\treturn nil, newError(`VLESS fallbacks: invalid PROXY protocol version, \"xver\" only accepts 0, 1, 2`)\n\t\t}\n\t}\n\n\treturn config, nil\n}\n\ntype VLessOutboundVnext struct {\n\tAddress *Address          `json:\"address\"`\n\tPort    uint16            `json:\"port\"`\n\tUsers   []json.RawMessage `json:\"users\"`\n}\n\ntype VLessOutboundConfig struct {\n\tVnext []*VLessOutboundVnext `json:\"vnext\"`\n}\n\n// Build implements Buildable\nfunc (c *VLessOutboundConfig) Build() (proto.Message, error) {\n\n\tconfig := new(outbound.Config)\n\n\tif len(c.Vnext) == 0 {\n\t\treturn nil, newError(`VLESS settings: \"vnext\" is empty`)\n\t}\n\tconfig.Vnext = make([]*protocol.ServerEndpoint, len(c.Vnext))\n\tfor idx, rec := range c.Vnext {\n\t\tif rec.Address == nil {\n\t\t\treturn nil, newError(`VLESS vnext: \"address\" is not set`)\n\t\t}\n\t\tif len(rec.Users) == 0 {\n\t\t\treturn nil, newError(`VLESS vnext: \"users\" is empty`)\n\t\t}\n\t\tspec := &protocol.ServerEndpoint{\n\t\t\tAddress: rec.Address.Build(),\n\t\t\tPort:    uint32(rec.Port),\n\t\t\tUser:    make([]*protocol.User, len(rec.Users)),\n\t\t}\n\t\tfor idx, rawUser := range rec.Users {\n\t\t\tuser := new(protocol.User)\n\t\t\tif err := json.Unmarshal(rawUser, user); err != nil {\n\t\t\t\treturn nil, newError(`VLESS users: invalid user`).Base(err)\n\t\t\t}\n\t\t\taccount := new(vless.Account)\n\t\t\tif err := json.Unmarshal(rawUser, account); err != nil {\n\t\t\t\treturn nil, newError(`VLESS users: invalid user`).Base(err)\n\t\t\t}\n\n\t\t\tswitch account.Flow {\n\t\t\tcase \"\", \"xtls-rprx-origin\", \"xtls-rprx-origin-udp443\", \"xtls-rprx-direct\", \"xtls-rprx-direct-udp443\":\n\t\t\tdefault:\n\t\t\t\treturn nil, newError(`VLESS users: \"flow\" doesn't support \"` + account.Flow + `\" in this version`)\n\t\t\t}\n\n\t\t\tif account.Encryption != \"none\" {\n\t\t\t\treturn nil, newError(`VLESS users: please add/set \"encryption\":\"none\" for every user`)\n\t\t\t}\n\n\t\t\tuser.Account = serial.ToTypedMessage(account)\n\t\t\tspec.User[idx] = user\n\t\t}\n\t\tconfig.Vnext[idx] = spec\n\t}\n\n\treturn config, nil\n}\n"
  },
  {
    "path": "infra/conf/vless_test.go",
    "content": "package conf_test\n\nimport (\n\t\"testing\"\n\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/serial\"\n\t. \"v2ray.com/core/infra/conf\"\n\t\"v2ray.com/core/proxy/vless\"\n\t\"v2ray.com/core/proxy/vless/inbound\"\n\t\"v2ray.com/core/proxy/vless/outbound\"\n)\n\nfunc TestVLessOutbound(t *testing.T) {\n\tcreator := func() Buildable {\n\t\treturn new(VLessOutboundConfig)\n\t}\n\n\trunMultiTestCase(t, []TestCase{\n\t\t{\n\t\t\tInput: `{\n\t\t\t\t\"vnext\": [{\n\t\t\t\t\t\"address\": \"example.com\",\n\t\t\t\t\t\"port\": 443,\n\t\t\t\t\t\"users\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"id\": \"27848739-7e62-4138-9fd3-098a63964b6b\",\n\t\t\t\t\t\t\t\"flow\": \"xtls-rprx-origin-udp443\",\n\t\t\t\t\t\t\t\"encryption\": \"none\",\n\t\t\t\t\t\t\t\"level\": 0\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\tParser: loadJSON(creator),\n\t\t\tOutput: &outbound.Config{\n\t\t\t\tVnext: []*protocol.ServerEndpoint{\n\t\t\t\t\t{\n\t\t\t\t\t\tAddress: &net.IPOrDomain{\n\t\t\t\t\t\t\tAddress: &net.IPOrDomain_Domain{\n\t\t\t\t\t\t\t\tDomain: \"example.com\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tPort: 443,\n\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vless.Account{\n\t\t\t\t\t\t\t\t\tId:         \"27848739-7e62-4138-9fd3-098a63964b6b\",\n\t\t\t\t\t\t\t\t\tFlow:       \"xtls-rprx-origin-udp443\",\n\t\t\t\t\t\t\t\t\tEncryption: \"none\",\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\tLevel: 0,\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},\n\t})\n}\n\nfunc TestVLessInbound(t *testing.T) {\n\tcreator := func() Buildable {\n\t\treturn new(VLessInboundConfig)\n\t}\n\n\trunMultiTestCase(t, []TestCase{\n\t\t{\n\t\t\tInput: `{\n\t\t\t\t\"clients\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"id\": \"27848739-7e62-4138-9fd3-098a63964b6b\",\n\t\t\t\t\t\t\"flow\": \"xtls-rprx-origin\",\n\t\t\t\t\t\t\"level\": 0,\n\t\t\t\t\t\t\"email\": \"love@v2fly.org\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"decryption\": \"none\",\n\t\t\t\t\"fallbacks\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"dest\": 80\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"alpn\": \"h2\",\n\t\t\t\t\t\t\"dest\": \"@/dev/shm/domain.socket\",\n\t\t\t\t\t\t\"xver\": 2\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"path\": \"/innerws\",\n\t\t\t\t\t\t\"dest\": \"serve-ws-none\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}`,\n\t\t\tParser: loadJSON(creator),\n\t\t\tOutput: &inbound.Config{\n\t\t\t\tClients: []*protocol.User{\n\t\t\t\t\t{\n\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vless.Account{\n\t\t\t\t\t\t\tId:   \"27848739-7e62-4138-9fd3-098a63964b6b\",\n\t\t\t\t\t\t\tFlow: \"xtls-rprx-origin\",\n\t\t\t\t\t\t}),\n\t\t\t\t\t\tLevel: 0,\n\t\t\t\t\t\tEmail: \"love@v2fly.org\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tDecryption: \"none\",\n\t\t\t\tFallbacks: []*inbound.Fallback{\n\t\t\t\t\t{\n\t\t\t\t\t\tAlpn: \"\",\n\t\t\t\t\t\tPath: \"\",\n\t\t\t\t\t\tType: \"tcp\",\n\t\t\t\t\t\tDest: \"127.0.0.1:80\",\n\t\t\t\t\t\tXver: 0,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tAlpn: \"h2\",\n\t\t\t\t\t\tPath: \"\",\n\t\t\t\t\t\tType: \"unix\",\n\t\t\t\t\t\tDest: \"@/dev/shm/domain.socket\",\n\t\t\t\t\t\tXver: 2,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tAlpn: \"\",\n\t\t\t\t\t\tPath: \"/innerws\",\n\t\t\t\t\t\tType: \"serve\",\n\t\t\t\t\t\tDest: \"serve-ws-none\",\n\t\t\t\t\t\tXver: 0,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "infra/conf/vmess.go",
    "content": "package conf\n\nimport (\n\t\"encoding/json\"\n\t\"strings\"\n\n\t\"github.com/golang/protobuf/proto\"\n\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/serial\"\n\t\"v2ray.com/core/proxy/vmess\"\n\t\"v2ray.com/core/proxy/vmess/inbound\"\n\t\"v2ray.com/core/proxy/vmess/outbound\"\n)\n\ntype VMessAccount struct {\n\tID       string `json:\"id\"`\n\tAlterIds uint16 `json:\"alterId\"`\n\tSecurity string `json:\"security\"`\n}\n\n// Build implements Buildable\nfunc (a *VMessAccount) Build() *vmess.Account {\n\tvar st protocol.SecurityType\n\tswitch strings.ToLower(a.Security) {\n\tcase \"aes-128-gcm\":\n\t\tst = protocol.SecurityType_AES128_GCM\n\tcase \"chacha20-poly1305\":\n\t\tst = protocol.SecurityType_CHACHA20_POLY1305\n\tcase \"auto\":\n\t\tst = protocol.SecurityType_AUTO\n\tcase \"none\":\n\t\tst = protocol.SecurityType_NONE\n\tdefault:\n\t\tst = protocol.SecurityType_AUTO\n\t}\n\treturn &vmess.Account{\n\t\tId:      a.ID,\n\t\tAlterId: uint32(a.AlterIds),\n\t\tSecuritySettings: &protocol.SecurityConfig{\n\t\t\tType: st,\n\t\t},\n\t}\n}\n\ntype VMessDetourConfig struct {\n\tToTag string `json:\"to\"`\n}\n\n// Build implements Buildable\nfunc (c *VMessDetourConfig) Build() *inbound.DetourConfig {\n\treturn &inbound.DetourConfig{\n\t\tTo: c.ToTag,\n\t}\n}\n\ntype FeaturesConfig struct {\n\tDetour *VMessDetourConfig `json:\"detour\"`\n}\n\ntype VMessDefaultConfig struct {\n\tAlterIDs uint16 `json:\"alterId\"`\n\tLevel    byte   `json:\"level\"`\n}\n\n// Build implements Buildable\nfunc (c *VMessDefaultConfig) Build() *inbound.DefaultConfig {\n\tconfig := new(inbound.DefaultConfig)\n\tconfig.AlterId = uint32(c.AlterIDs)\n\tif config.AlterId == 0 {\n\t\tconfig.AlterId = 32\n\t}\n\tconfig.Level = uint32(c.Level)\n\treturn config\n}\n\ntype VMessInboundConfig struct {\n\tUsers        []json.RawMessage   `json:\"clients\"`\n\tFeatures     *FeaturesConfig     `json:\"features\"`\n\tDefaults     *VMessDefaultConfig `json:\"default\"`\n\tDetourConfig *VMessDetourConfig  `json:\"detour\"`\n\tSecureOnly   bool                `json:\"disableInsecureEncryption\"`\n}\n\n// Build implements Buildable\nfunc (c *VMessInboundConfig) Build() (proto.Message, error) {\n\tconfig := &inbound.Config{\n\t\tSecureEncryptionOnly: c.SecureOnly,\n\t}\n\n\tif c.Defaults != nil {\n\t\tconfig.Default = c.Defaults.Build()\n\t}\n\n\tif c.DetourConfig != nil {\n\t\tconfig.Detour = c.DetourConfig.Build()\n\t} else if c.Features != nil && c.Features.Detour != nil {\n\t\tconfig.Detour = c.Features.Detour.Build()\n\t}\n\n\tconfig.User = make([]*protocol.User, len(c.Users))\n\tfor idx, rawData := range c.Users {\n\t\tuser := new(protocol.User)\n\t\tif err := json.Unmarshal(rawData, user); err != nil {\n\t\t\treturn nil, newError(\"invalid VMess user\").Base(err)\n\t\t}\n\t\taccount := new(VMessAccount)\n\t\tif err := json.Unmarshal(rawData, account); err != nil {\n\t\t\treturn nil, newError(\"invalid VMess user\").Base(err)\n\t\t}\n\t\tuser.Account = serial.ToTypedMessage(account.Build())\n\t\tconfig.User[idx] = user\n\t}\n\n\treturn config, nil\n}\n\ntype VMessOutboundTarget struct {\n\tAddress *Address          `json:\"address\"`\n\tPort    uint16            `json:\"port\"`\n\tUsers   []json.RawMessage `json:\"users\"`\n}\ntype VMessOutboundConfig struct {\n\tReceivers []*VMessOutboundTarget `json:\"vnext\"`\n}\n\n// Build implements Buildable\nfunc (c *VMessOutboundConfig) Build() (proto.Message, error) {\n\tconfig := new(outbound.Config)\n\n\tif len(c.Receivers) == 0 {\n\t\treturn nil, newError(\"0 VMess receiver configured\")\n\t}\n\tserverSpecs := make([]*protocol.ServerEndpoint, len(c.Receivers))\n\tfor idx, rec := range c.Receivers {\n\t\tif len(rec.Users) == 0 {\n\t\t\treturn nil, newError(\"0 user configured for VMess outbound\")\n\t\t}\n\t\tif rec.Address == nil {\n\t\t\treturn nil, newError(\"address is not set in VMess outbound config\")\n\t\t}\n\t\tspec := &protocol.ServerEndpoint{\n\t\t\tAddress: rec.Address.Build(),\n\t\t\tPort:    uint32(rec.Port),\n\t\t}\n\t\tfor _, rawUser := range rec.Users {\n\t\t\tuser := new(protocol.User)\n\t\t\tif err := json.Unmarshal(rawUser, user); err != nil {\n\t\t\t\treturn nil, newError(\"invalid VMess user\").Base(err)\n\t\t\t}\n\t\t\taccount := new(VMessAccount)\n\t\t\tif err := json.Unmarshal(rawUser, account); err != nil {\n\t\t\t\treturn nil, newError(\"invalid VMess user\").Base(err)\n\t\t\t}\n\t\t\tuser.Account = serial.ToTypedMessage(account.Build())\n\t\t\tspec.User = append(spec.User, user)\n\t\t}\n\t\tserverSpecs[idx] = spec\n\t}\n\tconfig.Receiver = serverSpecs\n\treturn config, nil\n}\n"
  },
  {
    "path": "infra/conf/vmess_test.go",
    "content": "package conf_test\n\nimport (\n\t\"testing\"\n\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/serial\"\n\t. \"v2ray.com/core/infra/conf\"\n\t\"v2ray.com/core/proxy/vmess\"\n\t\"v2ray.com/core/proxy/vmess/inbound\"\n\t\"v2ray.com/core/proxy/vmess/outbound\"\n)\n\nfunc TestVMessOutbound(t *testing.T) {\n\tcreator := func() Buildable {\n\t\treturn new(VMessOutboundConfig)\n\t}\n\n\trunMultiTestCase(t, []TestCase{\n\t\t{\n\t\t\tInput: `{\n\t\t\t\t\"vnext\": [{\n\t\t\t\t\t\"address\": \"127.0.0.1\",\n\t\t\t\t\t\"port\": 80,\n\t\t\t\t\t\"users\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"id\": \"e641f5ad-9397-41e3-bf1a-e8740dfed019\",\n\t\t\t\t\t\t\t\"email\": \"love@v2ray.com\",\n\t\t\t\t\t\t\t\"level\": 255\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\tParser: loadJSON(creator),\n\t\t\tOutput: &outbound.Config{\n\t\t\t\tReceiver: []*protocol.ServerEndpoint{\n\t\t\t\t\t{\n\t\t\t\t\t\tAddress: &net.IPOrDomain{\n\t\t\t\t\t\t\tAddress: &net.IPOrDomain_Ip{\n\t\t\t\t\t\t\t\tIp: []byte{127, 0, 0, 1},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tPort: 80,\n\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tEmail: \"love@v2ray.com\",\n\t\t\t\t\t\t\t\tLevel: 255,\n\t\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\t\tId:      \"e641f5ad-9397-41e3-bf1a-e8740dfed019\",\n\t\t\t\t\t\t\t\t\tAlterId: 0,\n\t\t\t\t\t\t\t\t\tSecuritySettings: &protocol.SecurityConfig{\n\t\t\t\t\t\t\t\t\t\tType: protocol.SecurityType_AUTO,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t}),\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},\n\t})\n}\n\nfunc TestVMessInbound(t *testing.T) {\n\tcreator := func() Buildable {\n\t\treturn new(VMessInboundConfig)\n\t}\n\n\trunMultiTestCase(t, []TestCase{\n\t\t{\n\t\t\tInput: `{\n\t\t\t\t\"clients\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"id\": \"27848739-7e62-4138-9fd3-098a63964b6b\",\n\t\t\t\t\t\t\"level\": 0,\n\t\t\t\t\t\t\"alterId\": 16,\n\t\t\t\t\t\t\"email\": \"love@v2ray.com\",\n\t\t\t\t\t\t\"security\": \"aes-128-gcm\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"default\": {\n\t\t\t\t\t\"level\": 0,\n\t\t\t\t\t\"alterId\": 32\n\t\t\t\t},\n\t\t\t\t\"detour\": {\n\t\t\t\t\t\"to\": \"tag_to_detour\"\n\t\t\t\t},\n\t\t\t\t\"disableInsecureEncryption\": true\n\t\t\t}`,\n\t\t\tParser: loadJSON(creator),\n\t\t\tOutput: &inbound.Config{\n\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t{\n\t\t\t\t\t\tLevel: 0,\n\t\t\t\t\t\tEmail: \"love@v2ray.com\",\n\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\tId:      \"27848739-7e62-4138-9fd3-098a63964b6b\",\n\t\t\t\t\t\t\tAlterId: 16,\n\t\t\t\t\t\t\tSecuritySettings: &protocol.SecurityConfig{\n\t\t\t\t\t\t\t\tType: protocol.SecurityType_AES128_GCM,\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\tDefault: &inbound.DefaultConfig{\n\t\t\t\t\tLevel:   0,\n\t\t\t\t\tAlterId: 32,\n\t\t\t\t},\n\t\t\t\tDetour: &inbound.DetourConfig{\n\t\t\t\t\tTo: \"tag_to_detour\",\n\t\t\t\t},\n\t\t\t\tSecureEncryptionOnly: true,\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "infra/control/api.go",
    "content": "package control\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"flag\"\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/golang/protobuf/proto\"\n\t\"google.golang.org/grpc\"\n\n\tlogService \"v2ray.com/core/app/log/command\"\n\tstatsService \"v2ray.com/core/app/stats/command\"\n\t\"v2ray.com/core/common\"\n)\n\ntype ApiCommand struct{}\n\nfunc (c *ApiCommand) Name() string {\n\treturn \"api\"\n}\n\nfunc (c *ApiCommand) Description() Description {\n\treturn Description{\n\t\tShort: \"Call V2Ray API\",\n\t\tUsage: []string{\n\t\t\t\"v2ctl api [--server=127.0.0.1:8080] Service.Method Request\",\n\t\t\t\"Call an API in an V2Ray process.\",\n\t\t\t\"The following methods are currently supported:\",\n\t\t\t\"\\tLoggerService.RestartLogger\",\n\t\t\t\"\\tStatsService.GetStats\",\n\t\t\t\"\\tStatsService.QueryStats\",\n\t\t\t\"API calls in this command have a timeout to the server of 3 seconds.\",\n\t\t\t\"Examples:\",\n\t\t\t\"v2ctl api --server=127.0.0.1:8080 LoggerService.RestartLogger '' \",\n\t\t\t\"v2ctl api --server=127.0.0.1:8080 StatsService.QueryStats 'pattern: \\\"\\\" reset: false'\",\n\t\t\t\"v2ctl api --server=127.0.0.1:8080 StatsService.GetStats 'name: \\\"inbound>>>statin>>>traffic>>>downlink\\\" reset: false'\",\n\t\t\t\"v2ctl api --server=127.0.0.1:8080 StatsService.GetSysStats ''\",\n\t\t},\n\t}\n}\n\nfunc (c *ApiCommand) Execute(args []string) error {\n\tfs := flag.NewFlagSet(c.Name(), flag.ContinueOnError)\n\n\tserverAddrPtr := fs.String(\"server\", \"127.0.0.1:8080\", \"Server address\")\n\n\tif err := fs.Parse(args); err != nil {\n\t\treturn err\n\t}\n\n\tunnamedArgs := fs.Args()\n\tif len(unnamedArgs) < 2 {\n\t\treturn newError(\"service name or request not specified.\")\n\t}\n\n\tservice, method := getServiceMethod(unnamedArgs[0])\n\thandler, found := serivceHandlerMap[strings.ToLower(service)]\n\tif !found {\n\t\treturn newError(\"unknown service: \", service)\n\t}\n\n\tctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)\n\tdefer cancel()\n\n\tconn, err := grpc.DialContext(ctx, *serverAddrPtr, grpc.WithInsecure(), grpc.WithBlock())\n\tif err != nil {\n\t\treturn newError(\"failed to dial \", *serverAddrPtr).Base(err)\n\t}\n\tdefer conn.Close()\n\n\tresponse, err := handler(ctx, conn, method, unnamedArgs[1])\n\tif err != nil {\n\t\treturn newError(\"failed to call service \", unnamedArgs[0]).Base(err)\n\t}\n\n\tfmt.Println(response)\n\treturn nil\n}\n\nfunc getServiceMethod(s string) (string, string) {\n\tss := strings.Split(s, \".\")\n\tservice := ss[0]\n\tvar method string\n\tif len(ss) > 1 {\n\t\tmethod = ss[1]\n\t}\n\treturn service, method\n}\n\ntype serviceHandler func(ctx context.Context, conn *grpc.ClientConn, method string, request string) (string, error)\n\nvar serivceHandlerMap = map[string]serviceHandler{\n\t\"statsservice\":  callStatsService,\n\t\"loggerservice\": callLogService,\n}\n\nfunc callLogService(ctx context.Context, conn *grpc.ClientConn, method string, request string) (string, error) {\n\tclient := logService.NewLoggerServiceClient(conn)\n\n\tswitch strings.ToLower(method) {\n\tcase \"restartlogger\":\n\t\tr := &logService.RestartLoggerRequest{}\n\t\tif err := proto.UnmarshalText(request, r); err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\tresp, err := client.RestartLogger(ctx, r)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\treturn proto.MarshalTextString(resp), nil\n\tdefault:\n\t\treturn \"\", errors.New(\"Unknown method: \" + method)\n\t}\n}\n\nfunc callStatsService(ctx context.Context, conn *grpc.ClientConn, method string, request string) (string, error) {\n\tclient := statsService.NewStatsServiceClient(conn)\n\n\tswitch strings.ToLower(method) {\n\tcase \"getstats\":\n\t\tr := &statsService.GetStatsRequest{}\n\t\tif err := proto.UnmarshalText(request, r); err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\tresp, err := client.GetStats(ctx, r)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\treturn proto.MarshalTextString(resp), nil\n\tcase \"querystats\":\n\t\tr := &statsService.QueryStatsRequest{}\n\t\tif err := proto.UnmarshalText(request, r); err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\tresp, err := client.QueryStats(ctx, r)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\treturn proto.MarshalTextString(resp), nil\n\tcase \"getsysstats\":\n\t\t// SysStatsRequest is an empty message\n\t\tr := &statsService.SysStatsRequest{}\n\t\tresp, err := client.GetSysStats(ctx, r)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\treturn proto.MarshalTextString(resp), nil\n\tdefault:\n\t\treturn \"\", errors.New(\"Unknown method: \" + method)\n\t}\n}\n\nfunc init() {\n\tcommon.Must(RegisterCommand(&ApiCommand{}))\n}\n"
  },
  {
    "path": "infra/control/cert.go",
    "content": "package control\n\nimport (\n\t\"context\"\n\t\"crypto/x509\"\n\t\"encoding/json\"\n\t\"flag\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/protocol/tls/cert\"\n\t\"v2ray.com/core/common/task\"\n)\n\ntype stringList []string\n\nfunc (l *stringList) String() string {\n\treturn \"String list\"\n}\n\nfunc (l *stringList) Set(v string) error {\n\tif v == \"\" {\n\t\treturn newError(\"empty value\")\n\t}\n\t*l = append(*l, v)\n\treturn nil\n}\n\ntype jsonCert struct {\n\tCertificate []string `json:\"certificate\"`\n\tKey         []string `json:\"key\"`\n}\n\ntype CertificateCommand struct {\n}\n\nfunc (c *CertificateCommand) Name() string {\n\treturn \"cert\"\n}\n\nfunc (c *CertificateCommand) Description() Description {\n\treturn Description{\n\t\tShort: \"Generate TLS certificates.\",\n\t\tUsage: []string{\n\t\t\t\"v2ctl cert [--ca] [--domain=v2ray.com] [--expire=240h]\",\n\t\t\t\"Generate new TLS certificate\",\n\t\t\t\"--ca The new certificate is a CA certificate\",\n\t\t\t\"--domain Common name for the certificate\",\n\t\t\t\"--expire Time until certificate expires. 240h = 10 days.\",\n\t\t},\n\t}\n}\n\nfunc (c *CertificateCommand) printJson(certificate *cert.Certificate) {\n\tcertPEM, keyPEM := certificate.ToPEM()\n\tjCert := &jsonCert{\n\t\tCertificate: strings.Split(strings.TrimSpace(string(certPEM)), \"\\n\"),\n\t\tKey:         strings.Split(strings.TrimSpace(string(keyPEM)), \"\\n\"),\n\t}\n\tcontent, err := json.MarshalIndent(jCert, \"\", \"  \")\n\tcommon.Must(err)\n\tos.Stdout.Write(content)\n\tos.Stdout.WriteString(\"\\n\")\n}\n\nfunc (c *CertificateCommand) writeFile(content []byte, name string) error {\n\tf, err := os.Create(name)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer f.Close()\n\n\treturn common.Error2(f.Write(content))\n}\n\nfunc (c *CertificateCommand) printFile(certificate *cert.Certificate, name string) error {\n\tcertPEM, keyPEM := certificate.ToPEM()\n\treturn task.Run(context.Background(), func() error {\n\t\treturn c.writeFile(certPEM, name+\"_cert.pem\")\n\t}, func() error {\n\t\treturn c.writeFile(keyPEM, name+\"_key.pem\")\n\t})\n}\n\nfunc (c *CertificateCommand) Execute(args []string) error {\n\tfs := flag.NewFlagSet(c.Name(), flag.ContinueOnError)\n\n\tvar domainNames stringList\n\tfs.Var(&domainNames, \"domain\", \"Domain name for the certificate\")\n\n\tcommonName := fs.String(\"name\", \"V2Ray Inc\", \"The common name of this certificate\")\n\torganization := fs.String(\"org\", \"V2Ray Inc\", \"Organization of the certificate\")\n\n\tisCA := fs.Bool(\"ca\", false, \"Whether this certificate is a CA\")\n\tjsonOutput := fs.Bool(\"json\", true, \"Print certificate in JSON format\")\n\tfileOutput := fs.String(\"file\", \"\", \"Save certificate in file.\")\n\n\texpire := fs.Duration(\"expire\", time.Hour*24*90 /* 90 days */, \"Time until the certificate expires. Default value 3 months.\")\n\n\tif err := fs.Parse(args); err != nil {\n\t\treturn err\n\t}\n\n\tvar opts []cert.Option\n\tif *isCA {\n\t\topts = append(opts, cert.Authority(*isCA))\n\t\topts = append(opts, cert.KeyUsage(x509.KeyUsageCertSign|x509.KeyUsageKeyEncipherment|x509.KeyUsageDigitalSignature))\n\t}\n\n\topts = append(opts, cert.NotAfter(time.Now().Add(*expire)))\n\topts = append(opts, cert.CommonName(*commonName))\n\tif len(domainNames) > 0 {\n\t\topts = append(opts, cert.DNSNames(domainNames...))\n\t}\n\topts = append(opts, cert.Organization(*organization))\n\n\tcert, err := cert.Generate(nil, opts...)\n\tif err != nil {\n\t\treturn newError(\"failed to generate TLS certificate\").Base(err)\n\t}\n\n\tif *jsonOutput {\n\t\tc.printJson(cert)\n\t}\n\n\tif len(*fileOutput) > 0 {\n\t\tif err := c.printFile(cert, *fileOutput); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc init() {\n\tcommon.Must(RegisterCommand(&CertificateCommand{}))\n}\n"
  },
  {
    "path": "infra/control/command.go",
    "content": "package control\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n)\n\ntype Description struct {\n\tShort string\n\tUsage []string\n}\n\ntype Command interface {\n\tName() string\n\tDescription() Description\n\tExecute(args []string) error\n}\n\nvar (\n\tcommandRegistry = make(map[string]Command)\n\tctllog          = log.New(os.Stderr, \"v2ctl> \", 0)\n)\n\nfunc RegisterCommand(cmd Command) error {\n\tentry := strings.ToLower(cmd.Name())\n\tif entry == \"\" {\n\t\treturn newError(\"empty command name\")\n\t}\n\tcommandRegistry[entry] = cmd\n\treturn nil\n}\n\nfunc GetCommand(name string) Command {\n\tcmd, found := commandRegistry[name]\n\tif !found {\n\t\treturn nil\n\t}\n\treturn cmd\n}\n\ntype hiddenCommand interface {\n\tHidden() bool\n}\n\nfunc PrintUsage() {\n\tfor name, cmd := range commandRegistry {\n\t\tif _, ok := cmd.(hiddenCommand); ok {\n\t\t\tcontinue\n\t\t}\n\t\tfmt.Println(\"   \", name, \"\\t\\t\\t\", cmd.Description())\n\t}\n}\n"
  },
  {
    "path": "infra/control/config.go",
    "content": "package control\n\nimport (\n\t\"bytes\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/golang/protobuf/proto\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/infra/conf\"\n\t\"v2ray.com/core/infra/conf/serial\"\n)\n\n// ConfigCommand is the json to pb convert struct\ntype ConfigCommand struct{}\n\n// Name for cmd usage\nfunc (c *ConfigCommand) Name() string {\n\treturn \"config\"\n}\n\n// Description for help usage\nfunc (c *ConfigCommand) Description() Description {\n\treturn Description{\n\t\tShort: \"merge multiple json config\",\n\t\tUsage: []string{\"v2ctl config config.json c1.json c2.json <url>.json\"},\n\t}\n}\n\n// Execute real work here.\nfunc (c *ConfigCommand) Execute(args []string) error {\n\tif len(args) < 1 {\n\t\treturn newError(\"empty config list\")\n\t}\n\n\tconf := &conf.Config{}\n\tfor _, arg := range args {\n\t\tctllog.Println(\"Read config: \", arg)\n\t\tr, err := c.LoadArg(arg)\n\t\tcommon.Must(err)\n\t\tc, err := serial.DecodeJSONConfig(r)\n\t\tif err != nil {\n\t\t\tctllog.Fatalln(err)\n\t\t}\n\t\tconf.Override(c, arg)\n\t}\n\n\tpbConfig, err := conf.Build()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tbytesConfig, err := proto.Marshal(pbConfig)\n\tif err != nil {\n\t\treturn newError(\"failed to marshal proto config\").Base(err)\n\t}\n\n\tif _, err := os.Stdout.Write(bytesConfig); err != nil {\n\t\treturn newError(\"failed to write proto config\").Base(err)\n\t}\n\n\treturn nil\n}\n\n// LoadArg loads one arg, maybe an remote url, or local file path\nfunc (c *ConfigCommand) LoadArg(arg string) (out io.Reader, err error) {\n\n\tvar data []byte\n\tif strings.HasPrefix(arg, \"http://\") || strings.HasPrefix(arg, \"https://\") {\n\t\tdata, err = FetchHTTPContent(arg)\n\t} else if arg == \"stdin:\" {\n\t\tdata, err = ioutil.ReadAll(os.Stdin)\n\t} else {\n\t\tdata, err = ioutil.ReadFile(arg)\n\t}\n\n\tif err != nil {\n\t\treturn\n\t}\n\tout = bytes.NewBuffer(data)\n\treturn\n}\n\nfunc init() {\n\tcommon.Must(RegisterCommand(&ConfigCommand{}))\n}\n"
  },
  {
    "path": "infra/control/control.go",
    "content": "package control\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n"
  },
  {
    "path": "infra/control/errors.generated.go",
    "content": "package control\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "infra/control/fetch.go",
    "content": "package control\n\nimport (\n\t\"net/http\"\n\t\"net/url\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n)\n\ntype FetchCommand struct{}\n\nfunc (c *FetchCommand) Name() string {\n\treturn \"fetch\"\n}\n\nfunc (c *FetchCommand) Description() Description {\n\treturn Description{\n\t\tShort: \"Fetch resources\",\n\t\tUsage: []string{\"v2ctl fetch <url>\"},\n\t}\n}\n\nfunc (c *FetchCommand) Execute(args []string) error {\n\tif len(args) < 1 {\n\t\treturn newError(\"empty url\")\n\t}\n\tcontent, err := FetchHTTPContent(args[0])\n\tif err != nil {\n\t\treturn newError(\"failed to read HTTP response\").Base(err)\n\t}\n\n\tos.Stdout.Write(content)\n\treturn nil\n}\n\n// FetchHTTPContent dials https for remote content\nfunc FetchHTTPContent(target string) ([]byte, error) {\n\n\tparsedTarget, err := url.Parse(target)\n\tif err != nil {\n\t\treturn nil, newError(\"invalid URL: \", target).Base(err)\n\t}\n\n\tif s := strings.ToLower(parsedTarget.Scheme); s != \"http\" && s != \"https\" {\n\t\treturn nil, newError(\"invalid scheme: \", parsedTarget.Scheme)\n\t}\n\n\tclient := &http.Client{\n\t\tTimeout: 30 * time.Second,\n\t}\n\tresp, err := client.Do(&http.Request{\n\t\tMethod: \"GET\",\n\t\tURL:    parsedTarget,\n\t\tClose:  true,\n\t})\n\tif err != nil {\n\t\treturn nil, newError(\"failed to dial to \", target).Base(err)\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != 200 {\n\t\treturn nil, newError(\"unexpected HTTP status code: \", resp.StatusCode)\n\t}\n\n\tcontent, err := buf.ReadAllToBytes(resp.Body)\n\tif err != nil {\n\t\treturn nil, newError(\"failed to read HTTP response\").Base(err)\n\t}\n\n\treturn content, nil\n}\n\nfunc init() {\n\tcommon.Must(RegisterCommand(&FetchCommand{}))\n}\n"
  },
  {
    "path": "infra/control/love.go",
    "content": "package control\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"compress/gzip\"\n\t\"encoding/base64\"\n\t\"fmt\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/platform\"\n)\n\nconst content = \"H4sIAAAAAAAC/4SVMaskNwzH+/kUW6izcSthMGrcqLhVk0rdQS5cSMg7Xu4S0vizB8meZd57M3ta2GHX/ukvyZZmY2ZKDMzCzJyY5yOlxKII1omsf+qkBiiC6WhbYsbkjDAfySQsJqD3jtrD0EBM3sBHzG3kUsrglIQREXonpd47kYIi4AHmgI9Wcq2jlJITC6JZJ+v3ECYzBMAHyYm392yuY4zWsjACmHZSh6l3A0JETzGlWZqDsnArpTg62mhJONhOdO90p97V1BAnteoaOcuummtrrtuERQwUiJwP8a4KGKcyxdOCw1spOY+WHueFqmakAIgUSSuhwKNgobxKXSLbtg6r5cFmBiAeF6yCkYycmv+BiCIiW8ScHa3DgxAuZQbRhFNrLTFo96RBmx9jKWWG5nBsjyJzuIkftUblonppZU5t5LzwIks5L1a4lijagQxLokbIYwxfytNDC+XQqrWW9fzAunhqh5/Tg8PuaMw0d/Tcw3iDO81bHfWM/AnutMh2xqSUntMzd3wHDy9iHMQz8bmUZYvqedTJ5GgOnrNt7FIbSlwXE3wDI19n/KA38MsLaP4l89b5F8AV3ESOMIEhIBgezHBc0H6xV9KbaXwMvPcNvIHcC0C7UPZQx4JVTb35/AneSQq+bAYXsBmY7TCRupF2NTdVm/+ch22xa0pvRERKqt1oxj9DUbXzU84Gvj5hc5a81SlAUwMwgEs4T9+7sg9lb9h+908MWiKV8xtWciVTmnB3tivRjNerfXdxpfEBbq2NUvLMM5R9NLuyQg8nXT0PIh1xPd/wrcV49oJ6zbZaPlj2V87IY9T3F2XCOcW2MbZyZd49H+9m81E1N9SxlU+ff/1y+/f3719vf7788+Ugv/ffbMIH7ZNj0dsT4WMHHwLPu/Rp2O75uh99AK+N2xn7ZHq1OK6gczkN+9ngdOl1Qvki5xwSR8vFX6D+9vXA97B/+fr5rz9u/738uP328urP19vfP759e3n9Xs6jamvqlfJ/AAAA//+YAMZjDgkAAA==\"\n\ntype LoveCommand struct{}\n\nfunc (*LoveCommand) Name() string {\n\treturn \"lovevictoria\"\n}\n\nfunc (*LoveCommand) Hidden() bool {\n\treturn false\n}\n\nfunc (c *LoveCommand) Description() Description {\n\treturn Description{\n\t\tShort: \"\",\n\t\tUsage: []string{\"\"},\n\t}\n}\n\nfunc (*LoveCommand) Execute([]string) error {\n\tc, err := base64.StdEncoding.DecodeString(content)\n\tcommon.Must(err)\n\treader, err := gzip.NewReader(bytes.NewBuffer(c))\n\tcommon.Must(err)\n\tb := make([]byte, 4096)\n\tnBytes, _ := reader.Read(b)\n\n\tbb := bytes.NewBuffer(b[:nBytes])\n\tscanner := bufio.NewScanner(bb)\n\tfor scanner.Scan() {\n\t\ts := scanner.Text()\n\t\tfmt.Print(s + platform.LineSeparator())\n\t}\n\n\treturn nil\n}\n\nfunc init() {\n\tcommon.Must(RegisterCommand(&LoveCommand{}))\n}\n"
  },
  {
    "path": "infra/control/main/BUILD",
    "content": "load(\"//infra/bazel:matrix.bzl\", \"SUPPORTED_MATRIX\")\nload(\"//infra/control/main:targets.bzl\", \"gen_targets\")\n\npackage(default_visibility=[\"//visibility:public\"])\n\ngen_targets(SUPPORTED_MATRIX)\n"
  },
  {
    "path": "infra/control/main/main.go",
    "content": "package main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"os\"\n\n\tcommlog \"v2ray.com/core/common/log\"\n\t// _ \"v2ray.com/core/infra/conf/command\"\n\t\"v2ray.com/core/infra/control\"\n)\n\nfunc getCommandName() string {\n\tif len(os.Args) > 1 {\n\t\treturn os.Args[1]\n\t}\n\treturn \"\"\n}\n\nfunc main() {\n\t// let the v2ctl prints log at stderr\n\tcommlog.RegisterHandler(commlog.NewLogger(commlog.CreateStderrLogWriter()))\n\tname := getCommandName()\n\tcmd := control.GetCommand(name)\n\tif cmd == nil {\n\t\tfmt.Fprintln(os.Stderr, \"Unknown command:\", name)\n\t\tfmt.Fprintln(os.Stderr)\n\n\t\tfmt.Println(\"v2ctl <command>\")\n\t\tfmt.Println(\"Available commands:\")\n\t\tcontrol.PrintUsage()\n\t\treturn\n\t}\n\n\tif err := cmd.Execute(os.Args[2:]); err != nil {\n\t\thasError := false\n\t\tif err != flag.ErrHelp {\n\t\t\tfmt.Fprintln(os.Stderr, err.Error())\n\t\t\tfmt.Fprintln(os.Stderr)\n\t\t\thasError = true\n\t\t}\n\n\t\tfor _, line := range cmd.Description().Usage {\n\t\t\tfmt.Println(line)\n\t\t}\n\n\t\tif hasError {\n\t\t\tos.Exit(-1)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "infra/control/main/targets.bzl",
    "content": "load(\"//infra/bazel:build.bzl\", \"foreign_go_binary\")\n\ndef gen_targets(matrix):\n  pkg = \"./infra/control/main\"\n  output = \"v2ctl\"\n\n  for (os, arch, ver) in matrix:\n\n    if arch in [\"arm\"]:\n      bin_name = \"v2ctl_\" + os + \"_\" + arch + \"_\" + ver\n      foreign_go_binary(\n        name = bin_name,\n        pkg = pkg,\n        output = output,\n        os = os,\n        arch = arch,\n        ver = ver,\n        arm = ver,\n        gotags = \"confonly\",\n      )\n\n    else:\n      bin_name = \"v2ctl_\" + os + \"_\" + arch\n      foreign_go_binary(\n        name = bin_name,\n        pkg = pkg,\n        output = output,\n        os = os,\n        arch = arch,\n        ver = ver,\n        gotags = \"confonly\",\n      )\n\n      if arch in [\"mips\", \"mipsle\"]:\n        bin_name = \"v2ctl_\" + os + \"_\" + arch + \"_softfloat\"\n        foreign_go_binary(\n          name = bin_name,\n          pkg = pkg,\n          output = output + \"_softfloat\",\n          os = os,\n          arch = arch,\n          ver = ver,\n          mips = \"softfloat\",\n          gotags = \"confonly\",\n        )\n"
  },
  {
    "path": "infra/control/tlsping.go",
    "content": "package control\n\nimport (\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"flag\"\n\t\"fmt\"\n\t\"net\"\n\n\t\"v2ray.com/core/common\"\n)\n\ntype TlsPingCommand struct{}\n\nfunc (c *TlsPingCommand) Name() string {\n\treturn \"tlsping\"\n}\n\nfunc (c *TlsPingCommand) Description() Description {\n\treturn Description{\n\t\tShort: \"Ping the domain with TLS handshake\",\n\t\tUsage: []string{\"v2ctl tlsping <domain> --ip <ip>\"},\n\t}\n}\n\nfunc printCertificates(certs []*x509.Certificate) {\n\tfor _, cert := range certs {\n\t\tif len(cert.DNSNames) == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tfmt.Println(\"Allowed domains: \", cert.DNSNames)\n\t}\n}\n\nfunc (c *TlsPingCommand) Execute(args []string) error {\n\tfs := flag.NewFlagSet(c.Name(), flag.ContinueOnError)\n\tipStr := fs.String(\"ip\", \"\", \"IP address of the domain\")\n\n\tif err := fs.Parse(args); err != nil {\n\t\treturn newError(\"flag parsing\").Base(err)\n\t}\n\n\tif fs.NArg() < 1 {\n\t\treturn newError(\"domain not specified\")\n\t}\n\n\tdomain := fs.Arg(0)\n\tfmt.Println(\"Tls ping: \", domain)\n\n\tvar ip net.IP\n\tif len(*ipStr) > 0 {\n\t\tv := net.ParseIP(*ipStr)\n\t\tif v == nil {\n\t\t\treturn newError(\"invalid IP: \", *ipStr)\n\t\t}\n\t\tip = v\n\t} else {\n\t\tv, err := net.ResolveIPAddr(\"ip\", domain)\n\t\tif err != nil {\n\t\t\treturn newError(\"resolve IP\").Base(err)\n\t\t}\n\t\tip = v.IP\n\t}\n\tfmt.Println(\"Using IP: \", ip.String())\n\n\tfmt.Println(\"-------------------\")\n\tfmt.Println(\"Pinging without SNI\")\n\t{\n\t\ttcpConn, err := net.DialTCP(\"tcp\", nil, &net.TCPAddr{IP: ip, Port: 443})\n\t\tif err != nil {\n\t\t\treturn newError(\"dial tcp\").Base(err)\n\t\t}\n\t\ttlsConn := tls.Client(tcpConn, &tls.Config{\n\t\t\tInsecureSkipVerify: true,\n\t\t\tNextProtos:         []string{\"http/1.1\"},\n\t\t\tMaxVersion:         tls.VersionTLS12,\n\t\t\tMinVersion:         tls.VersionTLS12,\n\t\t})\n\t\terr = tlsConn.Handshake()\n\t\tif err != nil {\n\t\t\tfmt.Println(\"Handshake failure: \", err)\n\t\t} else {\n\t\t\tfmt.Println(\"Handshake succeeded\")\n\t\t\tprintCertificates(tlsConn.ConnectionState().PeerCertificates)\n\t\t}\n\t\ttlsConn.Close()\n\t}\n\n\tfmt.Println(\"-------------------\")\n\tfmt.Println(\"Pinging with SNI\")\n\t{\n\t\ttcpConn, err := net.DialTCP(\"tcp\", nil, &net.TCPAddr{IP: ip, Port: 443})\n\t\tif err != nil {\n\t\t\treturn newError(\"dial tcp\").Base(err)\n\t\t}\n\t\ttlsConn := tls.Client(tcpConn, &tls.Config{\n\t\t\tServerName: domain,\n\t\t\tNextProtos: []string{\"http/1.1\"},\n\t\t\tMaxVersion: tls.VersionTLS12,\n\t\t\tMinVersion: tls.VersionTLS12,\n\t\t})\n\t\terr = tlsConn.Handshake()\n\t\tif err != nil {\n\t\t\tfmt.Println(\"handshake failure: \", err)\n\t\t} else {\n\t\t\tfmt.Println(\"handshake succeeded\")\n\t\t\tprintCertificates(tlsConn.ConnectionState().PeerCertificates)\n\t\t}\n\t\ttlsConn.Close()\n\t}\n\n\tfmt.Println(\"Tls ping finished\")\n\n\treturn nil\n}\n\nfunc init() {\n\tcommon.Must(RegisterCommand(&TlsPingCommand{}))\n}\n"
  },
  {
    "path": "infra/control/uuid.go",
    "content": "package control\n\nimport (\n\t\"fmt\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/uuid\"\n)\n\ntype UUIDCommand struct{}\n\nfunc (c *UUIDCommand) Name() string {\n\treturn \"uuid\"\n}\n\nfunc (c *UUIDCommand) Description() Description {\n\treturn Description{\n\t\tShort: \"Generate new UUIDs\",\n\t\tUsage: []string{\"v2ctl uuid\"},\n\t}\n}\n\nfunc (c *UUIDCommand) Execute([]string) error {\n\tu := uuid.New()\n\tfmt.Println(u.String())\n\treturn nil\n}\n\nfunc init() {\n\tcommon.Must(RegisterCommand(&UUIDCommand{}))\n}\n"
  },
  {
    "path": "infra/control/verify.go",
    "content": "package control\n\nimport (\n\t\"flag\"\n\t\"github.com/xiaokangwang/VSign/signerVerify\"\n\t\"os\"\n\t\"v2ray.com/core/common\"\n)\n\ntype VerifyCommand struct{}\n\nfunc (c *VerifyCommand) Name() string {\n\treturn \"verify\"\n}\n\nfunc (c *VerifyCommand) Description() Description {\n\treturn Description{\n\t\tShort: \"Verify if a binary is officially signed.\",\n\t\tUsage: []string{\n\t\t\t\"v2ctl verify --sig=<sig-file> file...\",\n\t\t\t\"Verify the file officially signed by V2Ray.\",\n\t\t},\n\t}\n}\n\nfunc (c *VerifyCommand) Execute(args []string) error {\n\tfs := flag.NewFlagSet(c.Name(), flag.ContinueOnError)\n\n\tsigFile := fs.String(\"sig\", \"\", \"Path to the signature file\")\n\n\tif err := fs.Parse(args); err != nil {\n\t\treturn err\n\t}\n\n\ttarget := fs.Arg(0)\n\tif target == \"\" {\n\t\treturn newError(\"empty file path.\")\n\t}\n\n\tif *sigFile == \"\" {\n\t\treturn newError(\"empty signature path.\")\n\t}\n\n\tsigReader, err := os.Open(os.ExpandEnv(*sigFile))\n\tif err != nil {\n\t\treturn newError(\"failed to open file \", *sigFile).Base(err)\n\t}\n\n\tfiles := fs.Args()\n\n\terr = signerVerify.OutputAndJudge(signerVerify.CheckSignaturesV2Fly(sigReader, files))\n\n\tif err == nil {\n\t\treturn nil\n\t}\n\n\treturn newError(\"file is not officially signed by V2Ray\").Base(err)\n}\n\nfunc init() {\n\tcommon.Must(RegisterCommand(&VerifyCommand{}))\n}\n"
  },
  {
    "path": "infra/vprotogen/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strings\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/common\"\n)\n\nfunc main() {\n\tpwd, wdErr := os.Getwd()\n\tif wdErr != nil {\n\t\tfmt.Println(\"Can not get current working directory.\")\n\t\tos.Exit(1)\n\t}\n\n\tGOBIN := common.GetGOBIN()\n\tprotoc := core.ProtocMap[runtime.GOOS]\n\n\tprotoFilesMap := make(map[string][]string)\n\twalkErr := filepath.Walk(\"./\", func(path string, info os.FileInfo, err error) error {\n\t\tif err != nil {\n\t\t\tfmt.Println(err)\n\t\t\treturn err\n\t\t}\n\n\t\tif info.IsDir() {\n\t\t\treturn nil\n\t\t}\n\n\t\tdir := filepath.Dir(path)\n\t\tfilename := filepath.Base(path)\n\t\tif strings.HasSuffix(filename, \".proto\") {\n\t\t\tprotoFilesMap[dir] = append(protoFilesMap[dir], path)\n\t\t}\n\n\t\treturn nil\n\t})\n\tif walkErr != nil {\n\t\tfmt.Println(walkErr)\n\t\tos.Exit(1)\n\t}\n\n\tfor _, files := range protoFilesMap {\n\t\tfor _, relProtoFile := range files {\n\t\t\tvar args []string\n\t\t\tif core.ProtoFilesUsingProtocGenGoFast[relProtoFile] {\n\t\t\t\targs = []string{\"--gofast_out\", pwd, \"--plugin\", \"protoc-gen-gofast=\" + GOBIN + \"/protoc-gen-gofast\"}\n\t\t\t} else {\n\t\t\t\targs = []string{\"--go_out\", pwd, \"--go-grpc_out\", pwd, \"--plugin\", \"protoc-gen-go=\" + GOBIN + \"/protoc-gen-go\", \"--plugin\", \"protoc-gen-go-grpc=\" + GOBIN + \"/protoc-gen-go-grpc\"}\n\t\t\t}\n\t\t\targs = append(args, relProtoFile)\n\t\t\tcmd := exec.Command(protoc, args...)\n\t\t\tcmd.Env = append(cmd.Env, os.Environ()...)\n\t\t\tcmd.Env = append(cmd.Env, \"GOBIN=\"+GOBIN)\n\t\t\toutput, cmdErr := cmd.CombinedOutput()\n\t\t\tif len(output) > 0 {\n\t\t\t\tfmt.Println(string(output))\n\t\t\t}\n\t\t\tif cmdErr != nil {\n\t\t\t\tfmt.Println(cmdErr)\n\t\t\t\tos.Exit(1)\n\t\t\t}\n\t\t}\n\t}\n\n\tmoduleName, gmnErr := common.GetModuleName(pwd)\n\tif gmnErr != nil {\n\t\tfmt.Println(gmnErr)\n\t\tos.Exit(1)\n\t}\n\tmodulePath := filepath.Join(strings.Split(moduleName, \"/\")...)\n\n\tpbGoFilesMap := make(map[string][]string)\n\twalkErr2 := filepath.Walk(modulePath, func(path string, info os.FileInfo, err error) error {\n\t\tif err != nil {\n\t\t\tfmt.Println(err)\n\t\t\treturn err\n\t\t}\n\n\t\tif info.IsDir() {\n\t\t\treturn nil\n\t\t}\n\n\t\tdir := filepath.Dir(path)\n\t\tfilename := filepath.Base(path)\n\t\tif strings.HasSuffix(filename, \".pb.go\") {\n\t\t\tpbGoFilesMap[dir] = append(pbGoFilesMap[dir], path)\n\t\t}\n\n\t\treturn nil\n\t})\n\tif walkErr2 != nil {\n\t\tfmt.Println(walkErr2)\n\t\tos.Exit(1)\n\t}\n\n\tvar err error\n\tfor _, srcPbGoFiles := range pbGoFilesMap {\n\t\tfor _, srcPbGoFile := range srcPbGoFiles {\n\t\t\tvar dstPbGoFile string\n\t\t\tdstPbGoFile, err = filepath.Rel(modulePath, srcPbGoFile)\n\t\t\tif err != nil {\n\t\t\t\tfmt.Println(err)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\terr = os.Link(srcPbGoFile, dstPbGoFile)\n\t\t\tif err != nil {\n\t\t\t\tif os.IsNotExist(err) {\n\t\t\t\t\tfmt.Printf(\"'%s' does not exist\\n\", srcPbGoFile)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif os.IsPermission(err) {\n\t\t\t\t\tfmt.Println(err)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif os.IsExist(err) {\n\t\t\t\t\terr = os.Remove(dstPbGoFile)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tfmt.Printf(\"Failed to delete file '%s'\\n\", dstPbGoFile)\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\terr = os.Rename(srcPbGoFile, dstPbGoFile)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tfmt.Printf(\"Can not move '%s' to '%s'\\n\", srcPbGoFile, dstPbGoFile)\n\t\t\t\t\t}\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\t\t\terr = os.Rename(srcPbGoFile, dstPbGoFile)\n\t\t\tif err != nil {\n\t\t\t\tfmt.Printf(\"Can not move '%s' to '%s'\\n\", srcPbGoFile, dstPbGoFile)\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t}\n\n\tif err == nil {\n\t\terr = os.RemoveAll(strings.Split(modulePath, \"/\")[0])\n\t\tif err != nil {\n\t\t\tfmt.Println(err)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "main/BUILD",
    "content": "load(\"//infra/bazel:matrix.bzl\", \"SUPPORTED_MATRIX\")\nload(\"//main:targets.bzl\", \"gen_targets\")\n\npackage(default_visibility=[\"//visibility:public\"])\n\ngen_targets(SUPPORTED_MATRIX)\n"
  },
  {
    "path": "main/confloader/confloader.go",
    "content": "package confloader\n\nimport (\n\t\"io\"\n\t\"os\"\n)\n\ntype configFileLoader func(string) (io.Reader, error)\ntype extconfigLoader func([]string) (io.Reader, error)\n\nvar (\n\tEffectiveConfigFileLoader configFileLoader\n\tEffectiveExtConfigLoader  extconfigLoader\n)\n\n// LoadConfig reads from a path/url/stdin\n// actual work is in external module\nfunc LoadConfig(file string) (io.Reader, error) {\n\tif EffectiveConfigFileLoader == nil {\n\t\tnewError(\"external config module not loaded, reading from stdin\").AtInfo().WriteToLog()\n\t\treturn os.Stdin, nil\n\t}\n\treturn EffectiveConfigFileLoader(file)\n}\n\n// LoadExtConfig calls v2ctl to handle multiple config\n// the actual work also in external module\nfunc LoadExtConfig(files []string) (io.Reader, error) {\n\tif EffectiveExtConfigLoader == nil {\n\t\treturn nil, newError(\"external config module not loaded\").AtError()\n\t}\n\n\treturn EffectiveExtConfigLoader(files)\n}\n"
  },
  {
    "path": "main/confloader/errors.generated.go",
    "content": "package confloader\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "main/confloader/external/errors.generated.go",
    "content": "package external\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "main/confloader/external/external.go",
    "content": "package external\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n\nimport (\n\t\"bytes\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/platform/ctlcmd\"\n\t\"v2ray.com/core/main/confloader\"\n)\n\nfunc ConfigLoader(arg string) (out io.Reader, err error) {\n\n\tvar data []byte\n\tif strings.HasPrefix(arg, \"http://\") || strings.HasPrefix(arg, \"https://\") {\n\t\tdata, err = FetchHTTPContent(arg)\n\t} else if arg == \"stdin:\" {\n\t\tdata, err = ioutil.ReadAll(os.Stdin)\n\t} else {\n\t\tdata, err = ioutil.ReadFile(arg)\n\t}\n\n\tif err != nil {\n\t\treturn\n\t}\n\tout = bytes.NewBuffer(data)\n\treturn\n}\n\nfunc FetchHTTPContent(target string) ([]byte, error) {\n\n\tparsedTarget, err := url.Parse(target)\n\tif err != nil {\n\t\treturn nil, newError(\"invalid URL: \", target).Base(err)\n\t}\n\n\tif s := strings.ToLower(parsedTarget.Scheme); s != \"http\" && s != \"https\" {\n\t\treturn nil, newError(\"invalid scheme: \", parsedTarget.Scheme)\n\t}\n\n\tclient := &http.Client{\n\t\tTimeout: 30 * time.Second,\n\t}\n\tresp, err := client.Do(&http.Request{\n\t\tMethod: \"GET\",\n\t\tURL:    parsedTarget,\n\t\tClose:  true,\n\t})\n\tif err != nil {\n\t\treturn nil, newError(\"failed to dial to \", target).Base(err)\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != 200 {\n\t\treturn nil, newError(\"unexpected HTTP status code: \", resp.StatusCode)\n\t}\n\n\tcontent, err := buf.ReadAllToBytes(resp.Body)\n\tif err != nil {\n\t\treturn nil, newError(\"failed to read HTTP response\").Base(err)\n\t}\n\n\treturn content, nil\n}\n\nfunc ExtConfigLoader(files []string) (io.Reader, error) {\n\tbuf, err := ctlcmd.Run(append([]string{\"config\"}, files...), os.Stdin)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn strings.NewReader(buf.String()), nil\n}\n\nfunc init() {\n\tconfloader.EffectiveConfigFileLoader = ConfigLoader\n\tconfloader.EffectiveExtConfigLoader = ExtConfigLoader\n}\n"
  },
  {
    "path": "main/distro/all/all.go",
    "content": "package all\n\nimport (\n\t// The following are necessary as they register handlers in their init functions.\n\n\t// Required features. Can't remove unless there is replacements.\n\t_ \"v2ray.com/core/app/dispatcher\"\n\t_ \"v2ray.com/core/app/proxyman/inbound\"\n\t_ \"v2ray.com/core/app/proxyman/outbound\"\n\n\t// Default commander and all its services. This is an optional feature.\n\t_ \"v2ray.com/core/app/commander\"\n\t_ \"v2ray.com/core/app/log/command\"\n\t_ \"v2ray.com/core/app/proxyman/command\"\n\t_ \"v2ray.com/core/app/stats/command\"\n\n\t// Other optional features.\n\t_ \"v2ray.com/core/app/dns\"\n\t_ \"v2ray.com/core/app/log\"\n\t_ \"v2ray.com/core/app/policy\"\n\t_ \"v2ray.com/core/app/reverse\"\n\t_ \"v2ray.com/core/app/router\"\n\t_ \"v2ray.com/core/app/stats\"\n\n\t// Inbound and outbound proxies.\n\t_ \"v2ray.com/core/proxy/blackhole\"\n\t_ \"v2ray.com/core/proxy/dns\"\n\t_ \"v2ray.com/core/proxy/dokodemo\"\n\t_ \"v2ray.com/core/proxy/freedom\"\n\t_ \"v2ray.com/core/proxy/http\"\n\t_ \"v2ray.com/core/proxy/mtproto\"\n\t_ \"v2ray.com/core/proxy/shadowsocks\"\n\t_ \"v2ray.com/core/proxy/socks\"\n\t_ \"v2ray.com/core/proxy/trojan\"\n\t_ \"v2ray.com/core/proxy/vless/inbound\"\n\t_ \"v2ray.com/core/proxy/vless/outbound\"\n\t_ \"v2ray.com/core/proxy/vmess/inbound\"\n\t_ \"v2ray.com/core/proxy/vmess/outbound\"\n\n\t// Transports\n\t_ \"v2ray.com/core/transport/internet/domainsocket\"\n\t_ \"v2ray.com/core/transport/internet/http\"\n\t_ \"v2ray.com/core/transport/internet/kcp\"\n\t_ \"v2ray.com/core/transport/internet/quic\"\n\t_ \"v2ray.com/core/transport/internet/tcp\"\n\t_ \"v2ray.com/core/transport/internet/tls\"\n\t_ \"v2ray.com/core/transport/internet/udp\"\n\t_ \"v2ray.com/core/transport/internet/websocket\"\n\t_ \"v2ray.com/core/transport/internet/xtls\"\n\n\t// Transport headers\n\t_ \"v2ray.com/core/transport/internet/headers/http\"\n\t_ \"v2ray.com/core/transport/internet/headers/noop\"\n\t_ \"v2ray.com/core/transport/internet/headers/srtp\"\n\t_ \"v2ray.com/core/transport/internet/headers/tls\"\n\t_ \"v2ray.com/core/transport/internet/headers/utp\"\n\t_ \"v2ray.com/core/transport/internet/headers/wechat\"\n\t_ \"v2ray.com/core/transport/internet/headers/wireguard\"\n\n\t// JSON config support. Choose only one from the two below.\n\t// The following line loads JSON from v2ctl\n\t_ \"v2ray.com/core/main/json\"\n\t// The following line loads JSON internally\n\t// _ \"v2ray.com/core/main/jsonem\"\n\n\t// Load config from file or http(s)\n\t_ \"v2ray.com/core/main/confloader/external\"\n)\n"
  },
  {
    "path": "main/distro/debug/debug.go",
    "content": "package debug\n\nimport _ \"net/http/pprof\"\nimport \"net/http\"\n\nfunc init() {\n\tgo func() {\n\t\thttp.ListenAndServe(\":6060\", nil)\n\t}()\n}\n"
  },
  {
    "path": "main/errors.generated.go",
    "content": "package main\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "main/json/config_json.go",
    "content": "package json\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n\nimport (\n\t\"io\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/cmdarg\"\n\t\"v2ray.com/core/infra/conf/serial\"\n\t\"v2ray.com/core/main/confloader\"\n)\n\nfunc init() {\n\tcommon.Must(core.RegisterConfigLoader(&core.ConfigFormat{\n\t\tName:      \"JSON\",\n\t\tExtension: []string{\"json\"},\n\t\tLoader: func(input interface{}) (*core.Config, error) {\n\t\t\tswitch v := input.(type) {\n\t\t\tcase cmdarg.Arg:\n\t\t\t\tr, err := confloader.LoadExtConfig(v)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, newError(\"failed to execute v2ctl to convert config file.\").Base(err).AtWarning()\n\t\t\t\t}\n\t\t\t\treturn core.LoadConfig(\"protobuf\", \"\", r)\n\t\t\tcase io.Reader:\n\t\t\t\treturn serial.LoadJSONConfig(v)\n\t\t\tdefault:\n\t\t\t\treturn nil, newError(\"unknow type\")\n\t\t\t}\n\t\t},\n\t}))\n}\n"
  },
  {
    "path": "main/json/errors.generated.go",
    "content": "package json\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "main/jsonem/errors.generated.go",
    "content": "package jsonem\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "main/jsonem/jsonem.go",
    "content": "package jsonem\n\nimport (\n\t\"io\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/cmdarg\"\n\t\"v2ray.com/core/infra/conf\"\n\t\"v2ray.com/core/infra/conf/serial\"\n\t\"v2ray.com/core/main/confloader\"\n)\n\nfunc init() {\n\tcommon.Must(core.RegisterConfigLoader(&core.ConfigFormat{\n\t\tName:      \"JSON\",\n\t\tExtension: []string{\"json\"},\n\t\tLoader: func(input interface{}) (*core.Config, error) {\n\t\t\tswitch v := input.(type) {\n\t\t\tcase cmdarg.Arg:\n\t\t\t\tcf := &conf.Config{}\n\t\t\t\tfor _, arg := range v {\n\t\t\t\t\tnewError(\"Reading config: \", arg).AtInfo().WriteToLog()\n\t\t\t\t\tr, err := confloader.LoadConfig(arg)\n\t\t\t\t\tcommon.Must(err)\n\t\t\t\t\tc, err := serial.DecodeJSONConfig(r)\n\t\t\t\t\tcommon.Must(err)\n\t\t\t\t\tcf.Override(c, arg)\n\t\t\t\t}\n\t\t\t\treturn cf.Build()\n\t\t\tcase io.Reader:\n\t\t\t\treturn serial.LoadJSONConfig(v)\n\t\t\tdefault:\n\t\t\t\treturn nil, newError(\"unknow type\")\n\t\t\t}\n\t\t},\n\t}))\n}\n"
  },
  {
    "path": "main/main.go",
    "content": "package main\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"os\"\n\t\"os/signal\"\n\t\"path\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strings\"\n\t\"syscall\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/common/cmdarg\"\n\t\"v2ray.com/core/common/platform\"\n\t_ \"v2ray.com/core/main/distro/all\"\n)\n\nvar (\n\tconfigFiles cmdarg.Arg // \"Config file for V2Ray.\", the option is customed type, parse in main\n\tconfigDir   string\n\tversion     = flag.Bool(\"version\", false, \"Show current version of V2Ray.\")\n\ttest        = flag.Bool(\"test\", false, \"Test config file only, without launching V2Ray server.\")\n\tformat      = flag.String(\"format\", \"json\", \"Format of input file.\")\n\n\t/* We have to do this here because Golang's Test will also need to parse flag, before\n\t * main func in this file is run.\n\t */\n\t_ = func() error {\n\n\t\tflag.Var(&configFiles, \"config\", \"Config file for V2Ray. Multiple assign is accepted (only json). Latter ones overrides the former ones.\")\n\t\tflag.Var(&configFiles, \"c\", \"Short alias of -config\")\n\t\tflag.StringVar(&configDir, \"confdir\", \"\", \"A dir with multiple json config\")\n\n\t\treturn nil\n\t}()\n)\n\nfunc fileExists(file string) bool {\n\tinfo, err := os.Stat(file)\n\treturn err == nil && !info.IsDir()\n}\n\nfunc dirExists(file string) bool {\n\tif file == \"\" {\n\t\treturn false\n\t}\n\tinfo, err := os.Stat(file)\n\treturn err == nil && info.IsDir()\n}\n\nfunc readConfDir(dirPath string) {\n\tconfs, err := ioutil.ReadDir(dirPath)\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\tfor _, f := range confs {\n\t\tif strings.HasSuffix(f.Name(), \".json\") {\n\t\t\tconfigFiles.Set(path.Join(dirPath, f.Name()))\n\t\t}\n\t}\n}\n\nfunc getConfigFilePath() (cmdarg.Arg, error) {\n\tif dirExists(configDir) {\n\t\tlog.Println(\"Using confdir from arg:\", configDir)\n\t\treadConfDir(configDir)\n\t} else {\n\t\tif envConfDir := platform.GetConfDirPath(); dirExists(envConfDir) {\n\t\t\tlog.Println(\"Using confdir from env:\", envConfDir)\n\t\t\treadConfDir(envConfDir)\n\t\t}\n\t}\n\n\tif len(configFiles) > 0 {\n\t\treturn configFiles, nil\n\t}\n\n\tif workingDir, err := os.Getwd(); err == nil {\n\t\tconfigFile := filepath.Join(workingDir, \"config.json\")\n\t\tif fileExists(configFile) {\n\t\t\tlog.Println(\"Using default config: \", configFile)\n\t\t\treturn cmdarg.Arg{configFile}, nil\n\t\t}\n\t}\n\n\tif configFile := platform.GetConfigurationPath(); fileExists(configFile) {\n\t\tlog.Println(\"Using config from env: \", configFile)\n\t\treturn cmdarg.Arg{configFile}, nil\n\t}\n\n\tlog.Println(\"Using config from STDIN\")\n\treturn cmdarg.Arg{\"stdin:\"}, nil\n}\n\nfunc GetConfigFormat() string {\n\tswitch strings.ToLower(*format) {\n\tcase \"pb\", \"protobuf\":\n\t\treturn \"protobuf\"\n\tdefault:\n\t\treturn \"json\"\n\t}\n}\n\nfunc startV2Ray() (core.Server, error) {\n\tconfigFiles, err := getConfigFilePath()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tconfig, err := core.LoadConfig(GetConfigFormat(), configFiles[0], configFiles)\n\tif err != nil {\n\t\treturn nil, newError(\"failed to read config files: [\", configFiles.String(), \"]\").Base(err)\n\t}\n\n\tserver, err := core.New(config)\n\tif err != nil {\n\t\treturn nil, newError(\"failed to create server\").Base(err)\n\t}\n\n\treturn server, nil\n}\n\nfunc printVersion() {\n\tversion := core.VersionStatement()\n\tfor _, s := range version {\n\t\tfmt.Println(s)\n\t}\n}\n\nfunc main() {\n\n\tflag.Parse()\n\n\tprintVersion()\n\n\tif *version {\n\t\treturn\n\t}\n\n\tserver, err := startV2Ray()\n\tif err != nil {\n\t\tfmt.Println(err)\n\t\t// Configuration error. Exit with a special value to prevent systemd from restarting.\n\t\tos.Exit(23)\n\t}\n\n\tif *test {\n\t\tfmt.Println(\"Configuration OK.\")\n\t\tos.Exit(0)\n\t}\n\n\tif err := server.Start(); err != nil {\n\t\tfmt.Println(\"Failed to start\", err)\n\t\tos.Exit(-1)\n\t}\n\tdefer server.Close()\n\n\t// Explicitly triggering GC to remove garbage from config loading.\n\truntime.GC()\n\n\t{\n\t\tosSignals := make(chan os.Signal, 1)\n\t\tsignal.Notify(osSignals, os.Interrupt, syscall.SIGTERM)\n\t\t<-osSignals\n\t}\n}\n"
  },
  {
    "path": "main/main_test.go",
    "content": "// +build coveragemain\n\npackage main\n\nimport (\n\t\"testing\"\n)\n\nfunc TestRunMainForCoverage(t *testing.T) {\n\tmain()\n}\n"
  },
  {
    "path": "main/targets.bzl",
    "content": "load(\"//infra/bazel:build.bzl\", \"foreign_go_binary\")\n\ndef gen_targets(matrix):\n  pkg = \"./main\"\n  output = \"v2ray\"\n\n  for (os, arch, ver) in matrix:\n\n    if arch in [\"arm\"]:\n      bin_name = \"v2ray_\" + os + \"_\" + arch + \"_\" + ver\n      foreign_go_binary(\n        name = bin_name,\n        pkg = pkg,\n        output = output,\n        os = os,\n        arch = arch,\n        ver = ver,\n        arm = ver,\n      )\n\n      if os in [\"windows\"]:\n        bin_name = \"v2ray_\" + os + \"_\" + arch + \"_\" + ver + \"_nowindow\"\n        foreign_go_binary(\n          name = bin_name,\n          pkg = pkg,\n          output = \"w\" + output,\n          os = os,\n          arch = arch,\n          ver = ver,\n          arm = ver,\n          ld = \"-H windowsgui\",\n        )\n\n    else:\n      bin_name = \"v2ray_\" + os + \"_\" + arch\n      foreign_go_binary(\n        name = bin_name,\n        pkg = pkg,\n        output = output,\n        os = os,\n        arch = arch,\n        ver = ver,\n      )\n\n      if os in [\"windows\"]:\n        bin_name = \"v2ray_\" + os + \"_\" + arch + \"_nowindow\"\n        foreign_go_binary(\n          name = bin_name,\n          pkg = pkg,\n          output = \"w\" + output,\n          os = os,\n          arch = arch,\n          ver = ver,\n          ld = \"-H windowsgui\",\n        )\n\n      if arch in [\"mips\", \"mipsle\"]:\n        bin_name = \"v2ray_\" + os + \"_\" + arch + \"_softfloat\"\n        foreign_go_binary(\n          name = bin_name,\n          pkg = pkg,\n          output = output + \"_softfloat\",\n          os = os,\n          arch = arch,\n          ver = ver,\n          mips = \"softfloat\",\n        )\n"
  },
  {
    "path": "mocks.go",
    "content": "package core\n\n//go:generate go run github.com/golang/mock/mockgen -package mocks -destination testing/mocks/io.go -mock_names Reader=Reader,Writer=Writer io Reader,Writer\n//go:generate go run github.com/golang/mock/mockgen -package mocks -destination testing/mocks/log.go -mock_names Handler=LogHandler v2ray.com/core/common/log Handler\n//go:generate go run github.com/golang/mock/mockgen -package mocks -destination testing/mocks/mux.go -mock_names ClientWorkerFactory=MuxClientWorkerFactory v2ray.com/core/common/mux ClientWorkerFactory\n//go:generate go run github.com/golang/mock/mockgen -package mocks -destination testing/mocks/dns.go -mock_names Client=DNSClient v2ray.com/core/features/dns Client\n//go:generate go run github.com/golang/mock/mockgen -package mocks -destination testing/mocks/outbound.go -mock_names Manager=OutboundManager,HandlerSelector=OutboundHandlerSelector v2ray.com/core/features/outbound Manager,HandlerSelector\n//go:generate go run github.com/golang/mock/mockgen -package mocks -destination testing/mocks/proxy.go -mock_names Inbound=ProxyInbound,Outbound=ProxyOutbound v2ray.com/core/proxy Inbound,Outbound\n"
  },
  {
    "path": "proto.go",
    "content": "package core\n\n//go:generate go install -v google.golang.org/protobuf/cmd/protoc-gen-go\n//go:generate go install -v google.golang.org/grpc/cmd/protoc-gen-go-grpc\n//go:generate go install -v github.com/gogo/protobuf/protoc-gen-gofast\n//go:generate go run ./infra/vprotogen/main.go\n\nimport \"path/filepath\"\n\n// ProtoFilesUsingProtocGenGoFast is the map of Proto files\n// that use `protoc-gen-gofast` to generate pb.go files\nvar ProtoFilesUsingProtocGenGoFast = map[string]bool{\"proxy/vless/encoding/addons.proto\": true}\n\n// ProtocMap is the map of paths to `protoc` binary excutable files of specific platform\nvar ProtocMap = map[string]string{\n\t\"windows\": filepath.Join(\".dev\", \"protoc\", \"windows\", \"protoc.exe\"),\n\t\"darwin\":  filepath.Join(\".dev\", \"protoc\", \"macos\", \"protoc\"),\n\t\"linux\":   filepath.Join(\".dev\", \"protoc\", \"linux\", \"protoc\"),\n}\n"
  },
  {
    "path": "proxy/blackhole/blackhole.go",
    "content": "// +build !confonly\n\n// Package blackhole is an outbound handler that blocks all connections.\n\npackage blackhole\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/transport\"\n\t\"v2ray.com/core/transport/internet\"\n)\n\n// Handler is an outbound connection that silently swallow the entire payload.\ntype Handler struct {\n\tresponse ResponseConfig\n}\n\n// New creates a new blackhole handler.\nfunc New(ctx context.Context, config *Config) (*Handler, error) {\n\tresponse, err := config.GetInternalResponse()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &Handler{\n\t\tresponse: response,\n\t}, nil\n}\n\n// Process implements OutboundHandler.Dispatch().\nfunc (h *Handler) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {\n\tnBytes := h.response.WriteTo(link.Writer)\n\tif nBytes > 0 {\n\t\t// Sleep a little here to make sure the response is sent to client.\n\t\ttime.Sleep(time.Second)\n\t}\n\tcommon.Interrupt(link.Writer)\n\treturn nil\n}\n\nfunc init() {\n\tcommon.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {\n\t\treturn New(ctx, config.(*Config))\n\t}))\n}\n"
  },
  {
    "path": "proxy/blackhole/blackhole_test.go",
    "content": "package blackhole_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/serial\"\n\t\"v2ray.com/core/proxy/blackhole\"\n\t\"v2ray.com/core/transport\"\n\t\"v2ray.com/core/transport/pipe\"\n)\n\nfunc TestBlackholeHTTPResponse(t *testing.T) {\n\thandler, err := blackhole.New(context.Background(), &blackhole.Config{\n\t\tResponse: serial.ToTypedMessage(&blackhole.HTTPResponse{}),\n\t})\n\tcommon.Must(err)\n\n\treader, writer := pipe.New(pipe.WithoutSizeLimit())\n\n\tvar mb buf.MultiBuffer\n\tvar rerr error\n\tgo func() {\n\t\tb, e := reader.ReadMultiBuffer()\n\t\tmb = b\n\t\trerr = e\n\t}()\n\n\tlink := transport.Link{\n\t\tReader: reader,\n\t\tWriter: writer,\n\t}\n\tcommon.Must(handler.Process(context.Background(), &link, nil))\n\tcommon.Must(rerr)\n\tif mb.IsEmpty() {\n\t\tt.Error(\"expect http response, but nothing\")\n\t}\n}\n"
  },
  {
    "path": "proxy/blackhole/config.go",
    "content": "package blackhole\n\nimport (\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n)\n\nconst (\n\thttp403response = `HTTP/1.1 403 Forbidden\nConnection: close\nCache-Control: max-age=3600, public\nContent-Length: 0\n\n\n`\n)\n\n// ResponseConfig is the configuration for blackhole responses.\ntype ResponseConfig interface {\n\t// WriteTo writes predefined response to the give buffer.\n\tWriteTo(buf.Writer) int32\n}\n\n// WriteTo implements ResponseConfig.WriteTo().\nfunc (*NoneResponse) WriteTo(buf.Writer) int32 { return 0 }\n\n// WriteTo implements ResponseConfig.WriteTo().\nfunc (*HTTPResponse) WriteTo(writer buf.Writer) int32 {\n\tb := buf.New()\n\tcommon.Must2(b.WriteString(http403response))\n\tn := b.Len()\n\twriter.WriteMultiBuffer(buf.MultiBuffer{b})\n\treturn n\n}\n\n// GetInternalResponse converts response settings from proto to internal data structure.\nfunc (c *Config) GetInternalResponse() (ResponseConfig, error) {\n\tif c.GetResponse() == nil {\n\t\treturn new(NoneResponse), nil\n\t}\n\n\tconfig, err := c.GetResponse().GetInstance()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn config.(ResponseConfig), nil\n}\n"
  },
  {
    "path": "proxy/blackhole/config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: proxy/blackhole/config.proto\n\npackage blackhole\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n\tserial \"v2ray.com/core/common/serial\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype NoneResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *NoneResponse) Reset() {\n\t*x = NoneResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_proxy_blackhole_config_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *NoneResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*NoneResponse) ProtoMessage() {}\n\nfunc (x *NoneResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_proxy_blackhole_config_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use NoneResponse.ProtoReflect.Descriptor instead.\nfunc (*NoneResponse) Descriptor() ([]byte, []int) {\n\treturn file_proxy_blackhole_config_proto_rawDescGZIP(), []int{0}\n}\n\ntype HTTPResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *HTTPResponse) Reset() {\n\t*x = HTTPResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_proxy_blackhole_config_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *HTTPResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*HTTPResponse) ProtoMessage() {}\n\nfunc (x *HTTPResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_proxy_blackhole_config_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use HTTPResponse.ProtoReflect.Descriptor instead.\nfunc (*HTTPResponse) Descriptor() ([]byte, []int) {\n\treturn file_proxy_blackhole_config_proto_rawDescGZIP(), []int{1}\n}\n\ntype Config struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tResponse *serial.TypedMessage `protobuf:\"bytes,1,opt,name=response,proto3\" json:\"response,omitempty\"`\n}\n\nfunc (x *Config) Reset() {\n\t*x = Config{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_proxy_blackhole_config_proto_msgTypes[2]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Config) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Config) ProtoMessage() {}\n\nfunc (x *Config) ProtoReflect() protoreflect.Message {\n\tmi := &file_proxy_blackhole_config_proto_msgTypes[2]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Config.ProtoReflect.Descriptor instead.\nfunc (*Config) Descriptor() ([]byte, []int) {\n\treturn file_proxy_blackhole_config_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *Config) GetResponse() *serial.TypedMessage {\n\tif x != nil {\n\t\treturn x.Response\n\t}\n\treturn nil\n}\n\nvar File_proxy_blackhole_config_proto protoreflect.FileDescriptor\n\nvar file_proxy_blackhole_config_proto_rawDesc = []byte{\n\t0x0a, 0x1c, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x62, 0x6c, 0x61, 0x63, 0x6b, 0x68, 0x6f, 0x6c,\n\t0x65, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1a,\n\t0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79,\n\t0x2e, 0x62, 0x6c, 0x61, 0x63, 0x6b, 0x68, 0x6f, 0x6c, 0x65, 0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d,\n\t0x6f, 0x6e, 0x2f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x64, 0x5f,\n\t0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x0e, 0x0a,\n\t0x0c, 0x4e, 0x6f, 0x6e, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x0e, 0x0a,\n\t0x0c, 0x48, 0x54, 0x54, 0x50, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4c, 0x0a,\n\t0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x42, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f,\n\t0x6e, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x76, 0x32, 0x72, 0x61,\n\t0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65,\n\t0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,\n\t0x65, 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x5f, 0x0a, 0x1e, 0x63,\n\t0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72,\n\t0x6f, 0x78, 0x79, 0x2e, 0x62, 0x6c, 0x61, 0x63, 0x6b, 0x68, 0x6f, 0x6c, 0x65, 0x50, 0x01, 0x5a,\n\t0x1e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f,\n\t0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x62, 0x6c, 0x61, 0x63, 0x6b, 0x68, 0x6f, 0x6c, 0x65, 0xaa,\n\t0x02, 0x1a, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x50, 0x72, 0x6f,\n\t0x78, 0x79, 0x2e, 0x42, 0x6c, 0x61, 0x63, 0x6b, 0x68, 0x6f, 0x6c, 0x65, 0x62, 0x06, 0x70, 0x72,\n\t0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_proxy_blackhole_config_proto_rawDescOnce sync.Once\n\tfile_proxy_blackhole_config_proto_rawDescData = file_proxy_blackhole_config_proto_rawDesc\n)\n\nfunc file_proxy_blackhole_config_proto_rawDescGZIP() []byte {\n\tfile_proxy_blackhole_config_proto_rawDescOnce.Do(func() {\n\t\tfile_proxy_blackhole_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_proxy_blackhole_config_proto_rawDescData)\n\t})\n\treturn file_proxy_blackhole_config_proto_rawDescData\n}\n\nvar file_proxy_blackhole_config_proto_msgTypes = make([]protoimpl.MessageInfo, 3)\nvar file_proxy_blackhole_config_proto_goTypes = []interface{}{\n\t(*NoneResponse)(nil),        // 0: v2ray.core.proxy.blackhole.NoneResponse\n\t(*HTTPResponse)(nil),        // 1: v2ray.core.proxy.blackhole.HTTPResponse\n\t(*Config)(nil),              // 2: v2ray.core.proxy.blackhole.Config\n\t(*serial.TypedMessage)(nil), // 3: v2ray.core.common.serial.TypedMessage\n}\nvar file_proxy_blackhole_config_proto_depIdxs = []int32{\n\t3, // 0: v2ray.core.proxy.blackhole.Config.response:type_name -> v2ray.core.common.serial.TypedMessage\n\t1, // [1:1] is the sub-list for method output_type\n\t1, // [1:1] is the sub-list for method input_type\n\t1, // [1:1] is the sub-list for extension type_name\n\t1, // [1:1] is the sub-list for extension extendee\n\t0, // [0:1] is the sub-list for field type_name\n}\n\nfunc init() { file_proxy_blackhole_config_proto_init() }\nfunc file_proxy_blackhole_config_proto_init() {\n\tif File_proxy_blackhole_config_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_proxy_blackhole_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*NoneResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_proxy_blackhole_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*HTTPResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_proxy_blackhole_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Config); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_proxy_blackhole_config_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   3,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_proxy_blackhole_config_proto_goTypes,\n\t\tDependencyIndexes: file_proxy_blackhole_config_proto_depIdxs,\n\t\tMessageInfos:      file_proxy_blackhole_config_proto_msgTypes,\n\t}.Build()\n\tFile_proxy_blackhole_config_proto = out.File\n\tfile_proxy_blackhole_config_proto_rawDesc = nil\n\tfile_proxy_blackhole_config_proto_goTypes = nil\n\tfile_proxy_blackhole_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "proxy/blackhole/config.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.proxy.blackhole;\noption csharp_namespace = \"V2Ray.Core.Proxy.Blackhole\";\noption go_package = \"v2ray.com/core/proxy/blackhole\";\noption java_package = \"com.v2ray.core.proxy.blackhole\";\noption java_multiple_files = true;\n\nimport \"common/serial/typed_message.proto\";\n\nmessage NoneResponse {}\n\nmessage HTTPResponse {}\n\nmessage Config {\n  v2ray.core.common.serial.TypedMessage response = 1;\n}\n"
  },
  {
    "path": "proxy/blackhole/config_test.go",
    "content": "package blackhole_test\n\nimport (\n\t\"bufio\"\n\t\"net/http\"\n\t\"testing\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t. \"v2ray.com/core/proxy/blackhole\"\n)\n\nfunc TestHTTPResponse(t *testing.T) {\n\tbuffer := buf.New()\n\n\thttpResponse := new(HTTPResponse)\n\thttpResponse.WriteTo(buf.NewWriter(buffer))\n\n\treader := bufio.NewReader(buffer)\n\tresponse, err := http.ReadResponse(reader, nil)\n\tcommon.Must(err)\n\tif response.StatusCode != 403 {\n\t\tt.Error(\"expected status code 403, but got \", response.StatusCode)\n\t}\n}\n"
  },
  {
    "path": "proxy/blackhole/errors.generated.go",
    "content": "package blackhole\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "proxy/dns/config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: proxy/dns/config.proto\n\npackage dns\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n\tnet \"v2ray.com/core/common/net\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype Config struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Server is the DNS server address. If specified, this address overrides the\n\t// original one.\n\tServer *net.Endpoint `protobuf:\"bytes,1,opt,name=server,proto3\" json:\"server,omitempty\"`\n}\n\nfunc (x *Config) Reset() {\n\t*x = Config{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_proxy_dns_config_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Config) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Config) ProtoMessage() {}\n\nfunc (x *Config) ProtoReflect() protoreflect.Message {\n\tmi := &file_proxy_dns_config_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Config.ProtoReflect.Descriptor instead.\nfunc (*Config) Descriptor() ([]byte, []int) {\n\treturn file_proxy_dns_config_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *Config) GetServer() *net.Endpoint {\n\tif x != nil {\n\t\treturn x.Server\n\t}\n\treturn nil\n}\n\nvar File_proxy_dns_config_proto protoreflect.FileDescriptor\n\nvar file_proxy_dns_config_proto_rawDesc = []byte{\n\t0x0a, 0x16, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x64, 0x6e, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x66,\n\t0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x14, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,\n\t0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x64, 0x6e, 0x73, 0x1a, 0x1c,\n\t0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x64, 0x65, 0x73, 0x74, 0x69,\n\t0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x41, 0x0a, 0x06,\n\t0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x37, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,\n\t0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,\n\t0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x45,\n\t0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x42,\n\t0x4d, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72,\n\t0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x64, 0x6e, 0x73, 0x50, 0x01, 0x5a, 0x18, 0x76,\n\t0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72,\n\t0x6f, 0x78, 0x79, 0x2f, 0x64, 0x6e, 0x73, 0xaa, 0x02, 0x14, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e,\n\t0x43, 0x6f, 0x72, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x44, 0x6e, 0x73, 0x62, 0x06,\n\t0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_proxy_dns_config_proto_rawDescOnce sync.Once\n\tfile_proxy_dns_config_proto_rawDescData = file_proxy_dns_config_proto_rawDesc\n)\n\nfunc file_proxy_dns_config_proto_rawDescGZIP() []byte {\n\tfile_proxy_dns_config_proto_rawDescOnce.Do(func() {\n\t\tfile_proxy_dns_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_proxy_dns_config_proto_rawDescData)\n\t})\n\treturn file_proxy_dns_config_proto_rawDescData\n}\n\nvar file_proxy_dns_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)\nvar file_proxy_dns_config_proto_goTypes = []interface{}{\n\t(*Config)(nil),       // 0: v2ray.core.proxy.dns.Config\n\t(*net.Endpoint)(nil), // 1: v2ray.core.common.net.Endpoint\n}\nvar file_proxy_dns_config_proto_depIdxs = []int32{\n\t1, // 0: v2ray.core.proxy.dns.Config.server:type_name -> v2ray.core.common.net.Endpoint\n\t1, // [1:1] is the sub-list for method output_type\n\t1, // [1:1] is the sub-list for method input_type\n\t1, // [1:1] is the sub-list for extension type_name\n\t1, // [1:1] is the sub-list for extension extendee\n\t0, // [0:1] is the sub-list for field type_name\n}\n\nfunc init() { file_proxy_dns_config_proto_init() }\nfunc file_proxy_dns_config_proto_init() {\n\tif File_proxy_dns_config_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_proxy_dns_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Config); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_proxy_dns_config_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   1,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_proxy_dns_config_proto_goTypes,\n\t\tDependencyIndexes: file_proxy_dns_config_proto_depIdxs,\n\t\tMessageInfos:      file_proxy_dns_config_proto_msgTypes,\n\t}.Build()\n\tFile_proxy_dns_config_proto = out.File\n\tfile_proxy_dns_config_proto_rawDesc = nil\n\tfile_proxy_dns_config_proto_goTypes = nil\n\tfile_proxy_dns_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "proxy/dns/config.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.proxy.dns;\noption csharp_namespace = \"V2Ray.Core.Proxy.Dns\";\noption go_package = \"v2ray.com/core/proxy/dns\";\noption java_package = \"com.v2ray.core.proxy.dns\";\noption java_multiple_files = true;\n\nimport \"common/net/destination.proto\";\n\nmessage Config {\n  // Server is the DNS server address. If specified, this address overrides the\n  // original one.\n  v2ray.core.common.net.Endpoint server = 1;\n}\n"
  },
  {
    "path": "proxy/dns/dns.go",
    "content": "// +build !confonly\n\npackage dns\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"sync\"\n\n\t\"golang.org/x/net/dns/dnsmessage\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/net\"\n\tdns_proto \"v2ray.com/core/common/protocol/dns\"\n\t\"v2ray.com/core/common/session\"\n\t\"v2ray.com/core/common/task\"\n\t\"v2ray.com/core/features/dns\"\n\t\"v2ray.com/core/transport\"\n\t\"v2ray.com/core/transport/internet\"\n)\n\nfunc init() {\n\tcommon.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {\n\t\th := new(Handler)\n\t\tif err := core.RequireFeatures(ctx, func(dnsClient dns.Client) error {\n\t\t\treturn h.Init(config.(*Config), dnsClient)\n\t\t}); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn h, nil\n\t}))\n}\n\ntype ownLinkVerifier interface {\n\tIsOwnLink(ctx context.Context) bool\n}\n\ntype Handler struct {\n\tipv4Lookup      dns.IPv4Lookup\n\tipv6Lookup      dns.IPv6Lookup\n\townLinkVerifier ownLinkVerifier\n\tserver          net.Destination\n}\n\nfunc (h *Handler) Init(config *Config, dnsClient dns.Client) error {\n\tipv4lookup, ok := dnsClient.(dns.IPv4Lookup)\n\tif !ok {\n\t\treturn newError(\"dns.Client doesn't implement IPv4Lookup\")\n\t}\n\th.ipv4Lookup = ipv4lookup\n\n\tipv6lookup, ok := dnsClient.(dns.IPv6Lookup)\n\tif !ok {\n\t\treturn newError(\"dns.Client doesn't implement IPv6Lookup\")\n\t}\n\th.ipv6Lookup = ipv6lookup\n\n\tif v, ok := dnsClient.(ownLinkVerifier); ok {\n\t\th.ownLinkVerifier = v\n\t}\n\n\tif config.Server != nil {\n\t\th.server = config.Server.AsDestination()\n\t}\n\treturn nil\n}\n\nfunc (h *Handler) isOwnLink(ctx context.Context) bool {\n\treturn h.ownLinkVerifier != nil && h.ownLinkVerifier.IsOwnLink(ctx)\n}\n\nfunc parseIPQuery(b []byte) (r bool, domain string, id uint16, qType dnsmessage.Type) {\n\tvar parser dnsmessage.Parser\n\theader, err := parser.Start(b)\n\tif err != nil {\n\t\tnewError(\"parser start\").Base(err).WriteToLog()\n\t\treturn\n\t}\n\n\tid = header.ID\n\tq, err := parser.Question()\n\tif err != nil {\n\t\tnewError(\"question\").Base(err).WriteToLog()\n\t\treturn\n\t}\n\tqType = q.Type\n\tif qType != dnsmessage.TypeA && qType != dnsmessage.TypeAAAA {\n\t\treturn\n\t}\n\n\tdomain = q.Name.String()\n\tr = true\n\treturn\n}\n\n// Process implements proxy.Outbound.\nfunc (h *Handler) Process(ctx context.Context, link *transport.Link, d internet.Dialer) error {\n\toutbound := session.OutboundFromContext(ctx)\n\tif outbound == nil || !outbound.Target.IsValid() {\n\t\treturn newError(\"invalid outbound\")\n\t}\n\n\tsrcNetwork := outbound.Target.Network\n\n\tdest := outbound.Target\n\tif h.server.Network != net.Network_Unknown {\n\t\tdest.Network = h.server.Network\n\t}\n\tif h.server.Address != nil {\n\t\tdest.Address = h.server.Address\n\t}\n\tif h.server.Port != 0 {\n\t\tdest.Port = h.server.Port\n\t}\n\n\tnewError(\"handling DNS traffic to \", dest).WriteToLog(session.ExportIDToError(ctx))\n\n\tconn := &outboundConn{\n\t\tdialer: func() (internet.Connection, error) {\n\t\t\treturn d.Dial(ctx, dest)\n\t\t},\n\t\tconnReady: make(chan struct{}, 1),\n\t}\n\n\tvar reader dns_proto.MessageReader\n\tvar writer dns_proto.MessageWriter\n\tif srcNetwork == net.Network_TCP {\n\t\treader = dns_proto.NewTCPReader(link.Reader)\n\t\twriter = &dns_proto.TCPWriter{\n\t\t\tWriter: link.Writer,\n\t\t}\n\t} else {\n\t\treader = &dns_proto.UDPReader{\n\t\t\tReader: link.Reader,\n\t\t}\n\t\twriter = &dns_proto.UDPWriter{\n\t\t\tWriter: link.Writer,\n\t\t}\n\t}\n\n\tvar connReader dns_proto.MessageReader\n\tvar connWriter dns_proto.MessageWriter\n\tif dest.Network == net.Network_TCP {\n\t\tconnReader = dns_proto.NewTCPReader(buf.NewReader(conn))\n\t\tconnWriter = &dns_proto.TCPWriter{\n\t\t\tWriter: buf.NewWriter(conn),\n\t\t}\n\t} else {\n\t\tconnReader = &dns_proto.UDPReader{\n\t\t\tReader: buf.NewPacketReader(conn),\n\t\t}\n\t\tconnWriter = &dns_proto.UDPWriter{\n\t\t\tWriter: buf.NewWriter(conn),\n\t\t}\n\t}\n\n\trequest := func() error {\n\t\tdefer conn.Close()\n\n\t\tfor {\n\t\t\tb, err := reader.ReadMessage()\n\t\t\tif err == io.EOF {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif !h.isOwnLink(ctx) {\n\t\t\t\tisIPQuery, domain, id, qType := parseIPQuery(b.Bytes())\n\t\t\t\tif isIPQuery {\n\t\t\t\t\tgo h.handleIPQuery(id, qType, domain, writer)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif err := connWriter.WriteMessage(b); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\tresponse := func() error {\n\t\tfor {\n\t\t\tb, err := connReader.ReadMessage()\n\t\t\tif err == io.EOF {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif err := writer.WriteMessage(b); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\tif err := task.Run(ctx, request, response); err != nil {\n\t\treturn newError(\"connection ends\").Base(err)\n\t}\n\n\treturn nil\n}\n\nfunc (h *Handler) handleIPQuery(id uint16, qType dnsmessage.Type, domain string, writer dns_proto.MessageWriter) {\n\tvar ips []net.IP\n\tvar err error\n\n\tswitch qType {\n\tcase dnsmessage.TypeA:\n\t\tips, err = h.ipv4Lookup.LookupIPv4(domain)\n\tcase dnsmessage.TypeAAAA:\n\t\tips, err = h.ipv6Lookup.LookupIPv6(domain)\n\t}\n\n\trcode := dns.RCodeFromError(err)\n\tif rcode == 0 && len(ips) == 0 && err != dns.ErrEmptyResponse {\n\t\tnewError(\"ip query\").Base(err).WriteToLog()\n\t\treturn\n\t}\n\n\tb := buf.New()\n\trawBytes := b.Extend(buf.Size)\n\tbuilder := dnsmessage.NewBuilder(rawBytes[:0], dnsmessage.Header{\n\t\tID:                 id,\n\t\tRCode:              dnsmessage.RCode(rcode),\n\t\tRecursionAvailable: true,\n\t\tRecursionDesired:   true,\n\t\tResponse:           true,\n\t\tAuthoritative:      true,\n\t})\n\tbuilder.EnableCompression()\n\tcommon.Must(builder.StartQuestions())\n\tcommon.Must(builder.Question(dnsmessage.Question{\n\t\tName:  dnsmessage.MustNewName(domain),\n\t\tClass: dnsmessage.ClassINET,\n\t\tType:  qType,\n\t}))\n\tcommon.Must(builder.StartAnswers())\n\n\trHeader := dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName(domain), Class: dnsmessage.ClassINET, TTL: 600}\n\tfor _, ip := range ips {\n\t\tif len(ip) == net.IPv4len {\n\t\t\tvar r dnsmessage.AResource\n\t\t\tcopy(r.A[:], ip)\n\t\t\tcommon.Must(builder.AResource(rHeader, r))\n\t\t} else {\n\t\t\tvar r dnsmessage.AAAAResource\n\t\t\tcopy(r.AAAA[:], ip)\n\t\t\tcommon.Must(builder.AAAAResource(rHeader, r))\n\t\t}\n\t}\n\tmsgBytes, err := builder.Finish()\n\tif err != nil {\n\t\tnewError(\"pack message\").Base(err).WriteToLog()\n\t\tb.Release()\n\t\treturn\n\t}\n\tb.Resize(0, int32(len(msgBytes)))\n\n\tif err := writer.WriteMessage(b); err != nil {\n\t\tnewError(\"write IP answer\").Base(err).WriteToLog()\n\t}\n}\n\ntype outboundConn struct {\n\taccess sync.Mutex\n\tdialer func() (internet.Connection, error)\n\n\tconn      net.Conn\n\tconnReady chan struct{}\n}\n\nfunc (c *outboundConn) dial() error {\n\tconn, err := c.dialer()\n\tif err != nil {\n\t\treturn err\n\t}\n\tc.conn = conn\n\tc.connReady <- struct{}{}\n\treturn nil\n}\n\nfunc (c *outboundConn) Write(b []byte) (int, error) {\n\tc.access.Lock()\n\n\tif c.conn == nil {\n\t\tif err := c.dial(); err != nil {\n\t\t\tc.access.Unlock()\n\t\t\tnewError(\"failed to dial outbound connection\").Base(err).AtWarning().WriteToLog()\n\t\t\treturn len(b), nil\n\t\t}\n\t}\n\n\tc.access.Unlock()\n\n\treturn c.conn.Write(b)\n}\n\nfunc (c *outboundConn) Read(b []byte) (int, error) {\n\tvar conn net.Conn\n\tc.access.Lock()\n\tconn = c.conn\n\tc.access.Unlock()\n\n\tif conn == nil {\n\t\t_, open := <-c.connReady\n\t\tif !open {\n\t\t\treturn 0, io.EOF\n\t\t}\n\t\tconn = c.conn\n\t}\n\n\treturn conn.Read(b)\n}\n\nfunc (c *outboundConn) Close() error {\n\tc.access.Lock()\n\tclose(c.connReady)\n\tif c.conn != nil {\n\t\tc.conn.Close()\n\t}\n\tc.access.Unlock()\n\treturn nil\n}\n"
  },
  {
    "path": "proxy/dns/dns_test.go",
    "content": "package dns_test\n\nimport (\n\t\"strconv\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/miekg/dns\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/app/dispatcher\"\n\tdnsapp \"v2ray.com/core/app/dns\"\n\t\"v2ray.com/core/app/policy\"\n\t\"v2ray.com/core/app/proxyman\"\n\t_ \"v2ray.com/core/app/proxyman/inbound\"\n\t_ \"v2ray.com/core/app/proxyman/outbound\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/serial\"\n\tdns_proxy \"v2ray.com/core/proxy/dns\"\n\t\"v2ray.com/core/proxy/dokodemo\"\n\t\"v2ray.com/core/testing/servers/tcp\"\n\t\"v2ray.com/core/testing/servers/udp\"\n)\n\ntype staticHandler struct {\n}\n\nfunc (*staticHandler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {\n\tans := new(dns.Msg)\n\tans.Id = r.Id\n\n\tvar clientIP net.IP\n\n\topt := r.IsEdns0()\n\tif opt != nil {\n\t\tfor _, o := range opt.Option {\n\t\t\tif o.Option() == dns.EDNS0SUBNET {\n\t\t\t\tsubnet := o.(*dns.EDNS0_SUBNET)\n\t\t\t\tclientIP = subnet.Address\n\t\t\t}\n\t\t}\n\t}\n\n\tfor _, q := range r.Question {\n\t\tif q.Name == \"google.com.\" && q.Qtype == dns.TypeA {\n\t\t\tif clientIP == nil {\n\t\t\t\trr, _ := dns.NewRR(\"google.com. IN A 8.8.8.8\")\n\t\t\t\tans.Answer = append(ans.Answer, rr)\n\t\t\t} else {\n\t\t\t\trr, _ := dns.NewRR(\"google.com. IN A 8.8.4.4\")\n\t\t\t\tans.Answer = append(ans.Answer, rr)\n\t\t\t}\n\t\t} else if q.Name == \"facebook.com.\" && q.Qtype == dns.TypeA {\n\t\t\trr, _ := dns.NewRR(\"facebook.com. IN A 9.9.9.9\")\n\t\t\tans.Answer = append(ans.Answer, rr)\n\t\t} else if q.Name == \"ipv6.google.com.\" && q.Qtype == dns.TypeA {\n\t\t\trr, err := dns.NewRR(\"ipv6.google.com. IN A 8.8.8.7\")\n\t\t\tcommon.Must(err)\n\t\t\tans.Answer = append(ans.Answer, rr)\n\t\t} else if q.Name == \"ipv6.google.com.\" && q.Qtype == dns.TypeAAAA {\n\t\t\trr, err := dns.NewRR(\"ipv6.google.com. IN AAAA 2001:4860:4860::8888\")\n\t\t\tcommon.Must(err)\n\t\t\tans.Answer = append(ans.Answer, rr)\n\t\t} else if q.Name == \"notexist.google.com.\" && q.Qtype == dns.TypeAAAA {\n\t\t\tans.MsgHdr.Rcode = dns.RcodeNameError\n\t\t}\n\t}\n\tw.WriteMsg(ans)\n}\n\nfunc TestUDPDNSTunnel(t *testing.T) {\n\tport := udp.PickPort()\n\n\tdnsServer := dns.Server{\n\t\tAddr:    \"127.0.0.1:\" + port.String(),\n\t\tNet:     \"udp\",\n\t\tHandler: &staticHandler{},\n\t\tUDPSize: 1200,\n\t}\n\tdefer dnsServer.Shutdown()\n\n\tgo dnsServer.ListenAndServe()\n\ttime.Sleep(time.Second)\n\n\tserverPort := udp.PickPort()\n\tconfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&dnsapp.Config{\n\t\t\t\tNameServers: []*net.Endpoint{\n\t\t\t\t\t{\n\t\t\t\t\t\tNetwork: net.Network_UDP,\n\t\t\t\t\t\tAddress: &net.IPOrDomain{\n\t\t\t\t\t\t\tAddress: &net.IPOrDomain_Ip{\n\t\t\t\t\t\t\t\tIp: []byte{127, 0, 0, 1},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tPort: uint32(port),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}),\n\t\t\tserial.ToTypedMessage(&dispatcher.Config{}),\n\t\t\tserial.ToTypedMessage(&proxyman.OutboundConfig{}),\n\t\t\tserial.ToTypedMessage(&proxyman.InboundConfig{}),\n\t\t\tserial.ToTypedMessage(&policy.Config{}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress:  net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\tPort:     uint32(port),\n\t\t\t\t\tNetworks: []net.Network{net.Network_UDP},\n\t\t\t\t}),\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dns_proxy.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tv, err := core.New(config)\n\tcommon.Must(err)\n\tcommon.Must(v.Start())\n\tdefer v.Close()\n\n\t{\n\t\tm1 := new(dns.Msg)\n\t\tm1.Id = dns.Id()\n\t\tm1.RecursionDesired = true\n\t\tm1.Question = make([]dns.Question, 1)\n\t\tm1.Question[0] = dns.Question{Name: \"google.com.\", Qtype: dns.TypeA, Qclass: dns.ClassINET}\n\n\t\tc := new(dns.Client)\n\t\tin, _, err := c.Exchange(m1, \"127.0.0.1:\"+strconv.Itoa(int(serverPort)))\n\t\tcommon.Must(err)\n\n\t\tif len(in.Answer) != 1 {\n\t\t\tt.Fatal(\"len(answer): \", len(in.Answer))\n\t\t}\n\n\t\trr, ok := in.Answer[0].(*dns.A)\n\t\tif !ok {\n\t\t\tt.Fatal(\"not A record\")\n\t\t}\n\t\tif r := cmp.Diff(rr.A[:], net.IP{8, 8, 8, 8}); r != \"\" {\n\t\t\tt.Error(r)\n\t\t}\n\t}\n\n\t{\n\t\tm1 := new(dns.Msg)\n\t\tm1.Id = dns.Id()\n\t\tm1.RecursionDesired = true\n\t\tm1.Question = make([]dns.Question, 1)\n\t\tm1.Question[0] = dns.Question{Name: \"ipv4only.google.com.\", Qtype: dns.TypeAAAA, Qclass: dns.ClassINET}\n\n\t\tc := new(dns.Client)\n\t\tc.Timeout = 10 * time.Second\n\t\tin, _, err := c.Exchange(m1, \"127.0.0.1:\"+strconv.Itoa(int(serverPort)))\n\t\tcommon.Must(err)\n\n\t\tif len(in.Answer) != 0 {\n\t\t\tt.Fatal(\"len(answer): \", len(in.Answer))\n\t\t}\n\t}\n\n\t{\n\t\tm1 := new(dns.Msg)\n\t\tm1.Id = dns.Id()\n\t\tm1.RecursionDesired = true\n\t\tm1.Question = make([]dns.Question, 1)\n\t\tm1.Question[0] = dns.Question{Name: \"notexist.google.com.\", Qtype: dns.TypeAAAA, Qclass: dns.ClassINET}\n\n\t\tc := new(dns.Client)\n\t\tin, _, err := c.Exchange(m1, \"127.0.0.1:\"+strconv.Itoa(int(serverPort)))\n\t\tcommon.Must(err)\n\n\t\tif in.Rcode != dns.RcodeNameError {\n\t\t\tt.Error(\"expected NameError, but got \", in.Rcode)\n\t\t}\n\t}\n}\n\nfunc TestTCPDNSTunnel(t *testing.T) {\n\tport := udp.PickPort()\n\n\tdnsServer := dns.Server{\n\t\tAddr:    \"127.0.0.1:\" + port.String(),\n\t\tNet:     \"udp\",\n\t\tHandler: &staticHandler{},\n\t}\n\tdefer dnsServer.Shutdown()\n\n\tgo dnsServer.ListenAndServe()\n\ttime.Sleep(time.Second)\n\n\tserverPort := tcp.PickPort()\n\tconfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&dnsapp.Config{\n\t\t\t\tNameServer: []*dnsapp.NameServer{\n\t\t\t\t\t{\n\t\t\t\t\t\tAddress: &net.Endpoint{\n\t\t\t\t\t\t\tNetwork: net.Network_UDP,\n\t\t\t\t\t\t\tAddress: &net.IPOrDomain{\n\t\t\t\t\t\t\t\tAddress: &net.IPOrDomain_Ip{\n\t\t\t\t\t\t\t\t\tIp: []byte{127, 0, 0, 1},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tPort: uint32(port),\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\tserial.ToTypedMessage(&dispatcher.Config{}),\n\t\t\tserial.ToTypedMessage(&proxyman.OutboundConfig{}),\n\t\t\tserial.ToTypedMessage(&proxyman.InboundConfig{}),\n\t\t\tserial.ToTypedMessage(&policy.Config{}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress:  net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\tPort:     uint32(port),\n\t\t\t\t\tNetworks: []net.Network{net.Network_TCP},\n\t\t\t\t}),\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dns_proxy.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tv, err := core.New(config)\n\tcommon.Must(err)\n\tcommon.Must(v.Start())\n\tdefer v.Close()\n\n\tm1 := new(dns.Msg)\n\tm1.Id = dns.Id()\n\tm1.RecursionDesired = true\n\tm1.Question = make([]dns.Question, 1)\n\tm1.Question[0] = dns.Question{Name: \"google.com.\", Qtype: dns.TypeA, Qclass: dns.ClassINET}\n\n\tc := &dns.Client{\n\t\tNet: \"tcp\",\n\t}\n\tin, _, err := c.Exchange(m1, \"127.0.0.1:\"+serverPort.String())\n\tcommon.Must(err)\n\n\tif len(in.Answer) != 1 {\n\t\tt.Fatal(\"len(answer): \", len(in.Answer))\n\t}\n\n\trr, ok := in.Answer[0].(*dns.A)\n\tif !ok {\n\t\tt.Fatal(\"not A record\")\n\t}\n\tif r := cmp.Diff(rr.A[:], net.IP{8, 8, 8, 8}); r != \"\" {\n\t\tt.Error(r)\n\t}\n}\n\nfunc TestUDP2TCPDNSTunnel(t *testing.T) {\n\tport := tcp.PickPort()\n\n\tdnsServer := dns.Server{\n\t\tAddr:    \"127.0.0.1:\" + port.String(),\n\t\tNet:     \"tcp\",\n\t\tHandler: &staticHandler{},\n\t}\n\tdefer dnsServer.Shutdown()\n\n\tgo dnsServer.ListenAndServe()\n\ttime.Sleep(time.Second)\n\n\tserverPort := tcp.PickPort()\n\tconfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&dnsapp.Config{\n\t\t\t\tNameServer: []*dnsapp.NameServer{\n\t\t\t\t\t{\n\t\t\t\t\t\tAddress: &net.Endpoint{\n\t\t\t\t\t\t\tNetwork: net.Network_UDP,\n\t\t\t\t\t\t\tAddress: &net.IPOrDomain{\n\t\t\t\t\t\t\t\tAddress: &net.IPOrDomain_Ip{\n\t\t\t\t\t\t\t\t\tIp: []byte{127, 0, 0, 1},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tPort: uint32(port),\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\tserial.ToTypedMessage(&dispatcher.Config{}),\n\t\t\tserial.ToTypedMessage(&proxyman.OutboundConfig{}),\n\t\t\tserial.ToTypedMessage(&proxyman.InboundConfig{}),\n\t\t\tserial.ToTypedMessage(&policy.Config{}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress:  net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\tPort:     uint32(port),\n\t\t\t\t\tNetworks: []net.Network{net.Network_TCP},\n\t\t\t\t}),\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dns_proxy.Config{\n\t\t\t\t\tServer: &net.Endpoint{\n\t\t\t\t\t\tNetwork: net.Network_TCP,\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t}\n\n\tv, err := core.New(config)\n\tcommon.Must(err)\n\tcommon.Must(v.Start())\n\tdefer v.Close()\n\n\tm1 := new(dns.Msg)\n\tm1.Id = dns.Id()\n\tm1.RecursionDesired = true\n\tm1.Question = make([]dns.Question, 1)\n\tm1.Question[0] = dns.Question{Name: \"google.com.\", Qtype: dns.TypeA, Qclass: dns.ClassINET}\n\n\tc := &dns.Client{\n\t\tNet: \"tcp\",\n\t}\n\tin, _, err := c.Exchange(m1, \"127.0.0.1:\"+serverPort.String())\n\tcommon.Must(err)\n\n\tif len(in.Answer) != 1 {\n\t\tt.Fatal(\"len(answer): \", len(in.Answer))\n\t}\n\n\trr, ok := in.Answer[0].(*dns.A)\n\tif !ok {\n\t\tt.Fatal(\"not A record\")\n\t}\n\tif r := cmp.Diff(rr.A[:], net.IP{8, 8, 8, 8}); r != \"\" {\n\t\tt.Error(r)\n\t}\n}\n"
  },
  {
    "path": "proxy/dns/errors.generated.go",
    "content": "package dns\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "proxy/dokodemo/config.go",
    "content": "package dokodemo\n\nimport (\n\t\"v2ray.com/core/common/net\"\n)\n\n// GetPredefinedAddress returns the defined address from proto config. Null if address is not valid.\nfunc (v *Config) GetPredefinedAddress() net.Address {\n\taddr := v.Address.AsAddress()\n\tif addr == nil {\n\t\treturn nil\n\t}\n\treturn addr\n}\n"
  },
  {
    "path": "proxy/dokodemo/config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: proxy/dokodemo/config.proto\n\npackage dokodemo\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n\tnet \"v2ray.com/core/common/net\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype Config struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tAddress *net.IPOrDomain `protobuf:\"bytes,1,opt,name=address,proto3\" json:\"address,omitempty\"`\n\tPort    uint32          `protobuf:\"varint,2,opt,name=port,proto3\" json:\"port,omitempty\"`\n\t// List of networks that the Dokodemo accepts.\n\t// Deprecated. Use networks.\n\t//\n\t// Deprecated: Do not use.\n\tNetworkList *net.NetworkList `protobuf:\"bytes,3,opt,name=network_list,json=networkList,proto3\" json:\"network_list,omitempty\"`\n\t// List of networks that the Dokodemo accepts.\n\tNetworks []net.Network `protobuf:\"varint,7,rep,packed,name=networks,proto3,enum=v2ray.core.common.net.Network\" json:\"networks,omitempty\"`\n\t// Deprecated: Do not use.\n\tTimeout        uint32 `protobuf:\"varint,4,opt,name=timeout,proto3\" json:\"timeout,omitempty\"`\n\tFollowRedirect bool   `protobuf:\"varint,5,opt,name=follow_redirect,json=followRedirect,proto3\" json:\"follow_redirect,omitempty\"`\n\tUserLevel      uint32 `protobuf:\"varint,6,opt,name=user_level,json=userLevel,proto3\" json:\"user_level,omitempty\"`\n}\n\nfunc (x *Config) Reset() {\n\t*x = Config{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_proxy_dokodemo_config_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Config) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Config) ProtoMessage() {}\n\nfunc (x *Config) ProtoReflect() protoreflect.Message {\n\tmi := &file_proxy_dokodemo_config_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Config.ProtoReflect.Descriptor instead.\nfunc (*Config) Descriptor() ([]byte, []int) {\n\treturn file_proxy_dokodemo_config_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *Config) GetAddress() *net.IPOrDomain {\n\tif x != nil {\n\t\treturn x.Address\n\t}\n\treturn nil\n}\n\nfunc (x *Config) GetPort() uint32 {\n\tif x != nil {\n\t\treturn x.Port\n\t}\n\treturn 0\n}\n\n// Deprecated: Do not use.\nfunc (x *Config) GetNetworkList() *net.NetworkList {\n\tif x != nil {\n\t\treturn x.NetworkList\n\t}\n\treturn nil\n}\n\nfunc (x *Config) GetNetworks() []net.Network {\n\tif x != nil {\n\t\treturn x.Networks\n\t}\n\treturn nil\n}\n\n// Deprecated: Do not use.\nfunc (x *Config) GetTimeout() uint32 {\n\tif x != nil {\n\t\treturn x.Timeout\n\t}\n\treturn 0\n}\n\nfunc (x *Config) GetFollowRedirect() bool {\n\tif x != nil {\n\t\treturn x.FollowRedirect\n\t}\n\treturn false\n}\n\nfunc (x *Config) GetUserLevel() uint32 {\n\tif x != nil {\n\t\treturn x.UserLevel\n\t}\n\treturn 0\n}\n\nvar File_proxy_dokodemo_config_proto protoreflect.FileDescriptor\n\nvar file_proxy_dokodemo_config_proto_rawDesc = []byte{\n\t0x0a, 0x1b, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x64, 0x6f, 0x6b, 0x6f, 0x64, 0x65, 0x6d, 0x6f,\n\t0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x19, 0x76,\n\t0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e,\n\t0x64, 0x6f, 0x6b, 0x6f, 0x64, 0x65, 0x6d, 0x6f, 0x1a, 0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,\n\t0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x70, 0x72, 0x6f,\n\t0x74, 0x6f, 0x1a, 0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x6e,\n\t0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc6, 0x02, 0x0a,\n\t0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3b, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65,\n\t0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,\n\t0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74,\n\t0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x07, 0x61, 0x64, 0x64,\n\t0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01,\n\t0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x49, 0x0a, 0x0c, 0x6e, 0x65, 0x74, 0x77,\n\t0x6f, 0x72, 0x6b, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22,\n\t0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,\n\t0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4c, 0x69,\n\t0x73, 0x74, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0b, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4c,\n\t0x69, 0x73, 0x74, 0x12, 0x3a, 0x0a, 0x08, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x18,\n\t0x07, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,\n\t0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4e, 0x65,\n\t0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x08, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x12,\n\t0x1c, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d,\n\t0x42, 0x02, 0x18, 0x01, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x27, 0x0a,\n\t0x0f, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74,\n\t0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x52, 0x65,\n\t0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6c,\n\t0x65, 0x76, 0x65, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72,\n\t0x4c, 0x65, 0x76, 0x65, 0x6c, 0x42, 0x5c, 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72,\n\t0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x64, 0x6f,\n\t0x6b, 0x6f, 0x64, 0x65, 0x6d, 0x6f, 0x50, 0x01, 0x5a, 0x1d, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,\n\t0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x64,\n\t0x6f, 0x6b, 0x6f, 0x64, 0x65, 0x6d, 0x6f, 0xaa, 0x02, 0x19, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e,\n\t0x43, 0x6f, 0x72, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x44, 0x6f, 0x6b, 0x6f, 0x64,\n\t0x65, 0x6d, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_proxy_dokodemo_config_proto_rawDescOnce sync.Once\n\tfile_proxy_dokodemo_config_proto_rawDescData = file_proxy_dokodemo_config_proto_rawDesc\n)\n\nfunc file_proxy_dokodemo_config_proto_rawDescGZIP() []byte {\n\tfile_proxy_dokodemo_config_proto_rawDescOnce.Do(func() {\n\t\tfile_proxy_dokodemo_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_proxy_dokodemo_config_proto_rawDescData)\n\t})\n\treturn file_proxy_dokodemo_config_proto_rawDescData\n}\n\nvar file_proxy_dokodemo_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)\nvar file_proxy_dokodemo_config_proto_goTypes = []interface{}{\n\t(*Config)(nil),          // 0: v2ray.core.proxy.dokodemo.Config\n\t(*net.IPOrDomain)(nil),  // 1: v2ray.core.common.net.IPOrDomain\n\t(*net.NetworkList)(nil), // 2: v2ray.core.common.net.NetworkList\n\t(net.Network)(0),        // 3: v2ray.core.common.net.Network\n}\nvar file_proxy_dokodemo_config_proto_depIdxs = []int32{\n\t1, // 0: v2ray.core.proxy.dokodemo.Config.address:type_name -> v2ray.core.common.net.IPOrDomain\n\t2, // 1: v2ray.core.proxy.dokodemo.Config.network_list:type_name -> v2ray.core.common.net.NetworkList\n\t3, // 2: v2ray.core.proxy.dokodemo.Config.networks:type_name -> v2ray.core.common.net.Network\n\t3, // [3:3] is the sub-list for method output_type\n\t3, // [3:3] is the sub-list for method input_type\n\t3, // [3:3] is the sub-list for extension type_name\n\t3, // [3:3] is the sub-list for extension extendee\n\t0, // [0:3] is the sub-list for field type_name\n}\n\nfunc init() { file_proxy_dokodemo_config_proto_init() }\nfunc file_proxy_dokodemo_config_proto_init() {\n\tif File_proxy_dokodemo_config_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_proxy_dokodemo_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Config); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_proxy_dokodemo_config_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   1,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_proxy_dokodemo_config_proto_goTypes,\n\t\tDependencyIndexes: file_proxy_dokodemo_config_proto_depIdxs,\n\t\tMessageInfos:      file_proxy_dokodemo_config_proto_msgTypes,\n\t}.Build()\n\tFile_proxy_dokodemo_config_proto = out.File\n\tfile_proxy_dokodemo_config_proto_rawDesc = nil\n\tfile_proxy_dokodemo_config_proto_goTypes = nil\n\tfile_proxy_dokodemo_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "proxy/dokodemo/config.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.proxy.dokodemo;\noption csharp_namespace = \"V2Ray.Core.Proxy.Dokodemo\";\noption go_package = \"v2ray.com/core/proxy/dokodemo\";\noption java_package = \"com.v2ray.core.proxy.dokodemo\";\noption java_multiple_files = true;\n\nimport \"common/net/address.proto\";\nimport \"common/net/network.proto\";\n\nmessage Config {\n  v2ray.core.common.net.IPOrDomain address = 1;\n  uint32 port = 2;\n\n  // List of networks that the Dokodemo accepts.\n  // Deprecated. Use networks.\n  v2ray.core.common.net.NetworkList network_list = 3 [deprecated = true];\n  // List of networks that the Dokodemo accepts.\n  repeated v2ray.core.common.net.Network networks = 7;\n\n  uint32 timeout = 4 [deprecated = true];\n  bool follow_redirect = 5;\n  uint32 user_level = 6;\n}\n"
  },
  {
    "path": "proxy/dokodemo/dokodemo.go",
    "content": "// +build !confonly\n\npackage dokodemo\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n\nimport (\n\t\"context\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/log\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/session\"\n\t\"v2ray.com/core/common/signal\"\n\t\"v2ray.com/core/common/task\"\n\t\"v2ray.com/core/features/policy\"\n\t\"v2ray.com/core/features/routing\"\n\t\"v2ray.com/core/transport/internet\"\n)\n\nfunc init() {\n\tcommon.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {\n\t\td := new(DokodemoDoor)\n\t\terr := core.RequireFeatures(ctx, func(pm policy.Manager) error {\n\t\t\treturn d.Init(config.(*Config), pm, session.SockoptFromContext(ctx))\n\t\t})\n\t\treturn d, err\n\t}))\n}\n\ntype DokodemoDoor struct {\n\tpolicyManager policy.Manager\n\tconfig        *Config\n\taddress       net.Address\n\tport          net.Port\n\tsockopt       *session.Sockopt\n}\n\n// Init initializes the DokodemoDoor instance with necessary parameters.\nfunc (d *DokodemoDoor) Init(config *Config, pm policy.Manager, sockopt *session.Sockopt) error {\n\tif (config.NetworkList == nil || len(config.NetworkList.Network) == 0) && len(config.Networks) == 0 {\n\t\treturn newError(\"no network specified\")\n\t}\n\td.config = config\n\td.address = config.GetPredefinedAddress()\n\td.port = net.Port(config.Port)\n\td.policyManager = pm\n\td.sockopt = sockopt\n\n\treturn nil\n}\n\n// Network implements proxy.Inbound.\nfunc (d *DokodemoDoor) Network() []net.Network {\n\tif len(d.config.Networks) > 0 {\n\t\treturn d.config.Networks\n\t}\n\n\treturn d.config.NetworkList.Network\n}\n\nfunc (d *DokodemoDoor) policy() policy.Session {\n\tconfig := d.config\n\tp := d.policyManager.ForLevel(config.UserLevel)\n\tif config.Timeout > 0 && config.UserLevel == 0 {\n\t\tp.Timeouts.ConnectionIdle = time.Duration(config.Timeout) * time.Second\n\t}\n\treturn p\n}\n\ntype hasHandshakeAddress interface {\n\tHandshakeAddress() net.Address\n}\n\n// Process implements proxy.Inbound.\nfunc (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn internet.Connection, dispatcher routing.Dispatcher) error {\n\tnewError(\"processing connection from: \", conn.RemoteAddr()).AtDebug().WriteToLog(session.ExportIDToError(ctx))\n\tdest := net.Destination{\n\t\tNetwork: network,\n\t\tAddress: d.address,\n\t\tPort:    d.port,\n\t}\n\n\tdestinationOverridden := false\n\tif d.config.FollowRedirect {\n\t\tif outbound := session.OutboundFromContext(ctx); outbound != nil && outbound.Target.IsValid() {\n\t\t\tdest = outbound.Target\n\t\t\tdestinationOverridden = true\n\t\t} else if handshake, ok := conn.(hasHandshakeAddress); ok {\n\t\t\taddr := handshake.HandshakeAddress()\n\t\t\tif addr != nil {\n\t\t\t\tdest.Address = addr\n\t\t\t\tdestinationOverridden = true\n\t\t\t}\n\t\t}\n\t}\n\tif !dest.IsValid() || dest.Address == nil {\n\t\treturn newError(\"unable to get destination\")\n\t}\n\n\tif inbound := session.InboundFromContext(ctx); inbound != nil {\n\t\tinbound.User = &protocol.MemoryUser{\n\t\t\tLevel: d.config.UserLevel,\n\t\t}\n\t}\n\n\tctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{\n\t\tFrom:   conn.RemoteAddr(),\n\t\tTo:     dest,\n\t\tStatus: log.AccessAccepted,\n\t\tReason: \"\",\n\t})\n\tnewError(\"received request for \", conn.RemoteAddr()).WriteToLog(session.ExportIDToError(ctx))\n\n\tplcy := d.policy()\n\tctx, cancel := context.WithCancel(ctx)\n\ttimer := signal.CancelAfterInactivity(ctx, cancel, plcy.Timeouts.ConnectionIdle)\n\n\tctx = policy.ContextWithBufferPolicy(ctx, plcy.Buffer)\n\tlink, err := dispatcher.Dispatch(ctx, dest)\n\tif err != nil {\n\t\treturn newError(\"failed to dispatch request\").Base(err)\n\t}\n\n\trequestCount := int32(1)\n\trequestDone := func() error {\n\t\tdefer func() {\n\t\t\tif atomic.AddInt32(&requestCount, -1) == 0 {\n\t\t\t\ttimer.SetTimeout(plcy.Timeouts.DownlinkOnly)\n\t\t\t}\n\t\t}()\n\n\t\tvar reader buf.Reader\n\t\tif dest.Network == net.Network_UDP {\n\t\t\treader = buf.NewPacketReader(conn)\n\t\t} else {\n\t\t\treader = buf.NewReader(conn)\n\t\t}\n\t\tif err := buf.Copy(reader, link.Writer, buf.UpdateActivity(timer)); err != nil {\n\t\t\treturn newError(\"failed to transport request\").Base(err)\n\t\t}\n\n\t\treturn nil\n\t}\n\n\ttproxyRequest := func() error {\n\t\treturn nil\n\t}\n\n\tvar writer buf.Writer\n\tif network == net.Network_TCP {\n\t\twriter = buf.NewWriter(conn)\n\t} else {\n\t\t//if we are in TPROXY mode, use linux's udp forging functionality\n\t\tif !destinationOverridden {\n\t\t\twriter = &buf.SequentialWriter{Writer: conn}\n\t\t} else {\n\t\t\tsockopt := &internet.SocketConfig{\n\t\t\t\tTproxy: internet.SocketConfig_TProxy,\n\t\t\t}\n\t\t\tif dest.Address.Family().IsIP() {\n\t\t\t\tsockopt.BindAddress = dest.Address.IP()\n\t\t\t\tsockopt.BindPort = uint32(dest.Port)\n\t\t\t}\n\t\t\tif d.sockopt != nil {\n\t\t\t\tsockopt.Mark = d.sockopt.Mark\n\t\t\t}\n\t\t\ttConn, err := internet.DialSystem(ctx, net.DestinationFromAddr(conn.RemoteAddr()), sockopt)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tdefer tConn.Close()\n\n\t\t\twriter = &buf.SequentialWriter{Writer: tConn}\n\t\t\ttReader := buf.NewPacketReader(tConn)\n\t\t\trequestCount++\n\t\t\ttproxyRequest = func() error {\n\t\t\t\tdefer func() {\n\t\t\t\t\tif atomic.AddInt32(&requestCount, -1) == 0 {\n\t\t\t\t\t\ttimer.SetTimeout(plcy.Timeouts.DownlinkOnly)\n\t\t\t\t\t}\n\t\t\t\t}()\n\t\t\t\tif err := buf.Copy(tReader, link.Writer, buf.UpdateActivity(timer)); err != nil {\n\t\t\t\t\treturn newError(\"failed to transport request (TPROXY conn)\").Base(err)\n\t\t\t\t}\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\n\tresponseDone := func() error {\n\t\tdefer timer.SetTimeout(plcy.Timeouts.UplinkOnly)\n\n\t\tif err := buf.Copy(link.Reader, writer, buf.UpdateActivity(timer)); err != nil {\n\t\t\treturn newError(\"failed to transport response\").Base(err)\n\t\t}\n\t\treturn nil\n\t}\n\n\tif err := task.Run(ctx, task.OnSuccess(func() error {\n\t\treturn task.Run(ctx, requestDone, tproxyRequest)\n\t}, task.Close(link.Writer)), responseDone); err != nil {\n\t\tcommon.Interrupt(link.Reader)\n\t\tcommon.Interrupt(link.Writer)\n\t\treturn newError(\"connection ends\").Base(err)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "proxy/dokodemo/errors.generated.go",
    "content": "package dokodemo\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "proxy/freedom/config.go",
    "content": "package freedom\n\nfunc (c *Config) useIP() bool {\n\treturn c.DomainStrategy == Config_USE_IP || c.DomainStrategy == Config_USE_IP4 || c.DomainStrategy == Config_USE_IP6\n}\n"
  },
  {
    "path": "proxy/freedom/config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: proxy/freedom/config.proto\n\npackage freedom\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n\tprotocol \"v2ray.com/core/common/protocol\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype Config_DomainStrategy int32\n\nconst (\n\tConfig_AS_IS   Config_DomainStrategy = 0\n\tConfig_USE_IP  Config_DomainStrategy = 1\n\tConfig_USE_IP4 Config_DomainStrategy = 2\n\tConfig_USE_IP6 Config_DomainStrategy = 3\n)\n\n// Enum value maps for Config_DomainStrategy.\nvar (\n\tConfig_DomainStrategy_name = map[int32]string{\n\t\t0: \"AS_IS\",\n\t\t1: \"USE_IP\",\n\t\t2: \"USE_IP4\",\n\t\t3: \"USE_IP6\",\n\t}\n\tConfig_DomainStrategy_value = map[string]int32{\n\t\t\"AS_IS\":   0,\n\t\t\"USE_IP\":  1,\n\t\t\"USE_IP4\": 2,\n\t\t\"USE_IP6\": 3,\n\t}\n)\n\nfunc (x Config_DomainStrategy) Enum() *Config_DomainStrategy {\n\tp := new(Config_DomainStrategy)\n\t*p = x\n\treturn p\n}\n\nfunc (x Config_DomainStrategy) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (Config_DomainStrategy) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_proxy_freedom_config_proto_enumTypes[0].Descriptor()\n}\n\nfunc (Config_DomainStrategy) Type() protoreflect.EnumType {\n\treturn &file_proxy_freedom_config_proto_enumTypes[0]\n}\n\nfunc (x Config_DomainStrategy) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use Config_DomainStrategy.Descriptor instead.\nfunc (Config_DomainStrategy) EnumDescriptor() ([]byte, []int) {\n\treturn file_proxy_freedom_config_proto_rawDescGZIP(), []int{1, 0}\n}\n\ntype DestinationOverride struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tServer *protocol.ServerEndpoint `protobuf:\"bytes,1,opt,name=server,proto3\" json:\"server,omitempty\"`\n}\n\nfunc (x *DestinationOverride) Reset() {\n\t*x = DestinationOverride{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_proxy_freedom_config_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *DestinationOverride) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*DestinationOverride) ProtoMessage() {}\n\nfunc (x *DestinationOverride) ProtoReflect() protoreflect.Message {\n\tmi := &file_proxy_freedom_config_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use DestinationOverride.ProtoReflect.Descriptor instead.\nfunc (*DestinationOverride) Descriptor() ([]byte, []int) {\n\treturn file_proxy_freedom_config_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *DestinationOverride) GetServer() *protocol.ServerEndpoint {\n\tif x != nil {\n\t\treturn x.Server\n\t}\n\treturn nil\n}\n\ntype Config struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tDomainStrategy Config_DomainStrategy `protobuf:\"varint,1,opt,name=domain_strategy,json=domainStrategy,proto3,enum=v2ray.core.proxy.freedom.Config_DomainStrategy\" json:\"domain_strategy,omitempty\"`\n\t// Deprecated: Do not use.\n\tTimeout             uint32               `protobuf:\"varint,2,opt,name=timeout,proto3\" json:\"timeout,omitempty\"`\n\tDestinationOverride *DestinationOverride `protobuf:\"bytes,3,opt,name=destination_override,json=destinationOverride,proto3\" json:\"destination_override,omitempty\"`\n\tUserLevel           uint32               `protobuf:\"varint,4,opt,name=user_level,json=userLevel,proto3\" json:\"user_level,omitempty\"`\n}\n\nfunc (x *Config) Reset() {\n\t*x = Config{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_proxy_freedom_config_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Config) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Config) ProtoMessage() {}\n\nfunc (x *Config) ProtoReflect() protoreflect.Message {\n\tmi := &file_proxy_freedom_config_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Config.ProtoReflect.Descriptor instead.\nfunc (*Config) Descriptor() ([]byte, []int) {\n\treturn file_proxy_freedom_config_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *Config) GetDomainStrategy() Config_DomainStrategy {\n\tif x != nil {\n\t\treturn x.DomainStrategy\n\t}\n\treturn Config_AS_IS\n}\n\n// Deprecated: Do not use.\nfunc (x *Config) GetTimeout() uint32 {\n\tif x != nil {\n\t\treturn x.Timeout\n\t}\n\treturn 0\n}\n\nfunc (x *Config) GetDestinationOverride() *DestinationOverride {\n\tif x != nil {\n\t\treturn x.DestinationOverride\n\t}\n\treturn nil\n}\n\nfunc (x *Config) GetUserLevel() uint32 {\n\tif x != nil {\n\t\treturn x.UserLevel\n\t}\n\treturn 0\n}\n\nvar File_proxy_freedom_config_proto protoreflect.FileDescriptor\n\nvar file_proxy_freedom_config_proto_rawDesc = []byte{\n\t0x0a, 0x1a, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x2f,\n\t0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x18, 0x76, 0x32,\n\t0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x66,\n\t0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70,\n\t0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x73,\n\t0x70, 0x65, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x59, 0x0a, 0x13, 0x44, 0x65, 0x73,\n\t0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65,\n\t0x12, 0x42, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,\n\t0x32, 0x2a, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f,\n\t0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65,\n\t0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x73, 0x65,\n\t0x72, 0x76, 0x65, 0x72, 0x22, 0xc4, 0x02, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,\n\t0x58, 0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65,\n\t0x67, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,\n\t0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x66, 0x72, 0x65, 0x65,\n\t0x64, 0x6f, 0x6d, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69,\n\t0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69,\n\t0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x1c, 0x0a, 0x07, 0x74, 0x69, 0x6d,\n\t0x65, 0x6f, 0x75, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x02, 0x18, 0x01, 0x52, 0x07,\n\t0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x60, 0x0a, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69,\n\t0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18,\n\t0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,\n\t0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d,\n\t0x2e, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x72,\n\t0x72, 0x69, 0x64, 0x65, 0x52, 0x13, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f,\n\t0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x65,\n\t0x72, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x75,\n\t0x73, 0x65, 0x72, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0x41, 0x0a, 0x0e, 0x44, 0x6f, 0x6d, 0x61,\n\t0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x53,\n\t0x5f, 0x49, 0x53, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x10,\n\t0x01, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x02, 0x12, 0x0b,\n\t0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x10, 0x03, 0x42, 0x59, 0x0a, 0x1c, 0x63,\n\t0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72,\n\t0x6f, 0x78, 0x79, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x50, 0x01, 0x5a, 0x1c, 0x76,\n\t0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72,\n\t0x6f, 0x78, 0x79, 0x2f, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0xaa, 0x02, 0x18, 0x56, 0x32,\n\t0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x46,\n\t0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_proxy_freedom_config_proto_rawDescOnce sync.Once\n\tfile_proxy_freedom_config_proto_rawDescData = file_proxy_freedom_config_proto_rawDesc\n)\n\nfunc file_proxy_freedom_config_proto_rawDescGZIP() []byte {\n\tfile_proxy_freedom_config_proto_rawDescOnce.Do(func() {\n\t\tfile_proxy_freedom_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_proxy_freedom_config_proto_rawDescData)\n\t})\n\treturn file_proxy_freedom_config_proto_rawDescData\n}\n\nvar file_proxy_freedom_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1)\nvar file_proxy_freedom_config_proto_msgTypes = make([]protoimpl.MessageInfo, 2)\nvar file_proxy_freedom_config_proto_goTypes = []interface{}{\n\t(Config_DomainStrategy)(0),      // 0: v2ray.core.proxy.freedom.Config.DomainStrategy\n\t(*DestinationOverride)(nil),     // 1: v2ray.core.proxy.freedom.DestinationOverride\n\t(*Config)(nil),                  // 2: v2ray.core.proxy.freedom.Config\n\t(*protocol.ServerEndpoint)(nil), // 3: v2ray.core.common.protocol.ServerEndpoint\n}\nvar file_proxy_freedom_config_proto_depIdxs = []int32{\n\t3, // 0: v2ray.core.proxy.freedom.DestinationOverride.server:type_name -> v2ray.core.common.protocol.ServerEndpoint\n\t0, // 1: v2ray.core.proxy.freedom.Config.domain_strategy:type_name -> v2ray.core.proxy.freedom.Config.DomainStrategy\n\t1, // 2: v2ray.core.proxy.freedom.Config.destination_override:type_name -> v2ray.core.proxy.freedom.DestinationOverride\n\t3, // [3:3] is the sub-list for method output_type\n\t3, // [3:3] is the sub-list for method input_type\n\t3, // [3:3] is the sub-list for extension type_name\n\t3, // [3:3] is the sub-list for extension extendee\n\t0, // [0:3] is the sub-list for field type_name\n}\n\nfunc init() { file_proxy_freedom_config_proto_init() }\nfunc file_proxy_freedom_config_proto_init() {\n\tif File_proxy_freedom_config_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_proxy_freedom_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*DestinationOverride); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_proxy_freedom_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Config); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_proxy_freedom_config_proto_rawDesc,\n\t\t\tNumEnums:      1,\n\t\t\tNumMessages:   2,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_proxy_freedom_config_proto_goTypes,\n\t\tDependencyIndexes: file_proxy_freedom_config_proto_depIdxs,\n\t\tEnumInfos:         file_proxy_freedom_config_proto_enumTypes,\n\t\tMessageInfos:      file_proxy_freedom_config_proto_msgTypes,\n\t}.Build()\n\tFile_proxy_freedom_config_proto = out.File\n\tfile_proxy_freedom_config_proto_rawDesc = nil\n\tfile_proxy_freedom_config_proto_goTypes = nil\n\tfile_proxy_freedom_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "proxy/freedom/config.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.proxy.freedom;\noption csharp_namespace = \"V2Ray.Core.Proxy.Freedom\";\noption go_package = \"v2ray.com/core/proxy/freedom\";\noption java_package = \"com.v2ray.core.proxy.freedom\";\noption java_multiple_files = true;\n\nimport \"common/protocol/server_spec.proto\";\n\nmessage DestinationOverride {\n  v2ray.core.common.protocol.ServerEndpoint server = 1;\n}\n\nmessage Config {\n  enum DomainStrategy {\n    AS_IS = 0;\n    USE_IP = 1;\n    USE_IP4 = 2;\n    USE_IP6 = 3;\n  }\n  DomainStrategy domain_strategy = 1;\n  uint32 timeout = 2 [deprecated = true];\n  DestinationOverride destination_override = 3;\n  uint32 user_level = 4;\n}\n"
  },
  {
    "path": "proxy/freedom/errors.generated.go",
    "content": "package freedom\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "proxy/freedom/freedom.go",
    "content": "// +build !confonly\n\npackage freedom\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/dice\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/retry\"\n\t\"v2ray.com/core/common/session\"\n\t\"v2ray.com/core/common/signal\"\n\t\"v2ray.com/core/common/task\"\n\t\"v2ray.com/core/features/dns\"\n\t\"v2ray.com/core/features/policy\"\n\t\"v2ray.com/core/transport\"\n\t\"v2ray.com/core/transport/internet\"\n)\n\nfunc init() {\n\tcommon.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {\n\t\th := new(Handler)\n\t\tif err := core.RequireFeatures(ctx, func(pm policy.Manager, d dns.Client) error {\n\t\t\treturn h.Init(config.(*Config), pm, d)\n\t\t}); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn h, nil\n\t}))\n}\n\n// Handler handles Freedom connections.\ntype Handler struct {\n\tpolicyManager policy.Manager\n\tdns           dns.Client\n\tconfig        *Config\n}\n\n// Init initializes the Handler with necessary parameters.\nfunc (h *Handler) Init(config *Config, pm policy.Manager, d dns.Client) error {\n\th.config = config\n\th.policyManager = pm\n\th.dns = d\n\n\treturn nil\n}\n\nfunc (h *Handler) policy() policy.Session {\n\tp := h.policyManager.ForLevel(h.config.UserLevel)\n\tif h.config.Timeout > 0 && h.config.UserLevel == 0 {\n\t\tp.Timeouts.ConnectionIdle = time.Duration(h.config.Timeout) * time.Second\n\t}\n\treturn p\n}\n\nfunc (h *Handler) resolveIP(ctx context.Context, domain string, localAddr net.Address) net.Address {\n\tvar lookupFunc func(string) ([]net.IP, error) = h.dns.LookupIP\n\n\tif h.config.DomainStrategy == Config_USE_IP4 || (localAddr != nil && localAddr.Family().IsIPv4()) {\n\t\tif lookupIPv4, ok := h.dns.(dns.IPv4Lookup); ok {\n\t\t\tlookupFunc = lookupIPv4.LookupIPv4\n\t\t}\n\t} else if h.config.DomainStrategy == Config_USE_IP6 || (localAddr != nil && localAddr.Family().IsIPv6()) {\n\t\tif lookupIPv6, ok := h.dns.(dns.IPv6Lookup); ok {\n\t\t\tlookupFunc = lookupIPv6.LookupIPv6\n\t\t}\n\t}\n\n\tips, err := lookupFunc(domain)\n\tif err != nil {\n\t\tnewError(\"failed to get IP address for domain \", domain).Base(err).WriteToLog(session.ExportIDToError(ctx))\n\t}\n\tif len(ips) == 0 {\n\t\treturn nil\n\t}\n\treturn net.IPAddress(ips[dice.Roll(len(ips))])\n}\n\nfunc isValidAddress(addr *net.IPOrDomain) bool {\n\tif addr == nil {\n\t\treturn false\n\t}\n\n\ta := addr.AsAddress()\n\treturn a != net.AnyIP\n}\n\n// Process implements proxy.Outbound.\nfunc (h *Handler) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {\n\toutbound := session.OutboundFromContext(ctx)\n\tif outbound == nil || !outbound.Target.IsValid() {\n\t\treturn newError(\"target not specified.\")\n\t}\n\tdestination := outbound.Target\n\tif h.config.DestinationOverride != nil {\n\t\tserver := h.config.DestinationOverride.Server\n\t\tif isValidAddress(server.Address) {\n\t\t\tdestination.Address = server.Address.AsAddress()\n\t\t}\n\t\tif server.Port != 0 {\n\t\t\tdestination.Port = net.Port(server.Port)\n\t\t}\n\t}\n\tnewError(\"opening connection to \", destination).WriteToLog(session.ExportIDToError(ctx))\n\n\tinput := link.Reader\n\toutput := link.Writer\n\n\tvar conn internet.Connection\n\terr := retry.ExponentialBackoff(5, 100).On(func() error {\n\t\tdialDest := destination\n\t\tif h.config.useIP() && dialDest.Address.Family().IsDomain() {\n\t\t\tip := h.resolveIP(ctx, dialDest.Address.Domain(), dialer.Address())\n\t\t\tif ip != nil {\n\t\t\t\tdialDest = net.Destination{\n\t\t\t\t\tNetwork: dialDest.Network,\n\t\t\t\t\tAddress: ip,\n\t\t\t\t\tPort:    dialDest.Port,\n\t\t\t\t}\n\t\t\t\tnewError(\"dialing to to \", dialDest).WriteToLog(session.ExportIDToError(ctx))\n\t\t\t}\n\t\t}\n\n\t\trawConn, err := dialer.Dial(ctx, dialDest)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tconn = rawConn\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\treturn newError(\"failed to open connection to \", destination).Base(err)\n\t}\n\tdefer conn.Close() // nolint: errcheck\n\n\tplcy := h.policy()\n\tctx, cancel := context.WithCancel(ctx)\n\ttimer := signal.CancelAfterInactivity(ctx, cancel, plcy.Timeouts.ConnectionIdle)\n\n\trequestDone := func() error {\n\t\tdefer timer.SetTimeout(plcy.Timeouts.DownlinkOnly)\n\n\t\tvar writer buf.Writer\n\t\tif destination.Network == net.Network_TCP {\n\t\t\twriter = buf.NewWriter(conn)\n\t\t} else {\n\t\t\twriter = &buf.SequentialWriter{Writer: conn}\n\t\t}\n\n\t\tif err := buf.Copy(input, writer, buf.UpdateActivity(timer)); err != nil {\n\t\t\treturn newError(\"failed to process request\").Base(err)\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tresponseDone := func() error {\n\t\tdefer timer.SetTimeout(plcy.Timeouts.UplinkOnly)\n\n\t\tvar reader buf.Reader\n\t\tif destination.Network == net.Network_TCP {\n\t\t\treader = buf.NewReader(conn)\n\t\t} else {\n\t\t\treader = buf.NewPacketReader(conn)\n\t\t}\n\t\tif err := buf.Copy(reader, output, buf.UpdateActivity(timer)); err != nil {\n\t\t\treturn newError(\"failed to process response\").Base(err)\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tif err := task.Run(ctx, requestDone, task.OnSuccess(responseDone, task.Close(output))); err != nil {\n\t\treturn newError(\"connection ends\").Base(err)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "proxy/http/client.go",
    "content": "// +build !confonly\n\npackage http\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"encoding/base64\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"sync\"\n\n\t\"golang.org/x/net/http2\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/bytespool\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/retry\"\n\t\"v2ray.com/core/common/session\"\n\t\"v2ray.com/core/common/signal\"\n\t\"v2ray.com/core/common/task\"\n\t\"v2ray.com/core/features/policy\"\n\t\"v2ray.com/core/transport\"\n\t\"v2ray.com/core/transport/internet\"\n\t\"v2ray.com/core/transport/internet/tls\"\n)\n\ntype Client struct {\n\tserverPicker  protocol.ServerPicker\n\tpolicyManager policy.Manager\n}\n\ntype h2Conn struct {\n\trawConn net.Conn\n\th2Conn  *http2.ClientConn\n}\n\nvar (\n\tcachedH2Mutex sync.Mutex\n\tcachedH2Conns map[net.Destination]h2Conn\n)\n\n// NewClient create a new http client based on the given config.\nfunc NewClient(ctx context.Context, config *ClientConfig) (*Client, error) {\n\tserverList := protocol.NewServerList()\n\tfor _, rec := range config.Server {\n\t\ts, err := protocol.NewServerSpecFromPB(rec)\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"failed to get server spec\").Base(err)\n\t\t}\n\t\tserverList.AddServer(s)\n\t}\n\tif serverList.Size() == 0 {\n\t\treturn nil, newError(\"0 target server\")\n\t}\n\n\tv := core.MustFromContext(ctx)\n\treturn &Client{\n\t\tserverPicker:  protocol.NewRoundRobinServerPicker(serverList),\n\t\tpolicyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),\n\t}, nil\n}\n\n// Process implements proxy.Outbound.Process. We first create a socket tunnel via HTTP CONNECT method, then redirect all inbound traffic to that tunnel.\nfunc (c *Client) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {\n\toutbound := session.OutboundFromContext(ctx)\n\tif outbound == nil || !outbound.Target.IsValid() {\n\t\treturn newError(\"target not specified.\")\n\t}\n\ttarget := outbound.Target\n\ttargetAddr := target.NetAddr()\n\n\tif target.Network == net.Network_UDP {\n\t\treturn newError(\"UDP is not supported by HTTP outbound\")\n\t}\n\n\tvar user *protocol.MemoryUser\n\tvar conn internet.Connection\n\n\tmbuf, _ := link.Reader.ReadMultiBuffer()\n\tlen := mbuf.Len()\n\tfirstPayload := bytespool.Alloc(len)\n\tmbuf, _ = buf.SplitBytes(mbuf, firstPayload)\n\tfirstPayload = firstPayload[:len]\n\n\tbuf.ReleaseMulti(mbuf)\n\tdefer bytespool.Free(firstPayload)\n\n\tif err := retry.ExponentialBackoff(5, 100).On(func() error {\n\t\tserver := c.serverPicker.PickServer()\n\t\tdest := server.Destination()\n\t\tuser = server.PickUser()\n\n\t\tnetConn, err := setUpHTTPTunnel(ctx, dest, targetAddr, user, dialer, firstPayload)\n\t\tif netConn != nil {\n\t\t\tconn = internet.Connection(netConn)\n\t\t}\n\t\treturn err\n\t}); err != nil {\n\t\treturn newError(\"failed to find an available destination\").Base(err)\n\t}\n\n\tdefer func() {\n\t\tif err := conn.Close(); err != nil {\n\t\t\tnewError(\"failed to closed connection\").Base(err).WriteToLog(session.ExportIDToError(ctx))\n\t\t}\n\t}()\n\n\tp := c.policyManager.ForLevel(0)\n\tif user != nil {\n\t\tp = c.policyManager.ForLevel(user.Level)\n\t}\n\n\tctx, cancel := context.WithCancel(ctx)\n\ttimer := signal.CancelAfterInactivity(ctx, cancel, p.Timeouts.ConnectionIdle)\n\n\trequestFunc := func() error {\n\t\tdefer timer.SetTimeout(p.Timeouts.DownlinkOnly)\n\t\treturn buf.Copy(link.Reader, buf.NewWriter(conn), buf.UpdateActivity(timer))\n\t}\n\tresponseFunc := func() error {\n\t\tdefer timer.SetTimeout(p.Timeouts.UplinkOnly)\n\t\treturn buf.Copy(buf.NewReader(conn), link.Writer, buf.UpdateActivity(timer))\n\t}\n\n\tvar responseDonePost = task.OnSuccess(responseFunc, task.Close(link.Writer))\n\tif err := task.Run(ctx, requestFunc, responseDonePost); err != nil {\n\t\treturn newError(\"connection ends\").Base(err)\n\t}\n\n\treturn nil\n}\n\n// setUpHTTPTunnel will create a socket tunnel via HTTP CONNECT method\nfunc setUpHTTPTunnel(ctx context.Context, dest net.Destination, target string, user *protocol.MemoryUser, dialer internet.Dialer, firstPayload []byte) (net.Conn, error) {\n\treq := &http.Request{\n\t\tMethod: http.MethodConnect,\n\t\tURL:    &url.URL{Host: target},\n\t\tHeader: make(http.Header),\n\t\tHost:   target,\n\t}\n\n\tif user != nil && user.Account != nil {\n\t\taccount := user.Account.(*Account)\n\t\tauth := account.GetUsername() + \":\" + account.GetPassword()\n\t\treq.Header.Set(\"Proxy-Authorization\", \"Basic \"+base64.StdEncoding.EncodeToString([]byte(auth)))\n\t}\n\n\tconnectHTTP1 := func(rawConn net.Conn) (net.Conn, error) {\n\t\treq.Header.Set(\"Proxy-Connection\", \"Keep-Alive\")\n\n\t\terr := req.Write(rawConn)\n\t\tif err != nil {\n\t\t\trawConn.Close()\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif _, err := rawConn.Write(firstPayload); err != nil {\n\t\t\trawConn.Close()\n\t\t\treturn nil, err\n\t\t}\n\n\t\tresp, err := http.ReadResponse(bufio.NewReader(rawConn), req)\n\t\tif err != nil {\n\t\t\trawConn.Close()\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif resp.StatusCode != http.StatusOK {\n\t\t\trawConn.Close()\n\t\t\treturn nil, newError(\"Proxy responded with non 200 code: \" + resp.Status)\n\t\t}\n\t\treturn rawConn, nil\n\t}\n\n\tconnectHTTP2 := func(rawConn net.Conn, h2clientConn *http2.ClientConn) (net.Conn, error) {\n\t\tpr, pw := io.Pipe()\n\t\treq.Body = pr\n\n\t\tvar pErr error\n\t\tvar wg sync.WaitGroup\n\t\twg.Add(1)\n\n\t\tgo func() {\n\t\t\t_, pErr = pw.Write(firstPayload)\n\t\t\twg.Done()\n\t\t}()\n\n\t\tresp, err := h2clientConn.RoundTrip(req)\n\t\tif err != nil {\n\t\t\trawConn.Close()\n\t\t\treturn nil, err\n\t\t}\n\n\t\twg.Wait()\n\t\tif pErr != nil {\n\t\t\trawConn.Close()\n\t\t\treturn nil, pErr\n\t\t}\n\n\t\tif resp.StatusCode != http.StatusOK {\n\t\t\trawConn.Close()\n\t\t\treturn nil, newError(\"Proxy responded with non 200 code: \" + resp.Status)\n\t\t}\n\t\treturn newHTTP2Conn(rawConn, pw, resp.Body), nil\n\t}\n\n\tcachedH2Mutex.Lock()\n\tcachedConn, cachedConnFound := cachedH2Conns[dest]\n\tcachedH2Mutex.Unlock()\n\n\tif cachedConnFound {\n\t\trc, cc := cachedConn.rawConn, cachedConn.h2Conn\n\t\tif cc.CanTakeNewRequest() {\n\t\t\tproxyConn, err := connectHTTP2(rc, cc)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\treturn proxyConn, nil\n\t\t}\n\t}\n\n\trawConn, err := dialer.Dial(ctx, dest)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tiConn := rawConn\n\tif statConn, ok := iConn.(*internet.StatCouterConnection); ok {\n\t\tiConn = statConn.Connection\n\t}\n\n\tnextProto := \"\"\n\tif tlsConn, ok := iConn.(*tls.Conn); ok {\n\t\tif err := tlsConn.Handshake(); err != nil {\n\t\t\trawConn.Close()\n\t\t\treturn nil, err\n\t\t}\n\t\tnextProto = tlsConn.ConnectionState().NegotiatedProtocol\n\t}\n\n\tswitch nextProto {\n\tcase \"\", \"http/1.1\":\n\t\treturn connectHTTP1(rawConn)\n\tcase \"h2\":\n\t\tt := http2.Transport{}\n\t\th2clientConn, err := t.NewClientConn(rawConn)\n\t\tif err != nil {\n\t\t\trawConn.Close()\n\t\t\treturn nil, err\n\t\t}\n\n\t\tproxyConn, err := connectHTTP2(rawConn, h2clientConn)\n\t\tif err != nil {\n\t\t\trawConn.Close()\n\t\t\treturn nil, err\n\t\t}\n\n\t\tcachedH2Mutex.Lock()\n\t\tif cachedH2Conns == nil {\n\t\t\tcachedH2Conns = make(map[net.Destination]h2Conn)\n\t\t}\n\n\t\tcachedH2Conns[dest] = h2Conn{\n\t\t\trawConn: rawConn,\n\t\t\th2Conn:  h2clientConn,\n\t\t}\n\t\tcachedH2Mutex.Unlock()\n\n\t\treturn proxyConn, err\n\tdefault:\n\t\treturn nil, newError(\"negotiated unsupported application layer protocol: \" + nextProto)\n\t}\n}\n\nfunc newHTTP2Conn(c net.Conn, pipedReqBody *io.PipeWriter, respBody io.ReadCloser) net.Conn {\n\treturn &http2Conn{Conn: c, in: pipedReqBody, out: respBody}\n}\n\ntype http2Conn struct {\n\tnet.Conn\n\tin  *io.PipeWriter\n\tout io.ReadCloser\n}\n\nfunc (h *http2Conn) Read(p []byte) (n int, err error) {\n\treturn h.out.Read(p)\n}\n\nfunc (h *http2Conn) Write(p []byte) (n int, err error) {\n\treturn h.in.Write(p)\n}\n\nfunc (h *http2Conn) Close() error {\n\th.in.Close()\n\treturn h.out.Close()\n}\n\nfunc init() {\n\tcommon.Must(common.RegisterConfig((*ClientConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {\n\t\treturn NewClient(ctx, config.(*ClientConfig))\n\t}))\n}\n"
  },
  {
    "path": "proxy/http/config.go",
    "content": "package http\n\nimport (\n\t\"v2ray.com/core/common/protocol\"\n)\n\nfunc (a *Account) Equals(another protocol.Account) bool {\n\tif account, ok := another.(*Account); ok {\n\t\treturn a.Username == account.Username\n\t}\n\treturn false\n}\n\nfunc (a *Account) AsAccount() (protocol.Account, error) {\n\treturn a, nil\n}\n\nfunc (sc *ServerConfig) HasAccount(username, password string) bool {\n\tif sc.Accounts == nil {\n\t\treturn false\n\t}\n\n\tp, found := sc.Accounts[username]\n\tif !found {\n\t\treturn false\n\t}\n\treturn p == password\n}\n"
  },
  {
    "path": "proxy/http/config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: proxy/http/config.proto\n\npackage http\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n\tprotocol \"v2ray.com/core/common/protocol\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype Account struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tUsername string `protobuf:\"bytes,1,opt,name=username,proto3\" json:\"username,omitempty\"`\n\tPassword string `protobuf:\"bytes,2,opt,name=password,proto3\" json:\"password,omitempty\"`\n}\n\nfunc (x *Account) Reset() {\n\t*x = Account{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_proxy_http_config_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Account) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Account) ProtoMessage() {}\n\nfunc (x *Account) ProtoReflect() protoreflect.Message {\n\tmi := &file_proxy_http_config_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Account.ProtoReflect.Descriptor instead.\nfunc (*Account) Descriptor() ([]byte, []int) {\n\treturn file_proxy_http_config_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *Account) GetUsername() string {\n\tif x != nil {\n\t\treturn x.Username\n\t}\n\treturn \"\"\n}\n\nfunc (x *Account) GetPassword() string {\n\tif x != nil {\n\t\treturn x.Password\n\t}\n\treturn \"\"\n}\n\n// Config for HTTP proxy server.\ntype ServerConfig struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Deprecated: Do not use.\n\tTimeout          uint32            `protobuf:\"varint,1,opt,name=timeout,proto3\" json:\"timeout,omitempty\"`\n\tAccounts         map[string]string `protobuf:\"bytes,2,rep,name=accounts,proto3\" json:\"accounts,omitempty\" protobuf_key:\"bytes,1,opt,name=key,proto3\" protobuf_val:\"bytes,2,opt,name=value,proto3\"`\n\tAllowTransparent bool              `protobuf:\"varint,3,opt,name=allow_transparent,json=allowTransparent,proto3\" json:\"allow_transparent,omitempty\"`\n\tUserLevel        uint32            `protobuf:\"varint,4,opt,name=user_level,json=userLevel,proto3\" json:\"user_level,omitempty\"`\n}\n\nfunc (x *ServerConfig) Reset() {\n\t*x = ServerConfig{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_proxy_http_config_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *ServerConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ServerConfig) ProtoMessage() {}\n\nfunc (x *ServerConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_proxy_http_config_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ServerConfig.ProtoReflect.Descriptor instead.\nfunc (*ServerConfig) Descriptor() ([]byte, []int) {\n\treturn file_proxy_http_config_proto_rawDescGZIP(), []int{1}\n}\n\n// Deprecated: Do not use.\nfunc (x *ServerConfig) GetTimeout() uint32 {\n\tif x != nil {\n\t\treturn x.Timeout\n\t}\n\treturn 0\n}\n\nfunc (x *ServerConfig) GetAccounts() map[string]string {\n\tif x != nil {\n\t\treturn x.Accounts\n\t}\n\treturn nil\n}\n\nfunc (x *ServerConfig) GetAllowTransparent() bool {\n\tif x != nil {\n\t\treturn x.AllowTransparent\n\t}\n\treturn false\n}\n\nfunc (x *ServerConfig) GetUserLevel() uint32 {\n\tif x != nil {\n\t\treturn x.UserLevel\n\t}\n\treturn 0\n}\n\n// ClientConfig is the protobuf config for HTTP proxy client.\ntype ClientConfig struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Sever is a list of HTTP server addresses.\n\tServer []*protocol.ServerEndpoint `protobuf:\"bytes,1,rep,name=server,proto3\" json:\"server,omitempty\"`\n}\n\nfunc (x *ClientConfig) Reset() {\n\t*x = ClientConfig{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_proxy_http_config_proto_msgTypes[2]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *ClientConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ClientConfig) ProtoMessage() {}\n\nfunc (x *ClientConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_proxy_http_config_proto_msgTypes[2]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ClientConfig.ProtoReflect.Descriptor instead.\nfunc (*ClientConfig) Descriptor() ([]byte, []int) {\n\treturn file_proxy_http_config_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *ClientConfig) GetServer() []*protocol.ServerEndpoint {\n\tif x != nil {\n\t\treturn x.Server\n\t}\n\treturn nil\n}\n\nvar File_proxy_http_config_proto protoreflect.FileDescriptor\n\nvar file_proxy_http_config_proto_rawDesc = []byte{\n\t0x0a, 0x17, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x63, 0x6f, 0x6e,\n\t0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x15, 0x76, 0x32, 0x72, 0x61, 0x79,\n\t0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x68, 0x74, 0x74, 0x70,\n\t0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,\n\t0x6c, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x2e, 0x70, 0x72,\n\t0x6f, 0x74, 0x6f, 0x22, 0x41, 0x0a, 0x07, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1a,\n\t0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,\n\t0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61,\n\t0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61,\n\t0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x84, 0x02, 0x0a, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x65,\n\t0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1c, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f,\n\t0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x02, 0x18, 0x01, 0x52, 0x07, 0x74, 0x69,\n\t0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x4d, 0x0a, 0x08, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74,\n\t0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,\n\t0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x2e,\n\t0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x41, 0x63, 0x63,\n\t0x6f, 0x75, 0x6e, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x61, 0x63, 0x63, 0x6f,\n\t0x75, 0x6e, 0x74, 0x73, 0x12, 0x2b, 0x0a, 0x11, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x74, 0x72,\n\t0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52,\n\t0x10, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e,\n\t0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18,\n\t0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x4c, 0x65, 0x76, 0x65, 0x6c,\n\t0x1a, 0x3b, 0x0a, 0x0d, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72,\n\t0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,\n\t0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01,\n\t0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x52, 0x0a,\n\t0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x42, 0x0a,\n\t0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e,\n\t0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,\n\t0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65,\n\t0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65,\n\t0x72, 0x42, 0x50, 0x0a, 0x19, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,\n\t0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x50, 0x01,\n\t0x5a, 0x19, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65,\n\t0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x68, 0x74, 0x74, 0x70, 0xaa, 0x02, 0x15, 0x56, 0x32,\n\t0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x48,\n\t0x74, 0x74, 0x70, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_proxy_http_config_proto_rawDescOnce sync.Once\n\tfile_proxy_http_config_proto_rawDescData = file_proxy_http_config_proto_rawDesc\n)\n\nfunc file_proxy_http_config_proto_rawDescGZIP() []byte {\n\tfile_proxy_http_config_proto_rawDescOnce.Do(func() {\n\t\tfile_proxy_http_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_proxy_http_config_proto_rawDescData)\n\t})\n\treturn file_proxy_http_config_proto_rawDescData\n}\n\nvar file_proxy_http_config_proto_msgTypes = make([]protoimpl.MessageInfo, 4)\nvar file_proxy_http_config_proto_goTypes = []interface{}{\n\t(*Account)(nil),                 // 0: v2ray.core.proxy.http.Account\n\t(*ServerConfig)(nil),            // 1: v2ray.core.proxy.http.ServerConfig\n\t(*ClientConfig)(nil),            // 2: v2ray.core.proxy.http.ClientConfig\n\tnil,                             // 3: v2ray.core.proxy.http.ServerConfig.AccountsEntry\n\t(*protocol.ServerEndpoint)(nil), // 4: v2ray.core.common.protocol.ServerEndpoint\n}\nvar file_proxy_http_config_proto_depIdxs = []int32{\n\t3, // 0: v2ray.core.proxy.http.ServerConfig.accounts:type_name -> v2ray.core.proxy.http.ServerConfig.AccountsEntry\n\t4, // 1: v2ray.core.proxy.http.ClientConfig.server:type_name -> v2ray.core.common.protocol.ServerEndpoint\n\t2, // [2:2] is the sub-list for method output_type\n\t2, // [2:2] is the sub-list for method input_type\n\t2, // [2:2] is the sub-list for extension type_name\n\t2, // [2:2] is the sub-list for extension extendee\n\t0, // [0:2] is the sub-list for field type_name\n}\n\nfunc init() { file_proxy_http_config_proto_init() }\nfunc file_proxy_http_config_proto_init() {\n\tif File_proxy_http_config_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_proxy_http_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Account); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_proxy_http_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*ServerConfig); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_proxy_http_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*ClientConfig); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_proxy_http_config_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   4,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_proxy_http_config_proto_goTypes,\n\t\tDependencyIndexes: file_proxy_http_config_proto_depIdxs,\n\t\tMessageInfos:      file_proxy_http_config_proto_msgTypes,\n\t}.Build()\n\tFile_proxy_http_config_proto = out.File\n\tfile_proxy_http_config_proto_rawDesc = nil\n\tfile_proxy_http_config_proto_goTypes = nil\n\tfile_proxy_http_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "proxy/http/config.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.proxy.http;\noption csharp_namespace = \"V2Ray.Core.Proxy.Http\";\noption go_package = \"v2ray.com/core/proxy/http\";\noption java_package = \"com.v2ray.core.proxy.http\";\noption java_multiple_files = true;\n\nimport \"common/protocol/server_spec.proto\";\n\nmessage Account {\n  string username = 1;\n  string password = 2;\n}\n\n// Config for HTTP proxy server.\nmessage ServerConfig {\n  uint32 timeout = 1 [deprecated = true];\n  map<string, string> accounts = 2;\n  bool allow_transparent = 3;\n  uint32 user_level = 4;\n}\n\n// ClientConfig is the protobuf config for HTTP proxy client.\nmessage ClientConfig {\n  // Sever is a list of HTTP server addresses.\n  repeated v2ray.core.common.protocol.ServerEndpoint server = 1;\n}\n"
  },
  {
    "path": "proxy/http/errors.generated.go",
    "content": "package http\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "proxy/http/http.go",
    "content": "package http\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n"
  },
  {
    "path": "proxy/http/server.go",
    "content": "// +build !confonly\n\npackage http\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"encoding/base64\"\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n\t\"time\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/errors\"\n\t\"v2ray.com/core/common/log\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\thttp_proto \"v2ray.com/core/common/protocol/http\"\n\t\"v2ray.com/core/common/session\"\n\t\"v2ray.com/core/common/signal\"\n\t\"v2ray.com/core/common/task\"\n\t\"v2ray.com/core/features/policy\"\n\t\"v2ray.com/core/features/routing\"\n\t\"v2ray.com/core/transport/internet\"\n)\n\n// Server is an HTTP proxy server.\ntype Server struct {\n\tconfig        *ServerConfig\n\tpolicyManager policy.Manager\n}\n\n// NewServer creates a new HTTP inbound handler.\nfunc NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {\n\tv := core.MustFromContext(ctx)\n\ts := &Server{\n\t\tconfig:        config,\n\t\tpolicyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),\n\t}\n\n\treturn s, nil\n}\n\nfunc (s *Server) policy() policy.Session {\n\tconfig := s.config\n\tp := s.policyManager.ForLevel(config.UserLevel)\n\tif config.Timeout > 0 && config.UserLevel == 0 {\n\t\tp.Timeouts.ConnectionIdle = time.Duration(config.Timeout) * time.Second\n\t}\n\treturn p\n}\n\n// Network implements proxy.Inbound.\nfunc (*Server) Network() []net.Network {\n\treturn []net.Network{net.Network_TCP}\n}\n\nfunc isTimeout(err error) bool {\n\tnerr, ok := errors.Cause(err).(net.Error)\n\treturn ok && nerr.Timeout()\n}\n\nfunc parseBasicAuth(auth string) (username, password string, ok bool) {\n\tconst prefix = \"Basic \"\n\tif !strings.HasPrefix(auth, prefix) {\n\t\treturn\n\t}\n\tc, err := base64.StdEncoding.DecodeString(auth[len(prefix):])\n\tif err != nil {\n\t\treturn\n\t}\n\tcs := string(c)\n\ts := strings.IndexByte(cs, ':')\n\tif s < 0 {\n\t\treturn\n\t}\n\treturn cs[:s], cs[s+1:], true\n}\n\ntype readerOnly struct {\n\tio.Reader\n}\n\nfunc (s *Server) Process(ctx context.Context, network net.Network, conn internet.Connection, dispatcher routing.Dispatcher) error {\n\tinbound := session.InboundFromContext(ctx)\n\tif inbound != nil {\n\t\tinbound.User = &protocol.MemoryUser{\n\t\t\tLevel: s.config.UserLevel,\n\t\t}\n\t}\n\n\treader := bufio.NewReaderSize(readerOnly{conn}, buf.Size)\n\nStart:\n\tif err := conn.SetReadDeadline(time.Now().Add(s.policy().Timeouts.Handshake)); err != nil {\n\t\tnewError(\"failed to set read deadline\").Base(err).WriteToLog(session.ExportIDToError(ctx))\n\t}\n\n\trequest, err := http.ReadRequest(reader)\n\tif err != nil {\n\t\ttrace := newError(\"failed to read http request\").Base(err)\n\t\tif errors.Cause(err) != io.EOF && !isTimeout(errors.Cause(err)) {\n\t\t\ttrace.AtWarning() // nolint: errcheck\n\t\t}\n\t\treturn trace\n\t}\n\n\tif len(s.config.Accounts) > 0 {\n\t\tuser, pass, ok := parseBasicAuth(request.Header.Get(\"Proxy-Authorization\"))\n\t\tif !ok || !s.config.HasAccount(user, pass) {\n\t\t\treturn common.Error2(conn.Write([]byte(\"HTTP/1.1 407 Proxy Authentication Required\\r\\nProxy-Authenticate: Basic realm=\\\"proxy\\\"\\r\\nConnection: close\\r\\n\\r\\n\")))\n\t\t}\n\t\tif inbound != nil {\n\t\t\tinbound.User.Email = user\n\t\t}\n\t}\n\n\tnewError(\"request to Method [\", request.Method, \"] Host [\", request.Host, \"] with URL [\", request.URL, \"]\").WriteToLog(session.ExportIDToError(ctx))\n\tif err := conn.SetReadDeadline(time.Time{}); err != nil {\n\t\tnewError(\"failed to clear read deadline\").Base(err).WriteToLog(session.ExportIDToError(ctx))\n\t}\n\n\tdefaultPort := net.Port(80)\n\tif strings.EqualFold(request.URL.Scheme, \"https\") {\n\t\tdefaultPort = net.Port(443)\n\t}\n\thost := request.Host\n\tif host == \"\" {\n\t\thost = request.URL.Host\n\t}\n\tdest, err := http_proto.ParseHost(host, defaultPort)\n\tif err != nil {\n\t\treturn newError(\"malformed proxy host: \", host).AtWarning().Base(err)\n\t}\n\tctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{\n\t\tFrom:   conn.RemoteAddr(),\n\t\tTo:     request.URL,\n\t\tStatus: log.AccessAccepted,\n\t\tReason: \"\",\n\t})\n\n\tif strings.EqualFold(request.Method, \"CONNECT\") {\n\t\treturn s.handleConnect(ctx, request, reader, conn, dest, dispatcher)\n\t}\n\n\tkeepAlive := (strings.TrimSpace(strings.ToLower(request.Header.Get(\"Proxy-Connection\"))) == \"keep-alive\")\n\n\terr = s.handlePlainHTTP(ctx, request, conn, dest, dispatcher)\n\tif err == errWaitAnother {\n\t\tif keepAlive {\n\t\t\tgoto Start\n\t\t}\n\t\terr = nil\n\t}\n\n\treturn err\n}\n\nfunc (s *Server) handleConnect(ctx context.Context, request *http.Request, reader *bufio.Reader, conn internet.Connection, dest net.Destination, dispatcher routing.Dispatcher) error {\n\t_, err := conn.Write([]byte(\"HTTP/1.1 200 Connection established\\r\\n\\r\\n\"))\n\tif err != nil {\n\t\treturn newError(\"failed to write back OK response\").Base(err)\n\t}\n\n\tplcy := s.policy()\n\tctx, cancel := context.WithCancel(ctx)\n\ttimer := signal.CancelAfterInactivity(ctx, cancel, plcy.Timeouts.ConnectionIdle)\n\n\tctx = policy.ContextWithBufferPolicy(ctx, plcy.Buffer)\n\tlink, err := dispatcher.Dispatch(ctx, dest)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif reader.Buffered() > 0 {\n\t\tpayload, err := buf.ReadFrom(io.LimitReader(reader, int64(reader.Buffered())))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := link.Writer.WriteMultiBuffer(payload); err != nil {\n\t\t\treturn err\n\t\t}\n\t\treader = nil\n\t}\n\n\trequestDone := func() error {\n\t\tdefer timer.SetTimeout(plcy.Timeouts.DownlinkOnly)\n\n\t\treturn buf.Copy(buf.NewReader(conn), link.Writer, buf.UpdateActivity(timer))\n\t}\n\n\tresponseDone := func() error {\n\t\tdefer timer.SetTimeout(plcy.Timeouts.UplinkOnly)\n\n\t\tv2writer := buf.NewWriter(conn)\n\t\tif err := buf.Copy(link.Reader, v2writer, buf.UpdateActivity(timer)); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tvar closeWriter = task.OnSuccess(requestDone, task.Close(link.Writer))\n\tif err := task.Run(ctx, closeWriter, responseDone); err != nil {\n\t\tcommon.Interrupt(link.Reader)\n\t\tcommon.Interrupt(link.Writer)\n\t\treturn newError(\"connection ends\").Base(err)\n\t}\n\n\treturn nil\n}\n\nvar errWaitAnother = newError(\"keep alive\")\n\nfunc (s *Server) handlePlainHTTP(ctx context.Context, request *http.Request, writer io.Writer, dest net.Destination, dispatcher routing.Dispatcher) error {\n\tif !s.config.AllowTransparent && request.URL.Host == \"\" {\n\t\t// RFC 2068 (HTTP/1.1) requires URL to be absolute URL in HTTP proxy.\n\t\tresponse := &http.Response{\n\t\t\tStatus:        \"Bad Request\",\n\t\t\tStatusCode:    400,\n\t\t\tProto:         \"HTTP/1.1\",\n\t\t\tProtoMajor:    1,\n\t\t\tProtoMinor:    1,\n\t\t\tHeader:        http.Header(make(map[string][]string)),\n\t\t\tBody:          nil,\n\t\t\tContentLength: 0,\n\t\t\tClose:         true,\n\t\t}\n\t\tresponse.Header.Set(\"Proxy-Connection\", \"close\")\n\t\tresponse.Header.Set(\"Connection\", \"close\")\n\t\treturn response.Write(writer)\n\t}\n\n\tif len(request.URL.Host) > 0 {\n\t\trequest.Host = request.URL.Host\n\t}\n\thttp_proto.RemoveHopByHopHeaders(request.Header)\n\n\t// Prevent UA from being set to golang's default ones\n\tif request.Header.Get(\"User-Agent\") == \"\" {\n\t\trequest.Header.Set(\"User-Agent\", \"\")\n\t}\n\n\tcontent := &session.Content{\n\t\tProtocol: \"http/1.1\",\n\t}\n\n\tcontent.SetAttribute(\":method\", strings.ToUpper(request.Method))\n\tcontent.SetAttribute(\":path\", request.URL.Path)\n\tfor key := range request.Header {\n\t\tvalue := request.Header.Get(key)\n\t\tcontent.SetAttribute(strings.ToLower(key), value)\n\t}\n\n\tctx = session.ContextWithContent(ctx, content)\n\n\tlink, err := dispatcher.Dispatch(ctx, dest)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Plain HTTP request is not a stream. The request always finishes before response. Hense request has to be closed later.\n\tdefer common.Close(link.Writer) // nolint: errcheck\n\tvar result error = errWaitAnother\n\n\trequestDone := func() error {\n\t\trequest.Header.Set(\"Connection\", \"close\")\n\n\t\trequestWriter := buf.NewBufferedWriter(link.Writer)\n\t\tcommon.Must(requestWriter.SetBuffered(false))\n\t\tif err := request.Write(requestWriter); err != nil {\n\t\t\treturn newError(\"failed to write whole request\").Base(err).AtWarning()\n\t\t}\n\t\treturn nil\n\t}\n\n\tresponseDone := func() error {\n\t\tresponseReader := bufio.NewReaderSize(&buf.BufferedReader{Reader: link.Reader}, buf.Size)\n\t\tresponse, err := http.ReadResponse(responseReader, request)\n\t\tif err == nil {\n\t\t\thttp_proto.RemoveHopByHopHeaders(response.Header)\n\t\t\tif response.ContentLength >= 0 {\n\t\t\t\tresponse.Header.Set(\"Proxy-Connection\", \"keep-alive\")\n\t\t\t\tresponse.Header.Set(\"Connection\", \"keep-alive\")\n\t\t\t\tresponse.Header.Set(\"Keep-Alive\", \"timeout=4\")\n\t\t\t\tresponse.Close = false\n\t\t\t} else {\n\t\t\t\tresponse.Close = true\n\t\t\t\tresult = nil\n\t\t\t}\n\t\t} else {\n\t\t\tnewError(\"failed to read response from \", request.Host).Base(err).AtWarning().WriteToLog(session.ExportIDToError(ctx))\n\t\t\tresponse = &http.Response{\n\t\t\t\tStatus:        \"Service Unavailable\",\n\t\t\t\tStatusCode:    503,\n\t\t\t\tProto:         \"HTTP/1.1\",\n\t\t\t\tProtoMajor:    1,\n\t\t\t\tProtoMinor:    1,\n\t\t\t\tHeader:        http.Header(make(map[string][]string)),\n\t\t\t\tBody:          nil,\n\t\t\t\tContentLength: 0,\n\t\t\t\tClose:         true,\n\t\t\t}\n\t\t\tresponse.Header.Set(\"Connection\", \"close\")\n\t\t\tresponse.Header.Set(\"Proxy-Connection\", \"close\")\n\t\t}\n\t\tif err := response.Write(writer); err != nil {\n\t\t\treturn newError(\"failed to write response\").Base(err).AtWarning()\n\t\t}\n\t\treturn nil\n\t}\n\n\tif err := task.Run(ctx, requestDone, responseDone); err != nil {\n\t\tcommon.Interrupt(link.Reader)\n\t\tcommon.Interrupt(link.Writer)\n\t\treturn newError(\"connection ends\").Base(err)\n\t}\n\n\treturn result\n}\n\nfunc init() {\n\tcommon.Must(common.RegisterConfig((*ServerConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {\n\t\treturn NewServer(ctx, config.(*ServerConfig))\n\t}))\n}\n"
  },
  {
    "path": "proxy/mtproto/auth.go",
    "content": "package mtproto\n\nimport (\n\t\"context\"\n\t\"crypto/rand\"\n\t\"crypto/sha256\"\n\t\"io\"\n\t\"sync\"\n\n\t\"v2ray.com/core/common\"\n)\n\nconst (\n\tHeaderSize = 64\n)\n\ntype SessionContext struct {\n\tConnectionType [4]byte\n\tDataCenterID   uint16\n}\n\nfunc DefaultSessionContext() SessionContext {\n\treturn SessionContext{\n\t\tConnectionType: [4]byte{0xef, 0xef, 0xef, 0xef},\n\t\tDataCenterID:   0,\n\t}\n}\n\ntype contextKey int32\n\nconst (\n\tsessionContextKey contextKey = iota\n)\n\nfunc ContextWithSessionContext(ctx context.Context, c SessionContext) context.Context {\n\treturn context.WithValue(ctx, sessionContextKey, c)\n}\n\nfunc SessionContextFromContext(ctx context.Context) SessionContext {\n\tif c := ctx.Value(sessionContextKey); c != nil {\n\t\treturn c.(SessionContext)\n\t}\n\treturn DefaultSessionContext()\n}\n\ntype Authentication struct {\n\tHeader        [HeaderSize]byte\n\tDecodingKey   [32]byte\n\tEncodingKey   [32]byte\n\tDecodingNonce [16]byte\n\tEncodingNonce [16]byte\n}\n\nfunc (a *Authentication) DataCenterID() uint16 {\n\tx := ((int16(a.Header[61]) << 8) | int16(a.Header[60]))\n\tif x < 0 {\n\t\tx = -x\n\t}\n\treturn uint16(x) - 1\n}\n\nfunc (a *Authentication) ConnectionType() [4]byte {\n\tvar x [4]byte\n\tcopy(x[:], a.Header[56:60])\n\treturn x\n}\n\nfunc (a *Authentication) ApplySecret(b []byte) {\n\ta.DecodingKey = sha256.Sum256(append(a.DecodingKey[:], b...))\n\ta.EncodingKey = sha256.Sum256(append(a.EncodingKey[:], b...))\n}\n\nfunc generateRandomBytes(random []byte, connType [4]byte) {\n\tfor {\n\t\tcommon.Must2(rand.Read(random))\n\n\t\tif random[0] == 0xef {\n\t\t\tcontinue\n\t\t}\n\n\t\tval := (uint32(random[3]) << 24) | (uint32(random[2]) << 16) | (uint32(random[1]) << 8) | uint32(random[0])\n\t\tif val == 0x44414548 || val == 0x54534f50 || val == 0x20544547 || val == 0x4954504f || val == 0xeeeeeeee {\n\t\t\tcontinue\n\t\t}\n\n\t\tif (uint32(random[7])<<24)|(uint32(random[6])<<16)|(uint32(random[5])<<8)|uint32(random[4]) == 0x00000000 {\n\t\t\tcontinue\n\t\t}\n\n\t\tcopy(random[56:60], connType[:])\n\n\t\treturn\n\t}\n}\n\nfunc NewAuthentication(sc SessionContext) *Authentication {\n\tauth := getAuthenticationObject()\n\trandom := auth.Header[:]\n\tgenerateRandomBytes(random, sc.ConnectionType)\n\tcopy(auth.EncodingKey[:], random[8:])\n\tcopy(auth.EncodingNonce[:], random[8+32:])\n\tkeyivInverse := Inverse(random[8 : 8+32+16])\n\tcopy(auth.DecodingKey[:], keyivInverse)\n\tcopy(auth.DecodingNonce[:], keyivInverse[32:])\n\treturn auth\n}\n\nfunc ReadAuthentication(reader io.Reader) (*Authentication, error) {\n\tauth := getAuthenticationObject()\n\n\tif _, err := io.ReadFull(reader, auth.Header[:]); err != nil {\n\t\tputAuthenticationObject(auth)\n\t\treturn nil, err\n\t}\n\n\tcopy(auth.DecodingKey[:], auth.Header[8:])\n\tcopy(auth.DecodingNonce[:], auth.Header[8+32:])\n\tkeyivInverse := Inverse(auth.Header[8 : 8+32+16])\n\tcopy(auth.EncodingKey[:], keyivInverse)\n\tcopy(auth.EncodingNonce[:], keyivInverse[32:])\n\n\treturn auth, nil\n}\n\n// Inverse returns a new byte array. It is a sequence of bytes when the input is read from end to beginning.Inverse\n// Visible for testing only.\nfunc Inverse(b []byte) []byte {\n\tlenb := len(b)\n\tb2 := make([]byte, lenb)\n\tfor i, v := range b {\n\t\tb2[lenb-i-1] = v\n\t}\n\treturn b2\n}\n\nvar (\n\tauthPool = sync.Pool{\n\t\tNew: func() interface{} {\n\t\t\treturn new(Authentication)\n\t\t},\n\t}\n)\n\nfunc getAuthenticationObject() *Authentication {\n\treturn authPool.Get().(*Authentication)\n}\n\nfunc putAuthenticationObject(auth *Authentication) {\n\tauthPool.Put(auth)\n}\n"
  },
  {
    "path": "proxy/mtproto/auth_test.go",
    "content": "package mtproto_test\n\nimport (\n\t\"bytes\"\n\t\"crypto/rand\"\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\n\t\"v2ray.com/core/common\"\n\t. \"v2ray.com/core/proxy/mtproto\"\n)\n\nfunc TestInverse(t *testing.T) {\n\tconst size = 64\n\tb := make([]byte, 64)\n\tfor b[0] == b[size-1] {\n\t\tcommon.Must2(rand.Read(b))\n\t}\n\n\tbi := Inverse(b)\n\tif b[0] == bi[0] {\n\t\tt.Fatal(\"seems bytes are not inversed: \", b[0], \"vs\", bi[0])\n\t}\n\n\tbii := Inverse(bi)\n\tif r := cmp.Diff(bii, b); r != \"\" {\n\t\tt.Fatal(r)\n\t}\n}\n\nfunc TestAuthenticationReadWrite(t *testing.T) {\n\ta := NewAuthentication(DefaultSessionContext())\n\tb := bytes.NewReader(a.Header[:])\n\ta2, err := ReadAuthentication(b)\n\tcommon.Must(err)\n\n\tif r := cmp.Diff(a.EncodingKey[:], a2.DecodingKey[:]); r != \"\" {\n\t\tt.Error(\"decoding key: \", r)\n\t}\n\n\tif r := cmp.Diff(a.EncodingNonce[:], a2.DecodingNonce[:]); r != \"\" {\n\t\tt.Error(\"decoding nonce: \", r)\n\t}\n\n\tif r := cmp.Diff(a.DecodingKey[:], a2.EncodingKey[:]); r != \"\" {\n\t\tt.Error(\"encoding key: \", r)\n\t}\n\n\tif r := cmp.Diff(a.DecodingNonce[:], a2.EncodingNonce[:]); r != \"\" {\n\t\tt.Error(\"encoding nonce: \", r)\n\t}\n}\n"
  },
  {
    "path": "proxy/mtproto/client.go",
    "content": "package mtproto\n\nimport (\n\t\"context\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/crypto\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/session\"\n\t\"v2ray.com/core/common/task\"\n\t\"v2ray.com/core/transport\"\n\t\"v2ray.com/core/transport/internet\"\n)\n\ntype Client struct {\n}\n\nfunc NewClient(ctx context.Context, config *ClientConfig) (*Client, error) {\n\treturn &Client{}, nil\n}\n\nfunc (c *Client) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {\n\toutbound := session.OutboundFromContext(ctx)\n\tif outbound == nil || !outbound.Target.IsValid() {\n\t\treturn newError(\"unknown destination.\")\n\t}\n\tdest := outbound.Target\n\tif dest.Network != net.Network_TCP {\n\t\treturn newError(\"not TCP traffic\", dest)\n\t}\n\n\tconn, err := dialer.Dial(ctx, dest)\n\tif err != nil {\n\t\treturn newError(\"failed to dial to \", dest).Base(err).AtWarning()\n\t}\n\tdefer conn.Close() // nolint: errcheck\n\n\tsc := SessionContextFromContext(ctx)\n\tauth := NewAuthentication(sc)\n\tdefer putAuthenticationObject(auth)\n\n\trequest := func() error {\n\t\tencryptor := crypto.NewAesCTRStream(auth.EncodingKey[:], auth.EncodingNonce[:])\n\n\t\tvar header [HeaderSize]byte\n\t\tencryptor.XORKeyStream(header[:], auth.Header[:])\n\t\tcopy(header[:56], auth.Header[:])\n\n\t\tif _, err := conn.Write(header[:]); err != nil {\n\t\t\treturn newError(\"failed to write auth header\").Base(err)\n\t\t}\n\n\t\tconnWriter := buf.NewWriter(crypto.NewCryptionWriter(encryptor, conn))\n\t\treturn buf.Copy(link.Reader, connWriter)\n\t}\n\n\tresponse := func() error {\n\t\tdecryptor := crypto.NewAesCTRStream(auth.DecodingKey[:], auth.DecodingNonce[:])\n\n\t\tconnReader := buf.NewReader(crypto.NewCryptionReader(decryptor, conn))\n\t\treturn buf.Copy(connReader, link.Writer)\n\t}\n\n\tvar responseDoneAndCloseWriter = task.OnSuccess(response, task.Close(link.Writer))\n\tif err := task.Run(ctx, request, responseDoneAndCloseWriter); err != nil {\n\t\treturn newError(\"connection ends\").Base(err)\n\t}\n\n\treturn nil\n}\n\nfunc init() {\n\tcommon.Must(common.RegisterConfig((*ClientConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {\n\t\treturn NewClient(ctx, config.(*ClientConfig))\n\t}))\n}\n"
  },
  {
    "path": "proxy/mtproto/config.go",
    "content": "package mtproto\n\nimport (\n\t\"v2ray.com/core/common/protocol\"\n)\n\nfunc (a *Account) Equals(another protocol.Account) bool {\n\taa, ok := another.(*Account)\n\tif !ok {\n\t\treturn false\n\t}\n\n\tif len(a.Secret) != len(aa.Secret) {\n\t\treturn false\n\t}\n\n\tfor i, v := range a.Secret {\n\t\tif v != aa.Secret[i] {\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n"
  },
  {
    "path": "proxy/mtproto/config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: proxy/mtproto/config.proto\n\npackage mtproto\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n\tprotocol \"v2ray.com/core/common/protocol\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype Account struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tSecret []byte `protobuf:\"bytes,1,opt,name=secret,proto3\" json:\"secret,omitempty\"`\n}\n\nfunc (x *Account) Reset() {\n\t*x = Account{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_proxy_mtproto_config_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Account) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Account) ProtoMessage() {}\n\nfunc (x *Account) ProtoReflect() protoreflect.Message {\n\tmi := &file_proxy_mtproto_config_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Account.ProtoReflect.Descriptor instead.\nfunc (*Account) Descriptor() ([]byte, []int) {\n\treturn file_proxy_mtproto_config_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *Account) GetSecret() []byte {\n\tif x != nil {\n\t\treturn x.Secret\n\t}\n\treturn nil\n}\n\ntype ServerConfig struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// User is a list of users that allowed to connect to this inbound.\n\t// Although this is a repeated field, only the first user is effective for\n\t// now.\n\tUser []*protocol.User `protobuf:\"bytes,1,rep,name=user,proto3\" json:\"user,omitempty\"`\n}\n\nfunc (x *ServerConfig) Reset() {\n\t*x = ServerConfig{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_proxy_mtproto_config_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *ServerConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ServerConfig) ProtoMessage() {}\n\nfunc (x *ServerConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_proxy_mtproto_config_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ServerConfig.ProtoReflect.Descriptor instead.\nfunc (*ServerConfig) Descriptor() ([]byte, []int) {\n\treturn file_proxy_mtproto_config_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *ServerConfig) GetUser() []*protocol.User {\n\tif x != nil {\n\t\treturn x.User\n\t}\n\treturn nil\n}\n\ntype ClientConfig struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *ClientConfig) Reset() {\n\t*x = ClientConfig{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_proxy_mtproto_config_proto_msgTypes[2]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *ClientConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ClientConfig) ProtoMessage() {}\n\nfunc (x *ClientConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_proxy_mtproto_config_proto_msgTypes[2]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ClientConfig.ProtoReflect.Descriptor instead.\nfunc (*ClientConfig) Descriptor() ([]byte, []int) {\n\treturn file_proxy_mtproto_config_proto_rawDescGZIP(), []int{2}\n}\n\nvar File_proxy_mtproto_config_proto protoreflect.FileDescriptor\n\nvar file_proxy_mtproto_config_proto_rawDesc = []byte{\n\t0x0a, 0x1a, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x6d, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f,\n\t0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x18, 0x76, 0x32,\n\t0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x6d,\n\t0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1a, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70,\n\t0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f,\n\t0x74, 0x6f, 0x22, 0x21, 0x0a, 0x07, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x16, 0x0a,\n\t0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x73,\n\t0x65, 0x63, 0x72, 0x65, 0x74, 0x22, 0x44, 0x0a, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43,\n\t0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x34, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20,\n\t0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,\n\t0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c,\n\t0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x22, 0x0e, 0x0a, 0x0c, 0x43,\n\t0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x59, 0x0a, 0x1c, 0x63,\n\t0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72,\n\t0x6f, 0x78, 0x79, 0x2e, 0x6d, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x1c, 0x76,\n\t0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72,\n\t0x6f, 0x78, 0x79, 0x2f, 0x6d, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0xaa, 0x02, 0x18, 0x56, 0x32,\n\t0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x4d,\n\t0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_proxy_mtproto_config_proto_rawDescOnce sync.Once\n\tfile_proxy_mtproto_config_proto_rawDescData = file_proxy_mtproto_config_proto_rawDesc\n)\n\nfunc file_proxy_mtproto_config_proto_rawDescGZIP() []byte {\n\tfile_proxy_mtproto_config_proto_rawDescOnce.Do(func() {\n\t\tfile_proxy_mtproto_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_proxy_mtproto_config_proto_rawDescData)\n\t})\n\treturn file_proxy_mtproto_config_proto_rawDescData\n}\n\nvar file_proxy_mtproto_config_proto_msgTypes = make([]protoimpl.MessageInfo, 3)\nvar file_proxy_mtproto_config_proto_goTypes = []interface{}{\n\t(*Account)(nil),       // 0: v2ray.core.proxy.mtproto.Account\n\t(*ServerConfig)(nil),  // 1: v2ray.core.proxy.mtproto.ServerConfig\n\t(*ClientConfig)(nil),  // 2: v2ray.core.proxy.mtproto.ClientConfig\n\t(*protocol.User)(nil), // 3: v2ray.core.common.protocol.User\n}\nvar file_proxy_mtproto_config_proto_depIdxs = []int32{\n\t3, // 0: v2ray.core.proxy.mtproto.ServerConfig.user:type_name -> v2ray.core.common.protocol.User\n\t1, // [1:1] is the sub-list for method output_type\n\t1, // [1:1] is the sub-list for method input_type\n\t1, // [1:1] is the sub-list for extension type_name\n\t1, // [1:1] is the sub-list for extension extendee\n\t0, // [0:1] is the sub-list for field type_name\n}\n\nfunc init() { file_proxy_mtproto_config_proto_init() }\nfunc file_proxy_mtproto_config_proto_init() {\n\tif File_proxy_mtproto_config_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_proxy_mtproto_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Account); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_proxy_mtproto_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*ServerConfig); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_proxy_mtproto_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*ClientConfig); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_proxy_mtproto_config_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   3,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_proxy_mtproto_config_proto_goTypes,\n\t\tDependencyIndexes: file_proxy_mtproto_config_proto_depIdxs,\n\t\tMessageInfos:      file_proxy_mtproto_config_proto_msgTypes,\n\t}.Build()\n\tFile_proxy_mtproto_config_proto = out.File\n\tfile_proxy_mtproto_config_proto_rawDesc = nil\n\tfile_proxy_mtproto_config_proto_goTypes = nil\n\tfile_proxy_mtproto_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "proxy/mtproto/config.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.proxy.mtproto;\noption csharp_namespace = \"V2Ray.Core.Proxy.Mtproto\";\noption go_package = \"v2ray.com/core/proxy/mtproto\";\noption java_package = \"com.v2ray.core.proxy.mtproto\";\noption java_multiple_files = true;\n\nimport \"common/protocol/user.proto\";\n\nmessage Account {\n  bytes secret = 1;\n}\n\nmessage ServerConfig {\n  // User is a list of users that allowed to connect to this inbound.\n  // Although this is a repeated field, only the first user is effective for\n  // now.\n  repeated v2ray.core.common.protocol.User user = 1;\n}\n\nmessage ClientConfig {}\n"
  },
  {
    "path": "proxy/mtproto/errors.generated.go",
    "content": "package mtproto\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "proxy/mtproto/mtproto.go",
    "content": "package mtproto\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n"
  },
  {
    "path": "proxy/mtproto/server.go",
    "content": "// +build !confonly\n\npackage mtproto\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"time\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/crypto\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/session\"\n\t\"v2ray.com/core/common/signal\"\n\t\"v2ray.com/core/common/task\"\n\t\"v2ray.com/core/features/policy\"\n\t\"v2ray.com/core/features/routing\"\n\t\"v2ray.com/core/transport/internet\"\n)\n\nvar (\n\tdcList = []net.Address{\n\t\tnet.ParseAddress(\"149.154.175.50\"),\n\t\tnet.ParseAddress(\"149.154.167.51\"),\n\t\tnet.ParseAddress(\"149.154.175.100\"),\n\t\tnet.ParseAddress(\"149.154.167.91\"),\n\t\tnet.ParseAddress(\"149.154.171.5\"),\n\t}\n)\n\ntype Server struct {\n\tuser    *protocol.User\n\taccount *Account\n\tpolicy  policy.Manager\n}\n\nfunc NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {\n\tif len(config.User) == 0 {\n\t\treturn nil, newError(\"no user configured.\")\n\t}\n\n\tuser := config.User[0]\n\trawAccount, err := config.User[0].GetTypedAccount()\n\tif err != nil {\n\t\treturn nil, newError(\"invalid account\").Base(err)\n\t}\n\taccount, ok := rawAccount.(*Account)\n\tif !ok {\n\t\treturn nil, newError(\"not a MTProto account\")\n\t}\n\n\tv := core.MustFromContext(ctx)\n\n\treturn &Server{\n\t\tuser:    user,\n\t\taccount: account,\n\t\tpolicy:  v.GetFeature(policy.ManagerType()).(policy.Manager),\n\t}, nil\n}\n\nfunc (s *Server) Network() []net.Network {\n\treturn []net.Network{net.Network_TCP}\n}\n\nvar ctype1 = []byte{0xef, 0xef, 0xef, 0xef}\nvar ctype2 = []byte{0xee, 0xee, 0xee, 0xee}\n\nfunc isValidConnectionType(c [4]byte) bool {\n\tif bytes.Equal(c[:], ctype1) {\n\t\treturn true\n\t}\n\tif bytes.Equal(c[:], ctype2) {\n\t\treturn true\n\t}\n\treturn false\n}\n\nfunc (s *Server) Process(ctx context.Context, network net.Network, conn internet.Connection, dispatcher routing.Dispatcher) error {\n\tsPolicy := s.policy.ForLevel(s.user.Level)\n\n\tif err := conn.SetDeadline(time.Now().Add(sPolicy.Timeouts.Handshake)); err != nil {\n\t\tnewError(\"failed to set deadline\").Base(err).WriteToLog(session.ExportIDToError(ctx))\n\t}\n\tauth, err := ReadAuthentication(conn)\n\tif err != nil {\n\t\treturn newError(\"failed to read authentication header\").Base(err)\n\t}\n\tdefer putAuthenticationObject(auth)\n\n\tif err := conn.SetDeadline(time.Time{}); err != nil {\n\t\tnewError(\"failed to clear deadline\").Base(err).WriteToLog(session.ExportIDToError(ctx))\n\t}\n\n\tauth.ApplySecret(s.account.Secret)\n\n\tdecryptor := crypto.NewAesCTRStream(auth.DecodingKey[:], auth.DecodingNonce[:])\n\tdecryptor.XORKeyStream(auth.Header[:], auth.Header[:])\n\n\tct := auth.ConnectionType()\n\tif !isValidConnectionType(ct) {\n\t\treturn newError(\"invalid connection type: \", ct)\n\t}\n\n\tdcID := auth.DataCenterID()\n\tif dcID >= uint16(len(dcList)) {\n\t\treturn newError(\"invalid datacenter id: \", dcID)\n\t}\n\n\tdest := net.Destination{\n\t\tNetwork: net.Network_TCP,\n\t\tAddress: dcList[dcID],\n\t\tPort:    net.Port(443),\n\t}\n\n\tctx, cancel := context.WithCancel(ctx)\n\ttimer := signal.CancelAfterInactivity(ctx, cancel, sPolicy.Timeouts.ConnectionIdle)\n\tctx = policy.ContextWithBufferPolicy(ctx, sPolicy.Buffer)\n\n\tsc := SessionContext{\n\t\tConnectionType: ct,\n\t\tDataCenterID:   dcID,\n\t}\n\tctx = ContextWithSessionContext(ctx, sc)\n\n\tlink, err := dispatcher.Dispatch(ctx, dest)\n\tif err != nil {\n\t\treturn newError(\"failed to dispatch request to: \", dest).Base(err)\n\t}\n\n\trequest := func() error {\n\t\tdefer timer.SetTimeout(sPolicy.Timeouts.DownlinkOnly)\n\n\t\treader := buf.NewReader(crypto.NewCryptionReader(decryptor, conn))\n\t\treturn buf.Copy(reader, link.Writer, buf.UpdateActivity(timer))\n\t}\n\n\tresponse := func() error {\n\t\tdefer timer.SetTimeout(sPolicy.Timeouts.UplinkOnly)\n\n\t\tencryptor := crypto.NewAesCTRStream(auth.EncodingKey[:], auth.EncodingNonce[:])\n\t\twriter := buf.NewWriter(crypto.NewCryptionWriter(encryptor, conn))\n\t\treturn buf.Copy(link.Reader, writer, buf.UpdateActivity(timer))\n\t}\n\n\tvar responseDoneAndCloseWriter = task.OnSuccess(response, task.Close(link.Writer))\n\tif err := task.Run(ctx, request, responseDoneAndCloseWriter); err != nil {\n\t\tcommon.Interrupt(link.Reader)\n\t\tcommon.Interrupt(link.Writer)\n\t\treturn newError(\"connection ends\").Base(err)\n\t}\n\n\treturn nil\n}\n\nfunc init() {\n\tcommon.Must(common.RegisterConfig((*ServerConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {\n\t\treturn NewServer(ctx, config.(*ServerConfig))\n\t}))\n}\n"
  },
  {
    "path": "proxy/proxy.go",
    "content": "// Package proxy contains all proxies used by V2Ray.\n//\n// To implement an inbound or outbound proxy, one needs to do the following:\n// 1. Implement the interface(s) below.\n// 2. Register a config creator through common.RegisterConfig.\npackage proxy\n\nimport (\n\t\"context\"\n\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/features/routing\"\n\t\"v2ray.com/core/transport\"\n\t\"v2ray.com/core/transport/internet\"\n)\n\n// An Inbound processes inbound connections.\ntype Inbound interface {\n\t// Network returns a list of networks that this inbound supports. Connections with not-supported networks will not be passed into Process().\n\tNetwork() []net.Network\n\n\t// Process processes a connection of given network. If necessary, the Inbound can dispatch the connection to an Outbound.\n\tProcess(context.Context, net.Network, internet.Connection, routing.Dispatcher) error\n}\n\n// An Outbound process outbound connections.\ntype Outbound interface {\n\t// Process processes the given connection. The given dialer may be used to dial a system outbound connection.\n\tProcess(context.Context, *transport.Link, internet.Dialer) error\n}\n\n// UserManager is the interface for Inbounds and Outbounds that can manage their users.\ntype UserManager interface {\n\t// AddUser adds a new user.\n\tAddUser(context.Context, *protocol.MemoryUser) error\n\n\t// RemoveUser removes a user by email.\n\tRemoveUser(context.Context, string) error\n}\n\ntype GetInbound interface {\n\tGetInbound() Inbound\n}\n\ntype GetOutbound interface {\n\tGetOutbound() Outbound\n}\n"
  },
  {
    "path": "proxy/shadowsocks/client.go",
    "content": "// +build !confonly\n\npackage shadowsocks\n\nimport (\n\t\"context\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/retry\"\n\t\"v2ray.com/core/common/session\"\n\t\"v2ray.com/core/common/signal\"\n\t\"v2ray.com/core/common/task\"\n\t\"v2ray.com/core/features/policy\"\n\t\"v2ray.com/core/transport\"\n\t\"v2ray.com/core/transport/internet\"\n)\n\n// Client is a inbound handler for Shadowsocks protocol\ntype Client struct {\n\tserverPicker  protocol.ServerPicker\n\tpolicyManager policy.Manager\n}\n\n// NewClient create a new Shadowsocks client.\nfunc NewClient(ctx context.Context, config *ClientConfig) (*Client, error) {\n\tserverList := protocol.NewServerList()\n\tfor _, rec := range config.Server {\n\t\ts, err := protocol.NewServerSpecFromPB(rec)\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"failed to parse server spec\").Base(err)\n\t\t}\n\t\tserverList.AddServer(s)\n\t}\n\tif serverList.Size() == 0 {\n\t\treturn nil, newError(\"0 server\")\n\t}\n\n\tv := core.MustFromContext(ctx)\n\tclient := &Client{\n\t\tserverPicker:  protocol.NewRoundRobinServerPicker(serverList),\n\t\tpolicyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),\n\t}\n\treturn client, nil\n}\n\n// Process implements OutboundHandler.Process().\nfunc (c *Client) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {\n\toutbound := session.OutboundFromContext(ctx)\n\tif outbound == nil || !outbound.Target.IsValid() {\n\t\treturn newError(\"target not specified\")\n\t}\n\tdestination := outbound.Target\n\tnetwork := destination.Network\n\n\tvar server *protocol.ServerSpec\n\tvar conn internet.Connection\n\n\terr := retry.ExponentialBackoff(5, 100).On(func() error {\n\t\tserver = c.serverPicker.PickServer()\n\t\tdest := server.Destination()\n\t\tdest.Network = network\n\t\trawConn, err := dialer.Dial(ctx, dest)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tconn = rawConn\n\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\treturn newError(\"failed to find an available destination\").AtWarning().Base(err)\n\t}\n\tnewError(\"tunneling request to \", destination, \" via \", server.Destination()).WriteToLog(session.ExportIDToError(ctx))\n\n\tdefer conn.Close()\n\n\trequest := &protocol.RequestHeader{\n\t\tVersion: Version,\n\t\tAddress: destination.Address,\n\t\tPort:    destination.Port,\n\t}\n\tif destination.Network == net.Network_TCP {\n\t\trequest.Command = protocol.RequestCommandTCP\n\t} else {\n\t\trequest.Command = protocol.RequestCommandUDP\n\t}\n\n\tuser := server.PickUser()\n\t_, ok := user.Account.(*MemoryAccount)\n\tif !ok {\n\t\treturn newError(\"user account is not valid\")\n\t}\n\trequest.User = user\n\n\tsessionPolicy := c.policyManager.ForLevel(user.Level)\n\tctx, cancel := context.WithCancel(ctx)\n\ttimer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)\n\n\tif request.Command == protocol.RequestCommandTCP {\n\t\tbufferedWriter := buf.NewBufferedWriter(buf.NewWriter(conn))\n\t\tbodyWriter, err := WriteTCPRequest(request, bufferedWriter)\n\t\tif err != nil {\n\t\t\treturn newError(\"failed to write request\").Base(err)\n\t\t}\n\n\t\tif err := bufferedWriter.SetBuffered(false); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\trequestDone := func() error {\n\t\t\tdefer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)\n\t\t\treturn buf.Copy(link.Reader, bodyWriter, buf.UpdateActivity(timer))\n\t\t}\n\n\t\tresponseDone := func() error {\n\t\t\tdefer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)\n\n\t\t\tresponseReader, err := ReadTCPResponse(user, conn)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\treturn buf.Copy(responseReader, link.Writer, buf.UpdateActivity(timer))\n\t\t}\n\n\t\tvar responseDoneAndCloseWriter = task.OnSuccess(responseDone, task.Close(link.Writer))\n\t\tif err := task.Run(ctx, requestDone, responseDoneAndCloseWriter); err != nil {\n\t\t\treturn newError(\"connection ends\").Base(err)\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tif request.Command == protocol.RequestCommandUDP {\n\n\t\twriter := &buf.SequentialWriter{Writer: &UDPWriter{\n\t\t\tWriter:  conn,\n\t\t\tRequest: request,\n\t\t}}\n\n\t\trequestDone := func() error {\n\t\t\tdefer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)\n\n\t\t\tif err := buf.Copy(link.Reader, writer, buf.UpdateActivity(timer)); err != nil {\n\t\t\t\treturn newError(\"failed to transport all UDP request\").Base(err)\n\t\t\t}\n\t\t\treturn nil\n\t\t}\n\n\t\tresponseDone := func() error {\n\t\t\tdefer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)\n\n\t\t\treader := &UDPReader{\n\t\t\t\tReader: conn,\n\t\t\t\tUser:   user,\n\t\t\t}\n\n\t\t\tif err := buf.Copy(reader, link.Writer, buf.UpdateActivity(timer)); err != nil {\n\t\t\t\treturn newError(\"failed to transport all UDP response\").Base(err)\n\t\t\t}\n\t\t\treturn nil\n\t\t}\n\n\t\tvar responseDoneAndCloseWriter = task.OnSuccess(responseDone, task.Close(link.Writer))\n\t\tif err := task.Run(ctx, requestDone, responseDoneAndCloseWriter); err != nil {\n\t\t\treturn newError(\"connection ends\").Base(err)\n\t\t}\n\n\t\treturn nil\n\t}\n\n\treturn nil\n}\n\nfunc init() {\n\tcommon.Must(common.RegisterConfig((*ClientConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {\n\t\treturn NewClient(ctx, config.(*ClientConfig))\n\t}))\n}\n"
  },
  {
    "path": "proxy/shadowsocks/config.go",
    "content": "package shadowsocks\n\nimport (\n\t\"bytes\"\n\t\"crypto/aes\"\n\t\"crypto/cipher\"\n\t\"crypto/md5\"\n\t\"crypto/sha1\"\n\t\"io\"\n\n\t\"golang.org/x/crypto/chacha20poly1305\"\n\t\"golang.org/x/crypto/hkdf\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/crypto\"\n\t\"v2ray.com/core/common/protocol\"\n)\n\n// MemoryAccount is an account type converted from Account.\ntype MemoryAccount struct {\n\tCipher Cipher\n\tKey    []byte\n}\n\n// Equals implements protocol.Account.Equals().\nfunc (a *MemoryAccount) Equals(another protocol.Account) bool {\n\tif account, ok := another.(*MemoryAccount); ok {\n\t\treturn bytes.Equal(a.Key, account.Key)\n\t}\n\treturn false\n}\n\nfunc createAesGcm(key []byte) cipher.AEAD {\n\tblock, err := aes.NewCipher(key)\n\tcommon.Must(err)\n\tgcm, err := cipher.NewGCM(block)\n\tcommon.Must(err)\n\treturn gcm\n}\n\nfunc createChacha20Poly1305(key []byte) cipher.AEAD {\n\tchacha20, err := chacha20poly1305.New(key)\n\tcommon.Must(err)\n\treturn chacha20\n}\n\nfunc (a *Account) getCipher() (Cipher, error) {\n\tswitch a.CipherType {\n\tcase CipherType_AES_128_CFB:\n\t\treturn &AesCfb{KeyBytes: 16}, nil\n\tcase CipherType_AES_256_CFB:\n\t\treturn &AesCfb{KeyBytes: 32}, nil\n\tcase CipherType_CHACHA20:\n\t\treturn &ChaCha20{IVBytes: 8}, nil\n\tcase CipherType_CHACHA20_IETF:\n\t\treturn &ChaCha20{IVBytes: 12}, nil\n\tcase CipherType_AES_128_GCM:\n\t\treturn &AEADCipher{\n\t\t\tKeyBytes:        16,\n\t\t\tIVBytes:         16,\n\t\t\tAEADAuthCreator: createAesGcm,\n\t\t}, nil\n\tcase CipherType_AES_256_GCM:\n\t\treturn &AEADCipher{\n\t\t\tKeyBytes:        32,\n\t\t\tIVBytes:         32,\n\t\t\tAEADAuthCreator: createAesGcm,\n\t\t}, nil\n\tcase CipherType_CHACHA20_POLY1305:\n\t\treturn &AEADCipher{\n\t\t\tKeyBytes:        32,\n\t\t\tIVBytes:         32,\n\t\t\tAEADAuthCreator: createChacha20Poly1305,\n\t\t}, nil\n\tcase CipherType_NONE:\n\t\treturn NoneCipher{}, nil\n\tdefault:\n\t\treturn nil, newError(\"Unsupported cipher.\")\n\t}\n}\n\n// AsAccount implements protocol.AsAccount.\nfunc (a *Account) AsAccount() (protocol.Account, error) {\n\tcipher, err := a.getCipher()\n\tif err != nil {\n\t\treturn nil, newError(\"failed to get cipher\").Base(err)\n\t}\n\treturn &MemoryAccount{\n\t\tCipher: cipher,\n\t\tKey:    passwordToCipherKey([]byte(a.Password), cipher.KeySize()),\n\t}, nil\n}\n\n// Cipher is an interface for all Shadowsocks ciphers.\ntype Cipher interface {\n\tKeySize() int32\n\tIVSize() int32\n\tNewEncryptionWriter(key []byte, iv []byte, writer io.Writer) (buf.Writer, error)\n\tNewDecryptionReader(key []byte, iv []byte, reader io.Reader) (buf.Reader, error)\n\tIsAEAD() bool\n\tEncodePacket(key []byte, b *buf.Buffer) error\n\tDecodePacket(key []byte, b *buf.Buffer) error\n}\n\n// AesCfb represents all AES-CFB ciphers.\ntype AesCfb struct {\n\tKeyBytes int32\n}\n\nfunc (*AesCfb) IsAEAD() bool {\n\treturn false\n}\n\nfunc (v *AesCfb) KeySize() int32 {\n\treturn v.KeyBytes\n}\n\nfunc (v *AesCfb) IVSize() int32 {\n\treturn 16\n}\n\nfunc (v *AesCfb) NewEncryptionWriter(key []byte, iv []byte, writer io.Writer) (buf.Writer, error) {\n\tstream := crypto.NewAesEncryptionStream(key, iv)\n\treturn &buf.SequentialWriter{Writer: crypto.NewCryptionWriter(stream, writer)}, nil\n}\n\nfunc (v *AesCfb) NewDecryptionReader(key []byte, iv []byte, reader io.Reader) (buf.Reader, error) {\n\tstream := crypto.NewAesDecryptionStream(key, iv)\n\treturn &buf.SingleReader{\n\t\tReader: crypto.NewCryptionReader(stream, reader),\n\t}, nil\n}\n\nfunc (v *AesCfb) EncodePacket(key []byte, b *buf.Buffer) error {\n\tiv := b.BytesTo(v.IVSize())\n\tstream := crypto.NewAesEncryptionStream(key, iv)\n\tstream.XORKeyStream(b.BytesFrom(v.IVSize()), b.BytesFrom(v.IVSize()))\n\treturn nil\n}\n\nfunc (v *AesCfb) DecodePacket(key []byte, b *buf.Buffer) error {\n\tif b.Len() <= v.IVSize() {\n\t\treturn newError(\"insufficient data: \", b.Len())\n\t}\n\tiv := b.BytesTo(v.IVSize())\n\tstream := crypto.NewAesDecryptionStream(key, iv)\n\tstream.XORKeyStream(b.BytesFrom(v.IVSize()), b.BytesFrom(v.IVSize()))\n\tb.Advance(v.IVSize())\n\treturn nil\n}\n\ntype AEADCipher struct {\n\tKeyBytes        int32\n\tIVBytes         int32\n\tAEADAuthCreator func(key []byte) cipher.AEAD\n}\n\nfunc (*AEADCipher) IsAEAD() bool {\n\treturn true\n}\n\nfunc (c *AEADCipher) KeySize() int32 {\n\treturn c.KeyBytes\n}\n\nfunc (c *AEADCipher) IVSize() int32 {\n\treturn c.IVBytes\n}\n\nfunc (c *AEADCipher) createAuthenticator(key []byte, iv []byte) *crypto.AEADAuthenticator {\n\tnonce := crypto.GenerateInitialAEADNonce()\n\tsubkey := make([]byte, c.KeyBytes)\n\thkdfSHA1(key, iv, subkey)\n\treturn &crypto.AEADAuthenticator{\n\t\tAEAD:           c.AEADAuthCreator(subkey),\n\t\tNonceGenerator: nonce,\n\t}\n}\n\nfunc (c *AEADCipher) NewEncryptionWriter(key []byte, iv []byte, writer io.Writer) (buf.Writer, error) {\n\tauth := c.createAuthenticator(key, iv)\n\treturn crypto.NewAuthenticationWriter(auth, &crypto.AEADChunkSizeParser{\n\t\tAuth: auth,\n\t}, writer, protocol.TransferTypeStream, nil), nil\n}\n\nfunc (c *AEADCipher) NewDecryptionReader(key []byte, iv []byte, reader io.Reader) (buf.Reader, error) {\n\tauth := c.createAuthenticator(key, iv)\n\treturn crypto.NewAuthenticationReader(auth, &crypto.AEADChunkSizeParser{\n\t\tAuth: auth,\n\t}, reader, protocol.TransferTypeStream, nil), nil\n}\n\nfunc (c *AEADCipher) EncodePacket(key []byte, b *buf.Buffer) error {\n\tivLen := c.IVSize()\n\tpayloadLen := b.Len()\n\tauth := c.createAuthenticator(key, b.BytesTo(ivLen))\n\n\tb.Extend(int32(auth.Overhead()))\n\t_, err := auth.Seal(b.BytesTo(ivLen), b.BytesRange(ivLen, payloadLen))\n\treturn err\n}\n\nfunc (c *AEADCipher) DecodePacket(key []byte, b *buf.Buffer) error {\n\tif b.Len() <= c.IVSize() {\n\t\treturn newError(\"insufficient data: \", b.Len())\n\t}\n\tivLen := c.IVSize()\n\tpayloadLen := b.Len()\n\tauth := c.createAuthenticator(key, b.BytesTo(ivLen))\n\n\tbbb, err := auth.Open(b.BytesTo(ivLen), b.BytesRange(ivLen, payloadLen))\n\tif err != nil {\n\t\treturn err\n\t}\n\tb.Resize(ivLen, int32(len(bbb)))\n\treturn nil\n}\n\ntype ChaCha20 struct {\n\tIVBytes int32\n}\n\nfunc (*ChaCha20) IsAEAD() bool {\n\treturn false\n}\n\nfunc (v *ChaCha20) KeySize() int32 {\n\treturn 32\n}\n\nfunc (v *ChaCha20) IVSize() int32 {\n\treturn v.IVBytes\n}\n\nfunc (v *ChaCha20) NewEncryptionWriter(key []byte, iv []byte, writer io.Writer) (buf.Writer, error) {\n\tstream := crypto.NewChaCha20Stream(key, iv)\n\treturn &buf.SequentialWriter{Writer: crypto.NewCryptionWriter(stream, writer)}, nil\n}\n\nfunc (v *ChaCha20) NewDecryptionReader(key []byte, iv []byte, reader io.Reader) (buf.Reader, error) {\n\tstream := crypto.NewChaCha20Stream(key, iv)\n\treturn &buf.SingleReader{Reader: crypto.NewCryptionReader(stream, reader)}, nil\n}\n\nfunc (v *ChaCha20) EncodePacket(key []byte, b *buf.Buffer) error {\n\tiv := b.BytesTo(v.IVSize())\n\tstream := crypto.NewChaCha20Stream(key, iv)\n\tstream.XORKeyStream(b.BytesFrom(v.IVSize()), b.BytesFrom(v.IVSize()))\n\treturn nil\n}\n\nfunc (v *ChaCha20) DecodePacket(key []byte, b *buf.Buffer) error {\n\tif b.Len() <= v.IVSize() {\n\t\treturn newError(\"insufficient data: \", b.Len())\n\t}\n\tiv := b.BytesTo(v.IVSize())\n\tstream := crypto.NewChaCha20Stream(key, iv)\n\tstream.XORKeyStream(b.BytesFrom(v.IVSize()), b.BytesFrom(v.IVSize()))\n\tb.Advance(v.IVSize())\n\treturn nil\n}\n\ntype NoneCipher struct{}\n\nfunc (NoneCipher) KeySize() int32 { return 0 }\nfunc (NoneCipher) IVSize() int32  { return 0 }\nfunc (NoneCipher) IsAEAD() bool {\n\treturn true // to avoid OTA\n}\n\nfunc (NoneCipher) NewDecryptionReader(key []byte, iv []byte, reader io.Reader) (buf.Reader, error) {\n\treturn buf.NewReader(reader), nil\n}\n\nfunc (NoneCipher) NewEncryptionWriter(key []byte, iv []byte, writer io.Writer) (buf.Writer, error) {\n\treturn buf.NewWriter(writer), nil\n}\n\nfunc (NoneCipher) EncodePacket(key []byte, b *buf.Buffer) error {\n\treturn nil\n}\n\nfunc (NoneCipher) DecodePacket(key []byte, b *buf.Buffer) error {\n\treturn nil\n}\n\nfunc passwordToCipherKey(password []byte, keySize int32) []byte {\n\tkey := make([]byte, 0, keySize)\n\n\tmd5Sum := md5.Sum(password)\n\tkey = append(key, md5Sum[:]...)\n\n\tfor int32(len(key)) < keySize {\n\t\tmd5Hash := md5.New()\n\t\tcommon.Must2(md5Hash.Write(md5Sum[:]))\n\t\tcommon.Must2(md5Hash.Write(password))\n\t\tmd5Hash.Sum(md5Sum[:0])\n\n\t\tkey = append(key, md5Sum[:]...)\n\t}\n\treturn key\n}\n\nfunc hkdfSHA1(secret, salt, outkey []byte) {\n\tr := hkdf.New(sha1.New, secret, salt, []byte(\"ss-subkey\"))\n\tcommon.Must2(io.ReadFull(r, outkey))\n}\n"
  },
  {
    "path": "proxy/shadowsocks/config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: proxy/shadowsocks/config.proto\n\npackage shadowsocks\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n\tnet \"v2ray.com/core/common/net\"\n\tprotocol \"v2ray.com/core/common/protocol\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype CipherType int32\n\nconst (\n\tCipherType_UNKNOWN           CipherType = 0\n\tCipherType_AES_128_CFB       CipherType = 1\n\tCipherType_AES_256_CFB       CipherType = 2\n\tCipherType_CHACHA20          CipherType = 3\n\tCipherType_CHACHA20_IETF     CipherType = 4\n\tCipherType_AES_128_GCM       CipherType = 5\n\tCipherType_AES_256_GCM       CipherType = 6\n\tCipherType_CHACHA20_POLY1305 CipherType = 7\n\tCipherType_NONE              CipherType = 8\n)\n\n// Enum value maps for CipherType.\nvar (\n\tCipherType_name = map[int32]string{\n\t\t0: \"UNKNOWN\",\n\t\t1: \"AES_128_CFB\",\n\t\t2: \"AES_256_CFB\",\n\t\t3: \"CHACHA20\",\n\t\t4: \"CHACHA20_IETF\",\n\t\t5: \"AES_128_GCM\",\n\t\t6: \"AES_256_GCM\",\n\t\t7: \"CHACHA20_POLY1305\",\n\t\t8: \"NONE\",\n\t}\n\tCipherType_value = map[string]int32{\n\t\t\"UNKNOWN\":           0,\n\t\t\"AES_128_CFB\":       1,\n\t\t\"AES_256_CFB\":       2,\n\t\t\"CHACHA20\":          3,\n\t\t\"CHACHA20_IETF\":     4,\n\t\t\"AES_128_GCM\":       5,\n\t\t\"AES_256_GCM\":       6,\n\t\t\"CHACHA20_POLY1305\": 7,\n\t\t\"NONE\":              8,\n\t}\n)\n\nfunc (x CipherType) Enum() *CipherType {\n\tp := new(CipherType)\n\t*p = x\n\treturn p\n}\n\nfunc (x CipherType) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (CipherType) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_proxy_shadowsocks_config_proto_enumTypes[0].Descriptor()\n}\n\nfunc (CipherType) Type() protoreflect.EnumType {\n\treturn &file_proxy_shadowsocks_config_proto_enumTypes[0]\n}\n\nfunc (x CipherType) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use CipherType.Descriptor instead.\nfunc (CipherType) EnumDescriptor() ([]byte, []int) {\n\treturn file_proxy_shadowsocks_config_proto_rawDescGZIP(), []int{0}\n}\n\ntype Account struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tPassword   string     `protobuf:\"bytes,1,opt,name=password,proto3\" json:\"password,omitempty\"`\n\tCipherType CipherType `protobuf:\"varint,2,opt,name=cipher_type,json=cipherType,proto3,enum=v2ray.core.proxy.shadowsocks.CipherType\" json:\"cipher_type,omitempty\"`\n}\n\nfunc (x *Account) Reset() {\n\t*x = Account{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_proxy_shadowsocks_config_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Account) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Account) ProtoMessage() {}\n\nfunc (x *Account) ProtoReflect() protoreflect.Message {\n\tmi := &file_proxy_shadowsocks_config_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Account.ProtoReflect.Descriptor instead.\nfunc (*Account) Descriptor() ([]byte, []int) {\n\treturn file_proxy_shadowsocks_config_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *Account) GetPassword() string {\n\tif x != nil {\n\t\treturn x.Password\n\t}\n\treturn \"\"\n}\n\nfunc (x *Account) GetCipherType() CipherType {\n\tif x != nil {\n\t\treturn x.CipherType\n\t}\n\treturn CipherType_UNKNOWN\n}\n\ntype ServerConfig struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// UdpEnabled specified whether or not to enable UDP for Shadowsocks.\n\t// Deprecated. Use 'network' field.\n\t//\n\t// Deprecated: Do not use.\n\tUdpEnabled bool           `protobuf:\"varint,1,opt,name=udp_enabled,json=udpEnabled,proto3\" json:\"udp_enabled,omitempty\"`\n\tUser       *protocol.User `protobuf:\"bytes,2,opt,name=user,proto3\" json:\"user,omitempty\"`\n\tNetwork    []net.Network  `protobuf:\"varint,3,rep,packed,name=network,proto3,enum=v2ray.core.common.net.Network\" json:\"network,omitempty\"`\n}\n\nfunc (x *ServerConfig) Reset() {\n\t*x = ServerConfig{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_proxy_shadowsocks_config_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *ServerConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ServerConfig) ProtoMessage() {}\n\nfunc (x *ServerConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_proxy_shadowsocks_config_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ServerConfig.ProtoReflect.Descriptor instead.\nfunc (*ServerConfig) Descriptor() ([]byte, []int) {\n\treturn file_proxy_shadowsocks_config_proto_rawDescGZIP(), []int{1}\n}\n\n// Deprecated: Do not use.\nfunc (x *ServerConfig) GetUdpEnabled() bool {\n\tif x != nil {\n\t\treturn x.UdpEnabled\n\t}\n\treturn false\n}\n\nfunc (x *ServerConfig) GetUser() *protocol.User {\n\tif x != nil {\n\t\treturn x.User\n\t}\n\treturn nil\n}\n\nfunc (x *ServerConfig) GetNetwork() []net.Network {\n\tif x != nil {\n\t\treturn x.Network\n\t}\n\treturn nil\n}\n\ntype ClientConfig struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tServer []*protocol.ServerEndpoint `protobuf:\"bytes,1,rep,name=server,proto3\" json:\"server,omitempty\"`\n}\n\nfunc (x *ClientConfig) Reset() {\n\t*x = ClientConfig{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_proxy_shadowsocks_config_proto_msgTypes[2]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *ClientConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ClientConfig) ProtoMessage() {}\n\nfunc (x *ClientConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_proxy_shadowsocks_config_proto_msgTypes[2]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ClientConfig.ProtoReflect.Descriptor instead.\nfunc (*ClientConfig) Descriptor() ([]byte, []int) {\n\treturn file_proxy_shadowsocks_config_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *ClientConfig) GetServer() []*protocol.ServerEndpoint {\n\tif x != nil {\n\t\treturn x.Server\n\t}\n\treturn nil\n}\n\nvar File_proxy_shadowsocks_config_proto protoreflect.FileDescriptor\n\nvar file_proxy_shadowsocks_config_proto_rawDesc = []byte{\n\t0x0a, 0x1e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x73, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x73, 0x6f,\n\t0x63, 0x6b, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,\n\t0x12, 0x1c, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f,\n\t0x78, 0x79, 0x2e, 0x73, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0x1a, 0x18,\n\t0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x6e, 0x65, 0x74, 0x77, 0x6f,\n\t0x72, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1a, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,\n\t0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70,\n\t0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f,\n\t0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x70, 0x65,\n\t0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x70, 0x0a, 0x07, 0x41, 0x63, 0x63, 0x6f, 0x75,\n\t0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01,\n\t0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x49,\n\t0x0a, 0x0b, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20,\n\t0x01, 0x28, 0x0e, 0x32, 0x28, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,\n\t0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x73, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x73, 0x6f, 0x63,\n\t0x6b, 0x73, 0x2e, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x63,\n\t0x69, 0x70, 0x68, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x22, 0xa3, 0x01, 0x0a, 0x0c, 0x53, 0x65,\n\t0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x23, 0x0a, 0x0b, 0x75, 0x64,\n\t0x70, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x42,\n\t0x02, 0x18, 0x01, 0x52, 0x0a, 0x75, 0x64, 0x70, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12,\n\t0x34, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e,\n\t0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,\n\t0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52,\n\t0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x38, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b,\n\t0x18, 0x03, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,\n\t0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4e,\n\t0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x22,\n\t0x52, 0x0a, 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,\n\t0x42, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,\n\t0x2a, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d,\n\t0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x72,\n\t0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x73, 0x65, 0x72,\n\t0x76, 0x65, 0x72, 0x2a, 0x9f, 0x01, 0x0a, 0x0a, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, 0x54, 0x79,\n\t0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12,\n\t0x0f, 0x0a, 0x0b, 0x41, 0x45, 0x53, 0x5f, 0x31, 0x32, 0x38, 0x5f, 0x43, 0x46, 0x42, 0x10, 0x01,\n\t0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x45, 0x53, 0x5f, 0x32, 0x35, 0x36, 0x5f, 0x43, 0x46, 0x42, 0x10,\n\t0x02, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x48, 0x41, 0x43, 0x48, 0x41, 0x32, 0x30, 0x10, 0x03, 0x12,\n\t0x11, 0x0a, 0x0d, 0x43, 0x48, 0x41, 0x43, 0x48, 0x41, 0x32, 0x30, 0x5f, 0x49, 0x45, 0x54, 0x46,\n\t0x10, 0x04, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x45, 0x53, 0x5f, 0x31, 0x32, 0x38, 0x5f, 0x47, 0x43,\n\t0x4d, 0x10, 0x05, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x45, 0x53, 0x5f, 0x32, 0x35, 0x36, 0x5f, 0x47,\n\t0x43, 0x4d, 0x10, 0x06, 0x12, 0x15, 0x0a, 0x11, 0x43, 0x48, 0x41, 0x43, 0x48, 0x41, 0x32, 0x30,\n\t0x5f, 0x50, 0x4f, 0x4c, 0x59, 0x31, 0x33, 0x30, 0x35, 0x10, 0x07, 0x12, 0x08, 0x0a, 0x04, 0x4e,\n\t0x4f, 0x4e, 0x45, 0x10, 0x08, 0x42, 0x65, 0x0a, 0x20, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72,\n\t0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x73, 0x68,\n\t0x61, 0x64, 0x6f, 0x77, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0x50, 0x01, 0x5a, 0x20, 0x76, 0x32, 0x72,\n\t0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78,\n\t0x79, 0x2f, 0x73, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0xaa, 0x02, 0x1c,\n\t0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79,\n\t0x2e, 0x53, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0x62, 0x06, 0x70, 0x72,\n\t0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_proxy_shadowsocks_config_proto_rawDescOnce sync.Once\n\tfile_proxy_shadowsocks_config_proto_rawDescData = file_proxy_shadowsocks_config_proto_rawDesc\n)\n\nfunc file_proxy_shadowsocks_config_proto_rawDescGZIP() []byte {\n\tfile_proxy_shadowsocks_config_proto_rawDescOnce.Do(func() {\n\t\tfile_proxy_shadowsocks_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_proxy_shadowsocks_config_proto_rawDescData)\n\t})\n\treturn file_proxy_shadowsocks_config_proto_rawDescData\n}\n\nvar file_proxy_shadowsocks_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1)\nvar file_proxy_shadowsocks_config_proto_msgTypes = make([]protoimpl.MessageInfo, 3)\nvar file_proxy_shadowsocks_config_proto_goTypes = []interface{}{\n\t(CipherType)(0),                 // 0: v2ray.core.proxy.shadowsocks.CipherType\n\t(*Account)(nil),                 // 1: v2ray.core.proxy.shadowsocks.Account\n\t(*ServerConfig)(nil),            // 2: v2ray.core.proxy.shadowsocks.ServerConfig\n\t(*ClientConfig)(nil),            // 3: v2ray.core.proxy.shadowsocks.ClientConfig\n\t(*protocol.User)(nil),           // 4: v2ray.core.common.protocol.User\n\t(net.Network)(0),                // 5: v2ray.core.common.net.Network\n\t(*protocol.ServerEndpoint)(nil), // 6: v2ray.core.common.protocol.ServerEndpoint\n}\nvar file_proxy_shadowsocks_config_proto_depIdxs = []int32{\n\t0, // 0: v2ray.core.proxy.shadowsocks.Account.cipher_type:type_name -> v2ray.core.proxy.shadowsocks.CipherType\n\t4, // 1: v2ray.core.proxy.shadowsocks.ServerConfig.user:type_name -> v2ray.core.common.protocol.User\n\t5, // 2: v2ray.core.proxy.shadowsocks.ServerConfig.network:type_name -> v2ray.core.common.net.Network\n\t6, // 3: v2ray.core.proxy.shadowsocks.ClientConfig.server:type_name -> v2ray.core.common.protocol.ServerEndpoint\n\t4, // [4:4] is the sub-list for method output_type\n\t4, // [4:4] is the sub-list for method input_type\n\t4, // [4:4] is the sub-list for extension type_name\n\t4, // [4:4] is the sub-list for extension extendee\n\t0, // [0:4] is the sub-list for field type_name\n}\n\nfunc init() { file_proxy_shadowsocks_config_proto_init() }\nfunc file_proxy_shadowsocks_config_proto_init() {\n\tif File_proxy_shadowsocks_config_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_proxy_shadowsocks_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Account); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_proxy_shadowsocks_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*ServerConfig); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_proxy_shadowsocks_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*ClientConfig); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_proxy_shadowsocks_config_proto_rawDesc,\n\t\t\tNumEnums:      1,\n\t\t\tNumMessages:   3,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_proxy_shadowsocks_config_proto_goTypes,\n\t\tDependencyIndexes: file_proxy_shadowsocks_config_proto_depIdxs,\n\t\tEnumInfos:         file_proxy_shadowsocks_config_proto_enumTypes,\n\t\tMessageInfos:      file_proxy_shadowsocks_config_proto_msgTypes,\n\t}.Build()\n\tFile_proxy_shadowsocks_config_proto = out.File\n\tfile_proxy_shadowsocks_config_proto_rawDesc = nil\n\tfile_proxy_shadowsocks_config_proto_goTypes = nil\n\tfile_proxy_shadowsocks_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "proxy/shadowsocks/config.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.proxy.shadowsocks;\noption csharp_namespace = \"V2Ray.Core.Proxy.Shadowsocks\";\noption go_package = \"v2ray.com/core/proxy/shadowsocks\";\noption java_package = \"com.v2ray.core.proxy.shadowsocks\";\noption java_multiple_files = true;\n\nimport \"common/net/network.proto\";\nimport \"common/protocol/user.proto\";\nimport \"common/protocol/server_spec.proto\";\n\nmessage Account {\n  string password = 1;\n  CipherType cipher_type = 2;\n}\n\nenum CipherType {\n  UNKNOWN = 0;\n  AES_128_CFB = 1;\n  AES_256_CFB = 2;\n  CHACHA20 = 3;\n  CHACHA20_IETF = 4;\n  AES_128_GCM = 5;\n  AES_256_GCM = 6;\n  CHACHA20_POLY1305 = 7;\n  NONE = 8;\n}\n\nmessage ServerConfig {\n  // UdpEnabled specified whether or not to enable UDP for Shadowsocks.\n  // Deprecated. Use 'network' field.\n  bool udp_enabled = 1 [deprecated = true];\n  v2ray.core.common.protocol.User user = 2;\n  repeated v2ray.core.common.net.Network network = 3;\n}\n\nmessage ClientConfig {\n  repeated v2ray.core.common.protocol.ServerEndpoint server = 1;\n}\n"
  },
  {
    "path": "proxy/shadowsocks/config_test.go",
    "content": "package shadowsocks_test\n\nimport (\n\t\"crypto/rand\"\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/proxy/shadowsocks\"\n)\n\nfunc TestAEADCipherUDP(t *testing.T) {\n\trawAccount := &shadowsocks.Account{\n\t\tCipherType: shadowsocks.CipherType_AES_128_GCM,\n\t\tPassword:   \"test\",\n\t}\n\taccount, err := rawAccount.AsAccount()\n\tcommon.Must(err)\n\n\tcipher := account.(*shadowsocks.MemoryAccount).Cipher\n\n\tkey := make([]byte, cipher.KeySize())\n\tcommon.Must2(rand.Read(key))\n\n\tpayload := make([]byte, 1024)\n\tcommon.Must2(rand.Read(payload))\n\n\tb1 := buf.New()\n\tcommon.Must2(b1.ReadFullFrom(rand.Reader, cipher.IVSize()))\n\tcommon.Must2(b1.Write(payload))\n\tcommon.Must(cipher.EncodePacket(key, b1))\n\n\tcommon.Must(cipher.DecodePacket(key, b1))\n\tif diff := cmp.Diff(b1.Bytes(), payload); diff != \"\" {\n\t\tt.Error(diff)\n\t}\n}\n"
  },
  {
    "path": "proxy/shadowsocks/errors.generated.go",
    "content": "package shadowsocks\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "proxy/shadowsocks/protocol.go",
    "content": "// +build !confonly\n\npackage shadowsocks\n\nimport (\n\t\"crypto/hmac\"\n\t\"crypto/rand\"\n\t\"crypto/sha256\"\n\t\"hash\"\n\t\"hash/crc32\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"v2ray.com/core/common/dice\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n)\n\nconst (\n\tVersion = 1\n)\n\nvar addrParser = protocol.NewAddressParser(\n\tprotocol.AddressFamilyByte(0x01, net.AddressFamilyIPv4),\n\tprotocol.AddressFamilyByte(0x04, net.AddressFamilyIPv6),\n\tprotocol.AddressFamilyByte(0x03, net.AddressFamilyDomain),\n\tprotocol.WithAddressTypeParser(func(b byte) byte {\n\t\treturn b & 0x0F\n\t}),\n)\n\n// ReadTCPSession reads a Shadowsocks TCP session from the given reader, returns its header and remaining parts.\nfunc ReadTCPSession(user *protocol.MemoryUser, reader io.Reader) (*protocol.RequestHeader, buf.Reader, error) {\n\taccount := user.Account.(*MemoryAccount)\n\n\thashkdf := hmac.New(func() hash.Hash { return sha256.New() }, []byte(\"SSBSKDF\"))\n\thashkdf.Write(account.Key)\n\n\tbehaviorSeed := crc32.ChecksumIEEE(hashkdf.Sum(nil))\n\n\tbehaviorRand := dice.NewDeterministicDice(int64(behaviorSeed))\n\tBaseDrainSize := behaviorRand.Roll(3266)\n\tRandDrainMax := behaviorRand.Roll(64) + 1\n\tRandDrainRolled := dice.Roll(RandDrainMax)\n\tDrainSize := BaseDrainSize + 16 + 38 + RandDrainRolled\n\treadSizeRemain := DrainSize\n\n\tbuffer := buf.New()\n\tdefer buffer.Release()\n\n\tivLen := account.Cipher.IVSize()\n\tvar iv []byte\n\tif ivLen > 0 {\n\t\tif _, err := buffer.ReadFullFrom(reader, ivLen); err != nil {\n\t\t\treadSizeRemain -= int(buffer.Len())\n\t\t\tDrainConnN(reader, readSizeRemain)\n\t\t\treturn nil, nil, newError(\"failed to read IV\").Base(err)\n\t\t}\n\n\t\tiv = append([]byte(nil), buffer.BytesTo(ivLen)...)\n\t}\n\n\tr, err := account.Cipher.NewDecryptionReader(account.Key, iv, reader)\n\tif err != nil {\n\t\treadSizeRemain -= int(buffer.Len())\n\t\tDrainConnN(reader, readSizeRemain)\n\t\treturn nil, nil, newError(\"failed to initialize decoding stream\").Base(err).AtError()\n\t}\n\tbr := &buf.BufferedReader{Reader: r}\n\n\trequest := &protocol.RequestHeader{\n\t\tVersion: Version,\n\t\tUser:    user,\n\t\tCommand: protocol.RequestCommandTCP,\n\t}\n\n\treadSizeRemain -= int(buffer.Len())\n\tbuffer.Clear()\n\n\taddr, port, err := addrParser.ReadAddressPort(buffer, br)\n\tif err != nil {\n\t\treadSizeRemain -= int(buffer.Len())\n\t\tDrainConnN(reader, readSizeRemain)\n\t\treturn nil, nil, newError(\"failed to read address\").Base(err)\n\t}\n\n\trequest.Address = addr\n\trequest.Port = port\n\n\tif request.Address == nil {\n\t\treadSizeRemain -= int(buffer.Len())\n\t\tDrainConnN(reader, readSizeRemain)\n\t\treturn nil, nil, newError(\"invalid remote address.\")\n\t}\n\n\treturn request, br, nil\n}\n\nfunc DrainConnN(reader io.Reader, n int) error {\n\t_, err := io.CopyN(ioutil.Discard, reader, int64(n))\n\treturn err\n}\n\n// WriteTCPRequest writes Shadowsocks request into the given writer, and returns a writer for body.\nfunc WriteTCPRequest(request *protocol.RequestHeader, writer io.Writer) (buf.Writer, error) {\n\tuser := request.User\n\taccount := user.Account.(*MemoryAccount)\n\n\tvar iv []byte\n\tif account.Cipher.IVSize() > 0 {\n\t\tiv = make([]byte, account.Cipher.IVSize())\n\t\tcommon.Must2(rand.Read(iv))\n\t\tif err := buf.WriteAllBytes(writer, iv); err != nil {\n\t\t\treturn nil, newError(\"failed to write IV\")\n\t\t}\n\t}\n\n\tw, err := account.Cipher.NewEncryptionWriter(account.Key, iv, writer)\n\tif err != nil {\n\t\treturn nil, newError(\"failed to create encoding stream\").Base(err).AtError()\n\t}\n\n\theader := buf.New()\n\n\tif err := addrParser.WriteAddressPort(header, request.Address, request.Port); err != nil {\n\t\treturn nil, newError(\"failed to write address\").Base(err)\n\t}\n\n\tif err := w.WriteMultiBuffer(buf.MultiBuffer{header}); err != nil {\n\t\treturn nil, newError(\"failed to write header\").Base(err)\n\t}\n\n\treturn w, nil\n}\n\nfunc ReadTCPResponse(user *protocol.MemoryUser, reader io.Reader) (buf.Reader, error) {\n\taccount := user.Account.(*MemoryAccount)\n\n\tvar iv []byte\n\tif account.Cipher.IVSize() > 0 {\n\t\tiv = make([]byte, account.Cipher.IVSize())\n\t\tif _, err := io.ReadFull(reader, iv); err != nil {\n\t\t\treturn nil, newError(\"failed to read IV\").Base(err)\n\t\t}\n\t}\n\n\treturn account.Cipher.NewDecryptionReader(account.Key, iv, reader)\n}\n\nfunc WriteTCPResponse(request *protocol.RequestHeader, writer io.Writer) (buf.Writer, error) {\n\tuser := request.User\n\taccount := user.Account.(*MemoryAccount)\n\n\tvar iv []byte\n\tif account.Cipher.IVSize() > 0 {\n\t\tiv = make([]byte, account.Cipher.IVSize())\n\t\tcommon.Must2(rand.Read(iv))\n\t\tif err := buf.WriteAllBytes(writer, iv); err != nil {\n\t\t\treturn nil, newError(\"failed to write IV.\").Base(err)\n\t\t}\n\t}\n\n\treturn account.Cipher.NewEncryptionWriter(account.Key, iv, writer)\n}\n\nfunc EncodeUDPPacket(request *protocol.RequestHeader, payload []byte) (*buf.Buffer, error) {\n\tuser := request.User\n\taccount := user.Account.(*MemoryAccount)\n\n\tbuffer := buf.New()\n\tivLen := account.Cipher.IVSize()\n\tif ivLen > 0 {\n\t\tcommon.Must2(buffer.ReadFullFrom(rand.Reader, ivLen))\n\t}\n\n\tif err := addrParser.WriteAddressPort(buffer, request.Address, request.Port); err != nil {\n\t\treturn nil, newError(\"failed to write address\").Base(err)\n\t}\n\n\tbuffer.Write(payload)\n\n\tif err := account.Cipher.EncodePacket(account.Key, buffer); err != nil {\n\t\treturn nil, newError(\"failed to encrypt UDP payload\").Base(err)\n\t}\n\n\treturn buffer, nil\n}\n\nfunc DecodeUDPPacket(user *protocol.MemoryUser, payload *buf.Buffer) (*protocol.RequestHeader, *buf.Buffer, error) {\n\taccount := user.Account.(*MemoryAccount)\n\n\tvar iv []byte\n\tif !account.Cipher.IsAEAD() && account.Cipher.IVSize() > 0 {\n\t\t// Keep track of IV as it gets removed from payload in DecodePacket.\n\t\tiv = make([]byte, account.Cipher.IVSize())\n\t\tcopy(iv, payload.BytesTo(account.Cipher.IVSize()))\n\t}\n\n\tif err := account.Cipher.DecodePacket(account.Key, payload); err != nil {\n\t\treturn nil, nil, newError(\"failed to decrypt UDP payload\").Base(err)\n\t}\n\n\trequest := &protocol.RequestHeader{\n\t\tVersion: Version,\n\t\tUser:    user,\n\t\tCommand: protocol.RequestCommandUDP,\n\t}\n\n\tpayload.SetByte(0, payload.Byte(0)&0x0F)\n\n\taddr, port, err := addrParser.ReadAddressPort(nil, payload)\n\tif err != nil {\n\t\treturn nil, nil, newError(\"failed to parse address\").Base(err)\n\t}\n\n\trequest.Address = addr\n\trequest.Port = port\n\n\treturn request, payload, nil\n}\n\ntype UDPReader struct {\n\tReader io.Reader\n\tUser   *protocol.MemoryUser\n}\n\nfunc (v *UDPReader) ReadMultiBuffer() (buf.MultiBuffer, error) {\n\tbuffer := buf.New()\n\t_, err := buffer.ReadFrom(v.Reader)\n\tif err != nil {\n\t\tbuffer.Release()\n\t\treturn nil, err\n\t}\n\t_, payload, err := DecodeUDPPacket(v.User, buffer)\n\tif err != nil {\n\t\tbuffer.Release()\n\t\treturn nil, err\n\t}\n\treturn buf.MultiBuffer{payload}, nil\n}\n\ntype UDPWriter struct {\n\tWriter  io.Writer\n\tRequest *protocol.RequestHeader\n}\n\n// Write implements io.Writer.\nfunc (w *UDPWriter) Write(payload []byte) (int, error) {\n\tpacket, err := EncodeUDPPacket(w.Request, payload)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\t_, err = w.Writer.Write(packet.Bytes())\n\tpacket.Release()\n\treturn len(payload), err\n}\n"
  },
  {
    "path": "proxy/shadowsocks/protocol_test.go",
    "content": "package shadowsocks_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t. \"v2ray.com/core/proxy/shadowsocks\"\n)\n\nfunc toAccount(a *Account) protocol.Account {\n\taccount, err := a.AsAccount()\n\tcommon.Must(err)\n\treturn account\n}\n\nfunc TestUDPEncoding(t *testing.T) {\n\trequest := &protocol.RequestHeader{\n\t\tVersion: Version,\n\t\tCommand: protocol.RequestCommandUDP,\n\t\tAddress: net.LocalHostIP,\n\t\tPort:    1234,\n\t\tUser: &protocol.MemoryUser{\n\t\t\tEmail: \"love@v2ray.com\",\n\t\t\tAccount: toAccount(&Account{\n\t\t\t\tPassword:   \"shadowsocks-password\",\n\t\t\t\tCipherType: CipherType_AES_128_CFB,\n\t\t\t}),\n\t\t},\n\t}\n\n\tdata := buf.New()\n\tcommon.Must2(data.WriteString(\"test string\"))\n\tencodedData, err := EncodeUDPPacket(request, data.Bytes())\n\tcommon.Must(err)\n\n\tdecodedRequest, decodedData, err := DecodeUDPPacket(request.User, encodedData)\n\tcommon.Must(err)\n\n\tif r := cmp.Diff(decodedData.Bytes(), data.Bytes()); r != \"\" {\n\t\tt.Error(\"data: \", r)\n\t}\n\n\tif r := cmp.Diff(decodedRequest, request); r != \"\" {\n\t\tt.Error(\"request: \", r)\n\t}\n}\n\nfunc TestTCPRequest(t *testing.T) {\n\tcases := []struct {\n\t\trequest *protocol.RequestHeader\n\t\tpayload []byte\n\t}{\n\t\t{\n\t\t\trequest: &protocol.RequestHeader{\n\t\t\t\tVersion: Version,\n\t\t\t\tCommand: protocol.RequestCommandTCP,\n\t\t\t\tAddress: net.LocalHostIP,\n\t\t\t\tPort:    1234,\n\t\t\t\tUser: &protocol.MemoryUser{\n\t\t\t\t\tEmail: \"love@v2ray.com\",\n\t\t\t\t\tAccount: toAccount(&Account{\n\t\t\t\t\t\tPassword:   \"tcp-password\",\n\t\t\t\t\t\tCipherType: CipherType_CHACHA20,\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t},\n\t\t\tpayload: []byte(\"test string\"),\n\t\t},\n\t\t{\n\t\t\trequest: &protocol.RequestHeader{\n\t\t\t\tVersion: Version,\n\t\t\t\tCommand: protocol.RequestCommandTCP,\n\t\t\t\tAddress: net.LocalHostIPv6,\n\t\t\t\tPort:    1234,\n\t\t\t\tUser: &protocol.MemoryUser{\n\t\t\t\t\tEmail: \"love@v2ray.com\",\n\t\t\t\t\tAccount: toAccount(&Account{\n\t\t\t\t\t\tPassword:   \"password\",\n\t\t\t\t\t\tCipherType: CipherType_AES_256_CFB,\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t},\n\t\t\tpayload: []byte(\"test string\"),\n\t\t},\n\t\t{\n\t\t\trequest: &protocol.RequestHeader{\n\t\t\t\tVersion: Version,\n\t\t\t\tCommand: protocol.RequestCommandTCP,\n\t\t\t\tAddress: net.DomainAddress(\"v2ray.com\"),\n\t\t\t\tPort:    1234,\n\t\t\t\tUser: &protocol.MemoryUser{\n\t\t\t\t\tEmail: \"love@v2ray.com\",\n\t\t\t\t\tAccount: toAccount(&Account{\n\t\t\t\t\t\tPassword:   \"password\",\n\t\t\t\t\t\tCipherType: CipherType_CHACHA20_IETF,\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t},\n\t\t\tpayload: []byte(\"test string\"),\n\t\t},\n\t}\n\n\trunTest := func(request *protocol.RequestHeader, payload []byte) {\n\t\tdata := buf.New()\n\t\tcommon.Must2(data.Write(payload))\n\n\t\tcache := buf.New()\n\t\tdefer cache.Release()\n\n\t\twriter, err := WriteTCPRequest(request, cache)\n\t\tcommon.Must(err)\n\n\t\tcommon.Must(writer.WriteMultiBuffer(buf.MultiBuffer{data}))\n\n\t\tdecodedRequest, reader, err := ReadTCPSession(request.User, cache)\n\t\tcommon.Must(err)\n\t\tif r := cmp.Diff(decodedRequest, request); r != \"\" {\n\t\t\tt.Error(\"request: \", r)\n\t\t}\n\n\t\tdecodedData, err := reader.ReadMultiBuffer()\n\t\tcommon.Must(err)\n\t\tif r := cmp.Diff(decodedData[0].Bytes(), payload); r != \"\" {\n\t\t\tt.Error(\"data: \", r)\n\t\t}\n\t}\n\n\tfor _, test := range cases {\n\t\trunTest(test.request, test.payload)\n\t}\n\n}\n\nfunc TestUDPReaderWriter(t *testing.T) {\n\tuser := &protocol.MemoryUser{\n\t\tAccount: toAccount(&Account{\n\t\t\tPassword:   \"test-password\",\n\t\t\tCipherType: CipherType_CHACHA20_IETF,\n\t\t}),\n\t}\n\tcache := buf.New()\n\tdefer cache.Release()\n\n\twriter := &buf.SequentialWriter{Writer: &UDPWriter{\n\t\tWriter: cache,\n\t\tRequest: &protocol.RequestHeader{\n\t\t\tVersion: Version,\n\t\t\tAddress: net.DomainAddress(\"v2ray.com\"),\n\t\t\tPort:    123,\n\t\t\tUser:    user,\n\t\t},\n\t}}\n\n\treader := &UDPReader{\n\t\tReader: cache,\n\t\tUser:   user,\n\t}\n\n\t{\n\t\tb := buf.New()\n\t\tcommon.Must2(b.WriteString(\"test payload\"))\n\t\tcommon.Must(writer.WriteMultiBuffer(buf.MultiBuffer{b}))\n\n\t\tpayload, err := reader.ReadMultiBuffer()\n\t\tcommon.Must(err)\n\t\tif payload[0].String() != \"test payload\" {\n\t\t\tt.Error(\"unexpected output: \", payload[0].String())\n\t\t}\n\t}\n\n\t{\n\t\tb := buf.New()\n\t\tcommon.Must2(b.WriteString(\"test payload 2\"))\n\t\tcommon.Must(writer.WriteMultiBuffer(buf.MultiBuffer{b}))\n\n\t\tpayload, err := reader.ReadMultiBuffer()\n\t\tcommon.Must(err)\n\t\tif payload[0].String() != \"test payload 2\" {\n\t\t\tt.Error(\"unexpected output: \", payload[0].String())\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "proxy/shadowsocks/server.go",
    "content": "// +build !confonly\n\npackage shadowsocks\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/log\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\tudp_proto \"v2ray.com/core/common/protocol/udp\"\n\t\"v2ray.com/core/common/session\"\n\t\"v2ray.com/core/common/signal\"\n\t\"v2ray.com/core/common/task\"\n\t\"v2ray.com/core/features/policy\"\n\t\"v2ray.com/core/features/routing\"\n\t\"v2ray.com/core/transport/internet\"\n\t\"v2ray.com/core/transport/internet/udp\"\n)\n\ntype Server struct {\n\tconfig        *ServerConfig\n\tuser          *protocol.MemoryUser\n\tpolicyManager policy.Manager\n}\n\n// NewServer create a new Shadowsocks server.\nfunc NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {\n\tif config.GetUser() == nil {\n\t\treturn nil, newError(\"user is not specified\")\n\t}\n\n\tmUser, err := config.User.ToMemoryUser()\n\tif err != nil {\n\t\treturn nil, newError(\"failed to parse user account\").Base(err)\n\t}\n\n\tv := core.MustFromContext(ctx)\n\ts := &Server{\n\t\tconfig:        config,\n\t\tuser:          mUser,\n\t\tpolicyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),\n\t}\n\n\treturn s, nil\n}\n\nfunc (s *Server) Network() []net.Network {\n\tlist := s.config.Network\n\tif len(list) == 0 {\n\t\tlist = append(list, net.Network_TCP)\n\t}\n\tif s.config.UdpEnabled {\n\t\tlist = append(list, net.Network_UDP)\n\t}\n\treturn list\n}\n\nfunc (s *Server) Process(ctx context.Context, network net.Network, conn internet.Connection, dispatcher routing.Dispatcher) error {\n\tswitch network {\n\tcase net.Network_TCP:\n\t\treturn s.handleConnection(ctx, conn, dispatcher)\n\tcase net.Network_UDP:\n\t\treturn s.handlerUDPPayload(ctx, conn, dispatcher)\n\tdefault:\n\t\treturn newError(\"unknown network: \", network)\n\t}\n}\n\nfunc (s *Server) handlerUDPPayload(ctx context.Context, conn internet.Connection, dispatcher routing.Dispatcher) error {\n\tudpServer := udp.NewDispatcher(dispatcher, func(ctx context.Context, packet *udp_proto.Packet) {\n\t\trequest := protocol.RequestHeaderFromContext(ctx)\n\t\tif request == nil {\n\t\t\treturn\n\t\t}\n\n\t\tpayload := packet.Payload\n\t\tdata, err := EncodeUDPPacket(request, payload.Bytes())\n\t\tpayload.Release()\n\t\tif err != nil {\n\t\t\tnewError(\"failed to encode UDP packet\").Base(err).AtWarning().WriteToLog(session.ExportIDToError(ctx))\n\t\t\treturn\n\t\t}\n\t\tdefer data.Release()\n\n\t\tconn.Write(data.Bytes())\n\t})\n\n\tinbound := session.InboundFromContext(ctx)\n\tif inbound == nil {\n\t\tpanic(\"no inbound metadata\")\n\t}\n\tinbound.User = s.user\n\n\treader := buf.NewPacketReader(conn)\n\tfor {\n\t\tmpayload, err := reader.ReadMultiBuffer()\n\t\tif err != nil {\n\t\t\tbreak\n\t\t}\n\n\t\tfor _, payload := range mpayload {\n\t\t\trequest, data, err := DecodeUDPPacket(s.user, payload)\n\t\t\tif err != nil {\n\t\t\t\tif inbound := session.InboundFromContext(ctx); inbound != nil && inbound.Source.IsValid() {\n\t\t\t\t\tnewError(\"dropping invalid UDP packet from: \", inbound.Source).Base(err).WriteToLog(session.ExportIDToError(ctx))\n\t\t\t\t\tlog.Record(&log.AccessMessage{\n\t\t\t\t\t\tFrom:   inbound.Source,\n\t\t\t\t\t\tTo:     \"\",\n\t\t\t\t\t\tStatus: log.AccessRejected,\n\t\t\t\t\t\tReason: err,\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\tpayload.Release()\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tcurrentPacketCtx := ctx\n\t\t\tdest := request.Destination()\n\t\t\tif inbound.Source.IsValid() {\n\t\t\t\tcurrentPacketCtx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{\n\t\t\t\t\tFrom:   inbound.Source,\n\t\t\t\t\tTo:     dest,\n\t\t\t\t\tStatus: log.AccessAccepted,\n\t\t\t\t\tReason: \"\",\n\t\t\t\t\tEmail:  request.User.Email,\n\t\t\t\t})\n\t\t\t}\n\t\t\tnewError(\"tunnelling request to \", dest).WriteToLog(session.ExportIDToError(currentPacketCtx))\n\n\t\t\tcurrentPacketCtx = protocol.ContextWithRequestHeader(currentPacketCtx, request)\n\t\t\tudpServer.Dispatch(currentPacketCtx, dest, data)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (s *Server) handleConnection(ctx context.Context, conn internet.Connection, dispatcher routing.Dispatcher) error {\n\tsessionPolicy := s.policyManager.ForLevel(s.user.Level)\n\tconn.SetReadDeadline(time.Now().Add(sessionPolicy.Timeouts.Handshake))\n\n\tbufferedReader := buf.BufferedReader{Reader: buf.NewReader(conn)}\n\trequest, bodyReader, err := ReadTCPSession(s.user, &bufferedReader)\n\tif err != nil {\n\t\tlog.Record(&log.AccessMessage{\n\t\t\tFrom:   conn.RemoteAddr(),\n\t\t\tTo:     \"\",\n\t\t\tStatus: log.AccessRejected,\n\t\t\tReason: err,\n\t\t})\n\t\treturn newError(\"failed to create request from: \", conn.RemoteAddr()).Base(err)\n\t}\n\tconn.SetReadDeadline(time.Time{})\n\n\tinbound := session.InboundFromContext(ctx)\n\tif inbound == nil {\n\t\tpanic(\"no inbound metadata\")\n\t}\n\tinbound.User = s.user\n\n\tdest := request.Destination()\n\tctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{\n\t\tFrom:   conn.RemoteAddr(),\n\t\tTo:     dest,\n\t\tStatus: log.AccessAccepted,\n\t\tReason: \"\",\n\t\tEmail:  request.User.Email,\n\t})\n\tnewError(\"tunnelling request to \", dest).WriteToLog(session.ExportIDToError(ctx))\n\n\tctx, cancel := context.WithCancel(ctx)\n\ttimer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)\n\n\tctx = policy.ContextWithBufferPolicy(ctx, sessionPolicy.Buffer)\n\tlink, err := dispatcher.Dispatch(ctx, dest)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tresponseDone := func() error {\n\t\tdefer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)\n\n\t\tbufferedWriter := buf.NewBufferedWriter(buf.NewWriter(conn))\n\t\tresponseWriter, err := WriteTCPResponse(request, bufferedWriter)\n\t\tif err != nil {\n\t\t\treturn newError(\"failed to write response\").Base(err)\n\t\t}\n\n\t\t{\n\t\t\tpayload, err := link.Reader.ReadMultiBuffer()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif err := responseWriter.WriteMultiBuffer(payload); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tif err := bufferedWriter.SetBuffered(false); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err := buf.Copy(link.Reader, responseWriter, buf.UpdateActivity(timer)); err != nil {\n\t\t\treturn newError(\"failed to transport all TCP response\").Base(err)\n\t\t}\n\n\t\treturn nil\n\t}\n\n\trequestDone := func() error {\n\t\tdefer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)\n\n\t\tif err := buf.Copy(bodyReader, link.Writer, buf.UpdateActivity(timer)); err != nil {\n\t\t\treturn newError(\"failed to transport all TCP request\").Base(err)\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tvar requestDoneAndCloseWriter = task.OnSuccess(requestDone, task.Close(link.Writer))\n\tif err := task.Run(ctx, requestDoneAndCloseWriter, responseDone); err != nil {\n\t\tcommon.Interrupt(link.Reader)\n\t\tcommon.Interrupt(link.Writer)\n\t\treturn newError(\"connection ends\").Base(err)\n\t}\n\n\treturn nil\n}\n\nfunc init() {\n\tcommon.Must(common.RegisterConfig((*ServerConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {\n\t\treturn NewServer(ctx, config.(*ServerConfig))\n\t}))\n}\n"
  },
  {
    "path": "proxy/shadowsocks/shadowsocks.go",
    "content": "// Package shadowsocks provides compatible functionality to Shadowsocks.\n//\n// Shadowsocks client and server are implemented as outbound and inbound respectively in V2Ray's term.\n//\n// R.I.P Shadowsocks\npackage shadowsocks\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n"
  },
  {
    "path": "proxy/socks/client.go",
    "content": "// +build !confonly\n\npackage socks\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/retry\"\n\t\"v2ray.com/core/common/session\"\n\t\"v2ray.com/core/common/signal\"\n\t\"v2ray.com/core/common/task\"\n\t\"v2ray.com/core/features/policy\"\n\t\"v2ray.com/core/transport\"\n\t\"v2ray.com/core/transport/internet\"\n)\n\n// Client is a Socks5 client.\ntype Client struct {\n\tserverPicker  protocol.ServerPicker\n\tpolicyManager policy.Manager\n}\n\n// NewClient create a new Socks5 client based on the given config.\nfunc NewClient(ctx context.Context, config *ClientConfig) (*Client, error) {\n\tserverList := protocol.NewServerList()\n\tfor _, rec := range config.Server {\n\t\ts, err := protocol.NewServerSpecFromPB(rec)\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"failed to get server spec\").Base(err)\n\t\t}\n\t\tserverList.AddServer(s)\n\t}\n\tif serverList.Size() == 0 {\n\t\treturn nil, newError(\"0 target server\")\n\t}\n\n\tv := core.MustFromContext(ctx)\n\treturn &Client{\n\t\tserverPicker:  protocol.NewRoundRobinServerPicker(serverList),\n\t\tpolicyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),\n\t}, nil\n}\n\n// Process implements proxy.Outbound.Process.\nfunc (c *Client) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {\n\toutbound := session.OutboundFromContext(ctx)\n\tif outbound == nil || !outbound.Target.IsValid() {\n\t\treturn newError(\"target not specified.\")\n\t}\n\tdestination := outbound.Target\n\n\tvar server *protocol.ServerSpec\n\tvar conn internet.Connection\n\n\tif err := retry.ExponentialBackoff(5, 100).On(func() error {\n\t\tserver = c.serverPicker.PickServer()\n\t\tdest := server.Destination()\n\t\trawConn, err := dialer.Dial(ctx, dest)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tconn = rawConn\n\n\t\treturn nil\n\t}); err != nil {\n\t\treturn newError(\"failed to find an available destination\").Base(err)\n\t}\n\n\tdefer func() {\n\t\tif err := conn.Close(); err != nil {\n\t\t\tnewError(\"failed to closed connection\").Base(err).WriteToLog(session.ExportIDToError(ctx))\n\t\t}\n\t}()\n\n\tp := c.policyManager.ForLevel(0)\n\n\trequest := &protocol.RequestHeader{\n\t\tVersion: socks5Version,\n\t\tCommand: protocol.RequestCommandTCP,\n\t\tAddress: destination.Address,\n\t\tPort:    destination.Port,\n\t}\n\tif destination.Network == net.Network_UDP {\n\t\trequest.Command = protocol.RequestCommandUDP\n\t}\n\n\tuser := server.PickUser()\n\tif user != nil {\n\t\trequest.User = user\n\t\tp = c.policyManager.ForLevel(user.Level)\n\t}\n\n\tif err := conn.SetDeadline(time.Now().Add(p.Timeouts.Handshake)); err != nil {\n\t\tnewError(\"failed to set deadline for handshake\").Base(err).WriteToLog(session.ExportIDToError(ctx))\n\t}\n\tudpRequest, err := ClientHandshake(request, conn, conn)\n\tif err != nil {\n\t\treturn newError(\"failed to establish connection to server\").AtWarning().Base(err)\n\t}\n\n\tif err := conn.SetDeadline(time.Time{}); err != nil {\n\t\tnewError(\"failed to clear deadline after handshake\").Base(err).WriteToLog(session.ExportIDToError(ctx))\n\t}\n\n\tctx, cancel := context.WithCancel(ctx)\n\ttimer := signal.CancelAfterInactivity(ctx, cancel, p.Timeouts.ConnectionIdle)\n\n\tvar requestFunc func() error\n\tvar responseFunc func() error\n\tif request.Command == protocol.RequestCommandTCP {\n\t\trequestFunc = func() error {\n\t\t\tdefer timer.SetTimeout(p.Timeouts.DownlinkOnly)\n\t\t\treturn buf.Copy(link.Reader, buf.NewWriter(conn), buf.UpdateActivity(timer))\n\t\t}\n\t\tresponseFunc = func() error {\n\t\t\tdefer timer.SetTimeout(p.Timeouts.UplinkOnly)\n\t\t\treturn buf.Copy(buf.NewReader(conn), link.Writer, buf.UpdateActivity(timer))\n\t\t}\n\t} else if request.Command == protocol.RequestCommandUDP {\n\t\tudpConn, err := dialer.Dial(ctx, udpRequest.Destination())\n\t\tif err != nil {\n\t\t\treturn newError(\"failed to create UDP connection\").Base(err)\n\t\t}\n\t\tdefer udpConn.Close() // nolint: errcheck\n\t\trequestFunc = func() error {\n\t\t\tdefer timer.SetTimeout(p.Timeouts.DownlinkOnly)\n\t\t\treturn buf.Copy(link.Reader, &buf.SequentialWriter{Writer: NewUDPWriter(request, udpConn)}, buf.UpdateActivity(timer))\n\t\t}\n\t\tresponseFunc = func() error {\n\t\t\tdefer timer.SetTimeout(p.Timeouts.UplinkOnly)\n\t\t\treader := &UDPReader{reader: udpConn}\n\t\t\treturn buf.Copy(reader, link.Writer, buf.UpdateActivity(timer))\n\t\t}\n\t}\n\n\tvar responseDonePost = task.OnSuccess(responseFunc, task.Close(link.Writer))\n\tif err := task.Run(ctx, requestFunc, responseDonePost); err != nil {\n\t\treturn newError(\"connection ends\").Base(err)\n\t}\n\n\treturn nil\n}\n\nfunc init() {\n\tcommon.Must(common.RegisterConfig((*ClientConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {\n\t\treturn NewClient(ctx, config.(*ClientConfig))\n\t}))\n}\n"
  },
  {
    "path": "proxy/socks/config.go",
    "content": "// +build !confonly\n\npackage socks\n\nimport \"v2ray.com/core/common/protocol\"\n\nfunc (a *Account) Equals(another protocol.Account) bool {\n\tif account, ok := another.(*Account); ok {\n\t\treturn a.Username == account.Username\n\t}\n\treturn false\n}\n\nfunc (a *Account) AsAccount() (protocol.Account, error) {\n\treturn a, nil\n}\n\nfunc (c *ServerConfig) HasAccount(username, password string) bool {\n\tif c.Accounts == nil {\n\t\treturn false\n\t}\n\tstoredPassed, found := c.Accounts[username]\n\tif !found {\n\t\treturn false\n\t}\n\treturn storedPassed == password\n}\n"
  },
  {
    "path": "proxy/socks/config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: proxy/socks/config.proto\n\npackage socks\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n\tnet \"v2ray.com/core/common/net\"\n\tprotocol \"v2ray.com/core/common/protocol\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\n// AuthType is the authentication type of Socks proxy.\ntype AuthType int32\n\nconst (\n\t// NO_AUTH is for anounymous authentication.\n\tAuthType_NO_AUTH AuthType = 0\n\t// PASSWORD is for username/password authentication.\n\tAuthType_PASSWORD AuthType = 1\n)\n\n// Enum value maps for AuthType.\nvar (\n\tAuthType_name = map[int32]string{\n\t\t0: \"NO_AUTH\",\n\t\t1: \"PASSWORD\",\n\t}\n\tAuthType_value = map[string]int32{\n\t\t\"NO_AUTH\":  0,\n\t\t\"PASSWORD\": 1,\n\t}\n)\n\nfunc (x AuthType) Enum() *AuthType {\n\tp := new(AuthType)\n\t*p = x\n\treturn p\n}\n\nfunc (x AuthType) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (AuthType) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_proxy_socks_config_proto_enumTypes[0].Descriptor()\n}\n\nfunc (AuthType) Type() protoreflect.EnumType {\n\treturn &file_proxy_socks_config_proto_enumTypes[0]\n}\n\nfunc (x AuthType) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use AuthType.Descriptor instead.\nfunc (AuthType) EnumDescriptor() ([]byte, []int) {\n\treturn file_proxy_socks_config_proto_rawDescGZIP(), []int{0}\n}\n\n// Account represents a Socks account.\ntype Account struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tUsername string `protobuf:\"bytes,1,opt,name=username,proto3\" json:\"username,omitempty\"`\n\tPassword string `protobuf:\"bytes,2,opt,name=password,proto3\" json:\"password,omitempty\"`\n}\n\nfunc (x *Account) Reset() {\n\t*x = Account{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_proxy_socks_config_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Account) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Account) ProtoMessage() {}\n\nfunc (x *Account) ProtoReflect() protoreflect.Message {\n\tmi := &file_proxy_socks_config_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Account.ProtoReflect.Descriptor instead.\nfunc (*Account) Descriptor() ([]byte, []int) {\n\treturn file_proxy_socks_config_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *Account) GetUsername() string {\n\tif x != nil {\n\t\treturn x.Username\n\t}\n\treturn \"\"\n}\n\nfunc (x *Account) GetPassword() string {\n\tif x != nil {\n\t\treturn x.Password\n\t}\n\treturn \"\"\n}\n\n// ServerConfig is the protobuf config for Socks server.\ntype ServerConfig struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tAuthType   AuthType          `protobuf:\"varint,1,opt,name=auth_type,json=authType,proto3,enum=v2ray.core.proxy.socks.AuthType\" json:\"auth_type,omitempty\"`\n\tAccounts   map[string]string `protobuf:\"bytes,2,rep,name=accounts,proto3\" json:\"accounts,omitempty\" protobuf_key:\"bytes,1,opt,name=key,proto3\" protobuf_val:\"bytes,2,opt,name=value,proto3\"`\n\tAddress    *net.IPOrDomain   `protobuf:\"bytes,3,opt,name=address,proto3\" json:\"address,omitempty\"`\n\tUdpEnabled bool              `protobuf:\"varint,4,opt,name=udp_enabled,json=udpEnabled,proto3\" json:\"udp_enabled,omitempty\"`\n\t// Deprecated: Do not use.\n\tTimeout   uint32 `protobuf:\"varint,5,opt,name=timeout,proto3\" json:\"timeout,omitempty\"`\n\tUserLevel uint32 `protobuf:\"varint,6,opt,name=user_level,json=userLevel,proto3\" json:\"user_level,omitempty\"`\n}\n\nfunc (x *ServerConfig) Reset() {\n\t*x = ServerConfig{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_proxy_socks_config_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *ServerConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ServerConfig) ProtoMessage() {}\n\nfunc (x *ServerConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_proxy_socks_config_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ServerConfig.ProtoReflect.Descriptor instead.\nfunc (*ServerConfig) Descriptor() ([]byte, []int) {\n\treturn file_proxy_socks_config_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *ServerConfig) GetAuthType() AuthType {\n\tif x != nil {\n\t\treturn x.AuthType\n\t}\n\treturn AuthType_NO_AUTH\n}\n\nfunc (x *ServerConfig) GetAccounts() map[string]string {\n\tif x != nil {\n\t\treturn x.Accounts\n\t}\n\treturn nil\n}\n\nfunc (x *ServerConfig) GetAddress() *net.IPOrDomain {\n\tif x != nil {\n\t\treturn x.Address\n\t}\n\treturn nil\n}\n\nfunc (x *ServerConfig) GetUdpEnabled() bool {\n\tif x != nil {\n\t\treturn x.UdpEnabled\n\t}\n\treturn false\n}\n\n// Deprecated: Do not use.\nfunc (x *ServerConfig) GetTimeout() uint32 {\n\tif x != nil {\n\t\treturn x.Timeout\n\t}\n\treturn 0\n}\n\nfunc (x *ServerConfig) GetUserLevel() uint32 {\n\tif x != nil {\n\t\treturn x.UserLevel\n\t}\n\treturn 0\n}\n\n// ClientConfig is the protobuf config for Socks client.\ntype ClientConfig struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Sever is a list of Socks server addresses.\n\tServer []*protocol.ServerEndpoint `protobuf:\"bytes,1,rep,name=server,proto3\" json:\"server,omitempty\"`\n}\n\nfunc (x *ClientConfig) Reset() {\n\t*x = ClientConfig{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_proxy_socks_config_proto_msgTypes[2]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *ClientConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ClientConfig) ProtoMessage() {}\n\nfunc (x *ClientConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_proxy_socks_config_proto_msgTypes[2]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ClientConfig.ProtoReflect.Descriptor instead.\nfunc (*ClientConfig) Descriptor() ([]byte, []int) {\n\treturn file_proxy_socks_config_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *ClientConfig) GetServer() []*protocol.ServerEndpoint {\n\tif x != nil {\n\t\treturn x.Server\n\t}\n\treturn nil\n}\n\nvar File_proxy_socks_config_proto protoreflect.FileDescriptor\n\nvar file_proxy_socks_config_proto_rawDesc = []byte{\n\t0x0a, 0x18, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0x2f, 0x63, 0x6f,\n\t0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x16, 0x76, 0x32, 0x72, 0x61,\n\t0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x73, 0x6f, 0x63,\n\t0x6b, 0x73, 0x1a, 0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x61,\n\t0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x21, 0x63, 0x6f,\n\t0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x73, 0x65,\n\t0x72, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22,\n\t0x41, 0x0a, 0x07, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73,\n\t0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73,\n\t0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f,\n\t0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f,\n\t0x72, 0x64, 0x22, 0xf5, 0x02, 0x0a, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e,\n\t0x66, 0x69, 0x67, 0x12, 0x3d, 0x0a, 0x09, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x74, 0x79, 0x70, 0x65,\n\t0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,\n\t0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0x2e,\n\t0x41, 0x75, 0x74, 0x68, 0x54, 0x79, 0x70, 0x65, 0x52, 0x08, 0x61, 0x75, 0x74, 0x68, 0x54, 0x79,\n\t0x70, 0x65, 0x12, 0x4e, 0x0a, 0x08, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x18, 0x02,\n\t0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72,\n\t0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0x2e, 0x53, 0x65,\n\t0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75,\n\t0x6e, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e,\n\t0x74, 0x73, 0x12, 0x3b, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20,\n\t0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,\n\t0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72,\n\t0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12,\n\t0x1f, 0x0a, 0x0b, 0x75, 0x64, 0x70, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x04,\n\t0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x75, 0x64, 0x70, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64,\n\t0x12, 0x1c, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28,\n\t0x0d, 0x42, 0x02, 0x18, 0x01, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x1d,\n\t0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x06, 0x20, 0x01,\n\t0x28, 0x0d, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x1a, 0x3b, 0x0a,\n\t0x0d, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10,\n\t0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79,\n\t0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,\n\t0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x52, 0x0a, 0x0c, 0x43, 0x6c,\n\t0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x42, 0x0a, 0x06, 0x73, 0x65,\n\t0x72, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x76, 0x32, 0x72,\n\t0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70,\n\t0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e,\n\t0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2a, 0x25,\n\t0x0a, 0x08, 0x41, 0x75, 0x74, 0x68, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x4e, 0x4f,\n\t0x5f, 0x41, 0x55, 0x54, 0x48, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x41, 0x53, 0x53, 0x57,\n\t0x4f, 0x52, 0x44, 0x10, 0x01, 0x42, 0x53, 0x0a, 0x1a, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72,\n\t0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x73, 0x6f,\n\t0x63, 0x6b, 0x73, 0x50, 0x01, 0x5a, 0x1a, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d,\n\t0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x73, 0x6f, 0x63, 0x6b,\n\t0x73, 0xaa, 0x02, 0x16, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x50,\n\t0x72, 0x6f, 0x78, 0x79, 0x2e, 0x53, 0x6f, 0x63, 0x6b, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,\n\t0x6f, 0x33,\n}\n\nvar (\n\tfile_proxy_socks_config_proto_rawDescOnce sync.Once\n\tfile_proxy_socks_config_proto_rawDescData = file_proxy_socks_config_proto_rawDesc\n)\n\nfunc file_proxy_socks_config_proto_rawDescGZIP() []byte {\n\tfile_proxy_socks_config_proto_rawDescOnce.Do(func() {\n\t\tfile_proxy_socks_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_proxy_socks_config_proto_rawDescData)\n\t})\n\treturn file_proxy_socks_config_proto_rawDescData\n}\n\nvar file_proxy_socks_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1)\nvar file_proxy_socks_config_proto_msgTypes = make([]protoimpl.MessageInfo, 4)\nvar file_proxy_socks_config_proto_goTypes = []interface{}{\n\t(AuthType)(0),                   // 0: v2ray.core.proxy.socks.AuthType\n\t(*Account)(nil),                 // 1: v2ray.core.proxy.socks.Account\n\t(*ServerConfig)(nil),            // 2: v2ray.core.proxy.socks.ServerConfig\n\t(*ClientConfig)(nil),            // 3: v2ray.core.proxy.socks.ClientConfig\n\tnil,                             // 4: v2ray.core.proxy.socks.ServerConfig.AccountsEntry\n\t(*net.IPOrDomain)(nil),          // 5: v2ray.core.common.net.IPOrDomain\n\t(*protocol.ServerEndpoint)(nil), // 6: v2ray.core.common.protocol.ServerEndpoint\n}\nvar file_proxy_socks_config_proto_depIdxs = []int32{\n\t0, // 0: v2ray.core.proxy.socks.ServerConfig.auth_type:type_name -> v2ray.core.proxy.socks.AuthType\n\t4, // 1: v2ray.core.proxy.socks.ServerConfig.accounts:type_name -> v2ray.core.proxy.socks.ServerConfig.AccountsEntry\n\t5, // 2: v2ray.core.proxy.socks.ServerConfig.address:type_name -> v2ray.core.common.net.IPOrDomain\n\t6, // 3: v2ray.core.proxy.socks.ClientConfig.server:type_name -> v2ray.core.common.protocol.ServerEndpoint\n\t4, // [4:4] is the sub-list for method output_type\n\t4, // [4:4] is the sub-list for method input_type\n\t4, // [4:4] is the sub-list for extension type_name\n\t4, // [4:4] is the sub-list for extension extendee\n\t0, // [0:4] is the sub-list for field type_name\n}\n\nfunc init() { file_proxy_socks_config_proto_init() }\nfunc file_proxy_socks_config_proto_init() {\n\tif File_proxy_socks_config_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_proxy_socks_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Account); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_proxy_socks_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*ServerConfig); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_proxy_socks_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*ClientConfig); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_proxy_socks_config_proto_rawDesc,\n\t\t\tNumEnums:      1,\n\t\t\tNumMessages:   4,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_proxy_socks_config_proto_goTypes,\n\t\tDependencyIndexes: file_proxy_socks_config_proto_depIdxs,\n\t\tEnumInfos:         file_proxy_socks_config_proto_enumTypes,\n\t\tMessageInfos:      file_proxy_socks_config_proto_msgTypes,\n\t}.Build()\n\tFile_proxy_socks_config_proto = out.File\n\tfile_proxy_socks_config_proto_rawDesc = nil\n\tfile_proxy_socks_config_proto_goTypes = nil\n\tfile_proxy_socks_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "proxy/socks/config.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.proxy.socks;\noption csharp_namespace = \"V2Ray.Core.Proxy.Socks\";\noption go_package = \"v2ray.com/core/proxy/socks\";\noption java_package = \"com.v2ray.core.proxy.socks\";\noption java_multiple_files = true;\n\nimport \"common/net/address.proto\";\nimport \"common/protocol/server_spec.proto\";\n\n// Account represents a Socks account.\nmessage Account {\n  string username = 1;\n  string password = 2;\n}\n\n// AuthType is the authentication type of Socks proxy.\nenum AuthType {\n  // NO_AUTH is for anounymous authentication.\n  NO_AUTH = 0;\n  // PASSWORD is for username/password authentication.\n  PASSWORD = 1;\n}\n\n// ServerConfig is the protobuf config for Socks server.\nmessage ServerConfig {\n  AuthType auth_type = 1;\n  map<string, string> accounts = 2;\n  v2ray.core.common.net.IPOrDomain address = 3;\n  bool udp_enabled = 4;\n  uint32 timeout = 5 [deprecated = true];\n  uint32 user_level = 6;\n}\n\n// ClientConfig is the protobuf config for Socks client.\nmessage ClientConfig {\n  // Sever is a list of Socks server addresses.\n  repeated v2ray.core.common.protocol.ServerEndpoint server = 1;\n}\n"
  },
  {
    "path": "proxy/socks/errors.generated.go",
    "content": "package socks\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "proxy/socks/protocol.go",
    "content": "// +build !confonly\n\npackage socks\n\nimport (\n\t\"encoding/binary\"\n\t\"io\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n)\n\nconst (\n\tsocks5Version = 0x05\n\tsocks4Version = 0x04\n\n\tcmdTCPConnect    = 0x01\n\tcmdTCPBind       = 0x02\n\tcmdUDPPort       = 0x03\n\tcmdTorResolve    = 0xF0\n\tcmdTorResolvePTR = 0xF1\n\n\tsocks4RequestGranted  = 90\n\tsocks4RequestRejected = 91\n\n\tauthNotRequired = 0x00\n\t//authGssAPI           = 0x01\n\tauthPassword         = 0x02\n\tauthNoMatchingMethod = 0xFF\n\n\tstatusSuccess       = 0x00\n\tstatusCmdNotSupport = 0x07\n)\n\nvar addrParser = protocol.NewAddressParser(\n\tprotocol.AddressFamilyByte(0x01, net.AddressFamilyIPv4),\n\tprotocol.AddressFamilyByte(0x04, net.AddressFamilyIPv6),\n\tprotocol.AddressFamilyByte(0x03, net.AddressFamilyDomain),\n)\n\ntype ServerSession struct {\n\tconfig *ServerConfig\n\tport   net.Port\n}\n\nfunc (s *ServerSession) handshake4(cmd byte, reader io.Reader, writer io.Writer) (*protocol.RequestHeader, error) {\n\tif s.config.AuthType == AuthType_PASSWORD {\n\t\twriteSocks4Response(writer, socks4RequestRejected, net.AnyIP, net.Port(0)) // nolint: errcheck\n\t\treturn nil, newError(\"socks 4 is not allowed when auth is required.\")\n\t}\n\n\tvar port net.Port\n\tvar address net.Address\n\n\t{\n\t\tbuffer := buf.StackNew()\n\t\tif _, err := buffer.ReadFullFrom(reader, 6); err != nil {\n\t\t\tbuffer.Release()\n\t\t\treturn nil, newError(\"insufficient header\").Base(err)\n\t\t}\n\t\tport = net.PortFromBytes(buffer.BytesRange(0, 2))\n\t\taddress = net.IPAddress(buffer.BytesRange(2, 6))\n\t\tbuffer.Release()\n\t}\n\n\tif _, err := ReadUntilNull(reader); /* user id */ err != nil {\n\t\treturn nil, err\n\t}\n\tif address.IP()[0] == 0x00 {\n\t\tdomain, err := ReadUntilNull(reader)\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"failed to read domain for socks 4a\").Base(err)\n\t\t}\n\t\taddress = net.DomainAddress(domain)\n\t}\n\n\tswitch cmd {\n\tcase cmdTCPConnect:\n\t\trequest := &protocol.RequestHeader{\n\t\t\tCommand: protocol.RequestCommandTCP,\n\t\t\tAddress: address,\n\t\t\tPort:    port,\n\t\t\tVersion: socks4Version,\n\t\t}\n\t\tif err := writeSocks4Response(writer, socks4RequestGranted, net.AnyIP, net.Port(0)); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn request, nil\n\tdefault:\n\t\twriteSocks4Response(writer, socks4RequestRejected, net.AnyIP, net.Port(0)) // nolint: errcheck\n\t\treturn nil, newError(\"unsupported command: \", cmd)\n\t}\n}\n\nfunc (s *ServerSession) auth5(nMethod byte, reader io.Reader, writer io.Writer) (username string, err error) {\n\tbuffer := buf.StackNew()\n\tdefer buffer.Release()\n\n\tif _, err = buffer.ReadFullFrom(reader, int32(nMethod)); err != nil {\n\t\treturn \"\", newError(\"failed to read auth methods\").Base(err)\n\t}\n\n\tvar expectedAuth byte = authNotRequired\n\tif s.config.AuthType == AuthType_PASSWORD {\n\t\texpectedAuth = authPassword\n\t}\n\n\tif !hasAuthMethod(expectedAuth, buffer.BytesRange(0, int32(nMethod))) {\n\t\twriteSocks5AuthenticationResponse(writer, socks5Version, authNoMatchingMethod) // nolint: errcheck\n\t\treturn \"\", newError(\"no matching auth method\")\n\t}\n\n\tif err := writeSocks5AuthenticationResponse(writer, socks5Version, expectedAuth); err != nil {\n\t\treturn \"\", newError(\"failed to write auth response\").Base(err)\n\t}\n\n\tif expectedAuth == authPassword {\n\t\tusername, password, err := ReadUsernamePassword(reader)\n\t\tif err != nil {\n\t\t\treturn \"\", newError(\"failed to read username and password for authentication\").Base(err)\n\t\t}\n\n\t\tif !s.config.HasAccount(username, password) {\n\t\t\twriteSocks5AuthenticationResponse(writer, 0x01, 0xFF) // nolint: errcheck\n\t\t\treturn \"\", newError(\"invalid username or password\")\n\t\t}\n\n\t\tif err := writeSocks5AuthenticationResponse(writer, 0x01, 0x00); err != nil {\n\t\t\treturn \"\", newError(\"failed to write auth response\").Base(err)\n\t\t}\n\t\treturn username, nil\n\t}\n\n\treturn \"\", nil\n}\n\nfunc (s *ServerSession) handshake5(nMethod byte, reader io.Reader, writer io.Writer) (*protocol.RequestHeader, error) {\n\tvar (\n\t\tusername string\n\t\terr      error\n\t)\n\tif username, err = s.auth5(nMethod, reader, writer); err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar cmd byte\n\t{\n\t\tbuffer := buf.StackNew()\n\t\tif _, err := buffer.ReadFullFrom(reader, 3); err != nil {\n\t\t\tbuffer.Release()\n\t\t\treturn nil, newError(\"failed to read request\").Base(err)\n\t\t}\n\t\tcmd = buffer.Byte(1)\n\t\tbuffer.Release()\n\t}\n\n\trequest := new(protocol.RequestHeader)\n\tif username != \"\" {\n\t\trequest.User = &protocol.MemoryUser{Email: username}\n\t}\n\tswitch cmd {\n\tcase cmdTCPConnect, cmdTorResolve, cmdTorResolvePTR:\n\t\t// We don't have a solution for Tor case now. Simply treat it as connect command.\n\t\trequest.Command = protocol.RequestCommandTCP\n\tcase cmdUDPPort:\n\t\tif !s.config.UdpEnabled {\n\t\t\twriteSocks5Response(writer, statusCmdNotSupport, net.AnyIP, net.Port(0)) // nolint: errcheck\n\t\t\treturn nil, newError(\"UDP is not enabled.\")\n\t\t}\n\t\trequest.Command = protocol.RequestCommandUDP\n\tcase cmdTCPBind:\n\t\twriteSocks5Response(writer, statusCmdNotSupport, net.AnyIP, net.Port(0)) // nolint: errcheck\n\t\treturn nil, newError(\"TCP bind is not supported.\")\n\tdefault:\n\t\twriteSocks5Response(writer, statusCmdNotSupport, net.AnyIP, net.Port(0)) // nolint: errcheck\n\t\treturn nil, newError(\"unknown command \", cmd)\n\t}\n\n\trequest.Version = socks5Version\n\n\taddr, port, err := addrParser.ReadAddressPort(nil, reader)\n\tif err != nil {\n\t\treturn nil, newError(\"failed to read address\").Base(err)\n\t}\n\trequest.Address = addr\n\trequest.Port = port\n\n\tresponseAddress := net.AnyIP\n\tresponsePort := net.Port(1717)\n\tif request.Command == protocol.RequestCommandUDP {\n\t\taddr := s.config.Address.AsAddress()\n\t\tif addr == nil {\n\t\t\taddr = net.LocalHostIP\n\t\t}\n\t\tresponseAddress = addr\n\t\tresponsePort = s.port\n\t}\n\tif err := writeSocks5Response(writer, statusSuccess, responseAddress, responsePort); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn request, nil\n}\n\n// Handshake performs a Socks4/4a/5 handshake.\nfunc (s *ServerSession) Handshake(reader io.Reader, writer io.Writer) (*protocol.RequestHeader, error) {\n\tbuffer := buf.StackNew()\n\tif _, err := buffer.ReadFullFrom(reader, 2); err != nil {\n\t\tbuffer.Release()\n\t\treturn nil, newError(\"insufficient header\").Base(err)\n\t}\n\n\tversion := buffer.Byte(0)\n\tcmd := buffer.Byte(1)\n\tbuffer.Release()\n\n\tswitch version {\n\tcase socks4Version:\n\t\treturn s.handshake4(cmd, reader, writer)\n\tcase socks5Version:\n\t\treturn s.handshake5(cmd, reader, writer)\n\tdefault:\n\t\treturn nil, newError(\"unknown Socks version: \", version)\n\t}\n}\n\n// ReadUsernamePassword reads Socks 5 username/password message from the given reader.\n// +----+------+----------+------+----------+\n// |VER | ULEN |  UNAME   | PLEN |  PASSWD  |\n// +----+------+----------+------+----------+\n// | 1  |  1   | 1 to 255 |  1   | 1 to 255 |\n// +----+------+----------+------+----------+\nfunc ReadUsernamePassword(reader io.Reader) (string, string, error) {\n\tbuffer := buf.StackNew()\n\tdefer buffer.Release()\n\n\tif _, err := buffer.ReadFullFrom(reader, 2); err != nil {\n\t\treturn \"\", \"\", err\n\t}\n\tnUsername := int32(buffer.Byte(1))\n\n\tbuffer.Clear()\n\tif _, err := buffer.ReadFullFrom(reader, nUsername); err != nil {\n\t\treturn \"\", \"\", err\n\t}\n\tusername := buffer.String()\n\n\tbuffer.Clear()\n\tif _, err := buffer.ReadFullFrom(reader, 1); err != nil {\n\t\treturn \"\", \"\", err\n\t}\n\tnPassword := int32(buffer.Byte(0))\n\n\tbuffer.Clear()\n\tif _, err := buffer.ReadFullFrom(reader, nPassword); err != nil {\n\t\treturn \"\", \"\", err\n\t}\n\tpassword := buffer.String()\n\treturn username, password, nil\n}\n\n// ReadUntilNull reads content from given reader, until a null (0x00) byte.\nfunc ReadUntilNull(reader io.Reader) (string, error) {\n\tb := buf.StackNew()\n\tdefer b.Release()\n\n\tfor {\n\t\t_, err := b.ReadFullFrom(reader, 1)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\tif b.Byte(b.Len()-1) == 0x00 {\n\t\t\tb.Resize(0, b.Len()-1)\n\t\t\treturn b.String(), nil\n\t\t}\n\t\tif b.IsFull() {\n\t\t\treturn \"\", newError(\"buffer overrun\")\n\t\t}\n\t}\n}\n\nfunc hasAuthMethod(expectedAuth byte, authCandidates []byte) bool {\n\tfor _, a := range authCandidates {\n\t\tif a == expectedAuth {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc writeSocks5AuthenticationResponse(writer io.Writer, version byte, auth byte) error {\n\treturn buf.WriteAllBytes(writer, []byte{version, auth})\n}\n\nfunc writeSocks5Response(writer io.Writer, errCode byte, address net.Address, port net.Port) error {\n\tbuffer := buf.New()\n\tdefer buffer.Release()\n\n\tcommon.Must2(buffer.Write([]byte{socks5Version, errCode, 0x00 /* reserved */}))\n\tif err := addrParser.WriteAddressPort(buffer, address, port); err != nil {\n\t\treturn err\n\t}\n\n\treturn buf.WriteAllBytes(writer, buffer.Bytes())\n}\n\nfunc writeSocks4Response(writer io.Writer, errCode byte, address net.Address, port net.Port) error {\n\tbuffer := buf.StackNew()\n\tdefer buffer.Release()\n\n\tcommon.Must(buffer.WriteByte(0x00))\n\tcommon.Must(buffer.WriteByte(errCode))\n\tportBytes := buffer.Extend(2)\n\tbinary.BigEndian.PutUint16(portBytes, port.Value())\n\tcommon.Must2(buffer.Write(address.IP()))\n\treturn buf.WriteAllBytes(writer, buffer.Bytes())\n}\n\nfunc DecodeUDPPacket(packet *buf.Buffer) (*protocol.RequestHeader, error) {\n\tif packet.Len() < 5 {\n\t\treturn nil, newError(\"insufficient length of packet.\")\n\t}\n\trequest := &protocol.RequestHeader{\n\t\tVersion: socks5Version,\n\t\tCommand: protocol.RequestCommandUDP,\n\t}\n\n\t// packet[0] and packet[1] are reserved\n\tif packet.Byte(2) != 0 /* fragments */ {\n\t\treturn nil, newError(\"discarding fragmented payload.\")\n\t}\n\n\tpacket.Advance(3)\n\n\taddr, port, err := addrParser.ReadAddressPort(nil, packet)\n\tif err != nil {\n\t\treturn nil, newError(\"failed to read UDP header\").Base(err)\n\t}\n\trequest.Address = addr\n\trequest.Port = port\n\treturn request, nil\n}\n\nfunc EncodeUDPPacket(request *protocol.RequestHeader, data []byte) (*buf.Buffer, error) {\n\tb := buf.New()\n\tcommon.Must2(b.Write([]byte{0, 0, 0 /* Fragment */}))\n\tif err := addrParser.WriteAddressPort(b, request.Address, request.Port); err != nil {\n\t\tb.Release()\n\t\treturn nil, err\n\t}\n\tcommon.Must2(b.Write(data))\n\treturn b, nil\n}\n\ntype UDPReader struct {\n\treader io.Reader\n}\n\nfunc NewUDPReader(reader io.Reader) *UDPReader {\n\treturn &UDPReader{reader: reader}\n}\n\nfunc (r *UDPReader) ReadMultiBuffer() (buf.MultiBuffer, error) {\n\tb := buf.New()\n\tif _, err := b.ReadFrom(r.reader); err != nil {\n\t\treturn nil, err\n\t}\n\tif _, err := DecodeUDPPacket(b); err != nil {\n\t\treturn nil, err\n\t}\n\treturn buf.MultiBuffer{b}, nil\n}\n\ntype UDPWriter struct {\n\trequest *protocol.RequestHeader\n\twriter  io.Writer\n}\n\nfunc NewUDPWriter(request *protocol.RequestHeader, writer io.Writer) *UDPWriter {\n\treturn &UDPWriter{\n\t\trequest: request,\n\t\twriter:  writer,\n\t}\n}\n\n// Write implements io.Writer.\nfunc (w *UDPWriter) Write(b []byte) (int, error) {\n\teb, err := EncodeUDPPacket(w.request, b)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tdefer eb.Release()\n\tif _, err := w.writer.Write(eb.Bytes()); err != nil {\n\t\treturn 0, err\n\t}\n\treturn len(b), nil\n}\n\nfunc ClientHandshake(request *protocol.RequestHeader, reader io.Reader, writer io.Writer) (*protocol.RequestHeader, error) {\n\tauthByte := byte(authNotRequired)\n\tif request.User != nil {\n\t\tauthByte = byte(authPassword)\n\t}\n\n\tb := buf.New()\n\tdefer b.Release()\n\n\tcommon.Must2(b.Write([]byte{socks5Version, 0x01, authByte}))\n\tif authByte == authPassword {\n\t\taccount := request.User.Account.(*Account)\n\n\t\tcommon.Must(b.WriteByte(0x01))\n\t\tcommon.Must(b.WriteByte(byte(len(account.Username))))\n\t\tcommon.Must2(b.WriteString(account.Username))\n\t\tcommon.Must(b.WriteByte(byte(len(account.Password))))\n\t\tcommon.Must2(b.WriteString(account.Password))\n\t}\n\n\tif err := buf.WriteAllBytes(writer, b.Bytes()); err != nil {\n\t\treturn nil, err\n\t}\n\n\tb.Clear()\n\tif _, err := b.ReadFullFrom(reader, 2); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif b.Byte(0) != socks5Version {\n\t\treturn nil, newError(\"unexpected server version: \", b.Byte(0)).AtWarning()\n\t}\n\tif b.Byte(1) != authByte {\n\t\treturn nil, newError(\"auth method not supported.\").AtWarning()\n\t}\n\n\tif authByte == authPassword {\n\t\tb.Clear()\n\t\tif _, err := b.ReadFullFrom(reader, 2); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif b.Byte(1) != 0x00 {\n\t\t\treturn nil, newError(\"server rejects account: \", b.Byte(1))\n\t\t}\n\t}\n\n\tb.Clear()\n\n\tcommand := byte(cmdTCPConnect)\n\tif request.Command == protocol.RequestCommandUDP {\n\t\tcommand = byte(cmdUDPPort)\n\t}\n\tcommon.Must2(b.Write([]byte{socks5Version, command, 0x00 /* reserved */}))\n\tif err := addrParser.WriteAddressPort(b, request.Address, request.Port); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := buf.WriteAllBytes(writer, b.Bytes()); err != nil {\n\t\treturn nil, err\n\t}\n\n\tb.Clear()\n\tif _, err := b.ReadFullFrom(reader, 3); err != nil {\n\t\treturn nil, err\n\t}\n\n\tresp := b.Byte(1)\n\tif resp != 0x00 {\n\t\treturn nil, newError(\"server rejects request: \", resp)\n\t}\n\n\tb.Clear()\n\n\taddress, port, err := addrParser.ReadAddressPort(b, reader)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif request.Command == protocol.RequestCommandUDP {\n\t\tudpRequest := &protocol.RequestHeader{\n\t\t\tVersion: socks5Version,\n\t\t\tCommand: protocol.RequestCommandUDP,\n\t\t\tAddress: address,\n\t\t\tPort:    port,\n\t\t}\n\t\treturn udpRequest, nil\n\t}\n\n\treturn nil, nil\n}\n"
  },
  {
    "path": "proxy/socks/protocol_test.go",
    "content": "package socks_test\n\nimport (\n\t\"bytes\"\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t. \"v2ray.com/core/proxy/socks\"\n)\n\nfunc TestUDPEncoding(t *testing.T) {\n\tb := buf.New()\n\n\trequest := &protocol.RequestHeader{\n\t\tAddress: net.IPAddress([]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6}),\n\t\tPort:    1024,\n\t}\n\twriter := &buf.SequentialWriter{Writer: NewUDPWriter(request, b)}\n\n\tcontent := []byte{'a'}\n\tpayload := buf.New()\n\tpayload.Write(content)\n\tcommon.Must(writer.WriteMultiBuffer(buf.MultiBuffer{payload}))\n\n\treader := NewUDPReader(b)\n\n\tdecodedPayload, err := reader.ReadMultiBuffer()\n\tcommon.Must(err)\n\tif r := cmp.Diff(decodedPayload[0].Bytes(), content); r != \"\" {\n\t\tt.Error(r)\n\t}\n}\n\nfunc TestReadUsernamePassword(t *testing.T) {\n\ttestCases := []struct {\n\t\tInput    []byte\n\t\tUsername string\n\t\tPassword string\n\t\tError    bool\n\t}{\n\t\t{\n\t\t\tInput:    []byte{0x05, 0x01, 'a', 0x02, 'b', 'c'},\n\t\t\tUsername: \"a\",\n\t\t\tPassword: \"bc\",\n\t\t},\n\t\t{\n\t\t\tInput: []byte{0x05, 0x18, 'a', 0x02, 'b', 'c'},\n\t\t\tError: true,\n\t\t},\n\t}\n\n\tfor _, testCase := range testCases {\n\t\treader := bytes.NewReader(testCase.Input)\n\t\tusername, password, err := ReadUsernamePassword(reader)\n\t\tif testCase.Error {\n\t\t\tif err == nil {\n\t\t\t\tt.Error(\"for input: \", testCase.Input, \" expect error, but actually nil\")\n\t\t\t}\n\t\t} else {\n\t\t\tif err != nil {\n\t\t\t\tt.Error(\"for input: \", testCase.Input, \" expect no error, but actually \", err.Error())\n\t\t\t}\n\t\t\tif testCase.Username != username {\n\t\t\t\tt.Error(\"for input: \", testCase.Input, \" expect username \", testCase.Username, \" but actually \", username)\n\t\t\t}\n\t\t\tif testCase.Password != password {\n\t\t\t\tt.Error(\"for input: \", testCase.Input, \" expect passowrd \", testCase.Password, \" but actually \", password)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc TestReadUntilNull(t *testing.T) {\n\ttestCases := []struct {\n\t\tInput  []byte\n\t\tOutput string\n\t\tError  bool\n\t}{\n\t\t{\n\t\t\tInput:  []byte{'a', 'b', 0x00},\n\t\t\tOutput: \"ab\",\n\t\t},\n\t\t{\n\t\t\tInput: []byte{'a'},\n\t\t\tError: true,\n\t\t},\n\t}\n\n\tfor _, testCase := range testCases {\n\t\treader := bytes.NewReader(testCase.Input)\n\t\tvalue, err := ReadUntilNull(reader)\n\t\tif testCase.Error {\n\t\t\tif err == nil {\n\t\t\t\tt.Error(\"for input: \", testCase.Input, \" expect error, but actually nil\")\n\t\t\t}\n\t\t} else {\n\t\t\tif err != nil {\n\t\t\t\tt.Error(\"for input: \", testCase.Input, \" expect no error, but actually \", err.Error())\n\t\t\t}\n\t\t\tif testCase.Output != value {\n\t\t\t\tt.Error(\"for input: \", testCase.Input, \" expect output \", testCase.Output, \" but actually \", value)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc BenchmarkReadUsernamePassword(b *testing.B) {\n\tinput := []byte{0x05, 0x01, 'a', 0x02, 'b', 'c'}\n\tbuffer := buf.New()\n\tbuffer.Write(input)\n\n\tb.ResetTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\t_, _, err := ReadUsernamePassword(buffer)\n\t\tcommon.Must(err)\n\t\tbuffer.Clear()\n\t\tbuffer.Extend(int32(len(input)))\n\t}\n}\n"
  },
  {
    "path": "proxy/socks/server.go",
    "content": "// +build !confonly\n\npackage socks\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"time\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/log\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\tudp_proto \"v2ray.com/core/common/protocol/udp\"\n\t\"v2ray.com/core/common/session\"\n\t\"v2ray.com/core/common/signal\"\n\t\"v2ray.com/core/common/task\"\n\t\"v2ray.com/core/features\"\n\t\"v2ray.com/core/features/policy\"\n\t\"v2ray.com/core/features/routing\"\n\t\"v2ray.com/core/transport/internet\"\n\t\"v2ray.com/core/transport/internet/udp\"\n)\n\n// Server is a SOCKS 5 proxy server\ntype Server struct {\n\tconfig        *ServerConfig\n\tpolicyManager policy.Manager\n}\n\n// NewServer creates a new Server object.\nfunc NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {\n\tv := core.MustFromContext(ctx)\n\ts := &Server{\n\t\tconfig:        config,\n\t\tpolicyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),\n\t}\n\treturn s, nil\n}\n\nfunc (s *Server) policy() policy.Session {\n\tconfig := s.config\n\tp := s.policyManager.ForLevel(config.UserLevel)\n\tif config.Timeout > 0 {\n\t\tfeatures.PrintDeprecatedFeatureWarning(\"Socks timeout\")\n\t}\n\tif config.Timeout > 0 && config.UserLevel == 0 {\n\t\tp.Timeouts.ConnectionIdle = time.Duration(config.Timeout) * time.Second\n\t}\n\treturn p\n}\n\n// Network implements proxy.Inbound.\nfunc (s *Server) Network() []net.Network {\n\tlist := []net.Network{net.Network_TCP}\n\tif s.config.UdpEnabled {\n\t\tlist = append(list, net.Network_UDP)\n\t}\n\treturn list\n}\n\n// Process implements proxy.Inbound.\nfunc (s *Server) Process(ctx context.Context, network net.Network, conn internet.Connection, dispatcher routing.Dispatcher) error {\n\tif inbound := session.InboundFromContext(ctx); inbound != nil {\n\t\tinbound.User = &protocol.MemoryUser{\n\t\t\tLevel: s.config.UserLevel,\n\t\t}\n\t}\n\n\tswitch network {\n\tcase net.Network_TCP:\n\t\treturn s.processTCP(ctx, conn, dispatcher)\n\tcase net.Network_UDP:\n\t\treturn s.handleUDPPayload(ctx, conn, dispatcher)\n\tdefault:\n\t\treturn newError(\"unknown network: \", network)\n\t}\n}\n\nfunc (s *Server) processTCP(ctx context.Context, conn internet.Connection, dispatcher routing.Dispatcher) error {\n\tplcy := s.policy()\n\tif err := conn.SetReadDeadline(time.Now().Add(plcy.Timeouts.Handshake)); err != nil {\n\t\tnewError(\"failed to set deadline\").Base(err).WriteToLog(session.ExportIDToError(ctx))\n\t}\n\n\tinbound := session.InboundFromContext(ctx)\n\tif inbound == nil || !inbound.Gateway.IsValid() {\n\t\treturn newError(\"inbound gateway not specified\")\n\t}\n\n\tsvrSession := &ServerSession{\n\t\tconfig: s.config,\n\t\tport:   inbound.Gateway.Port,\n\t}\n\n\treader := &buf.BufferedReader{Reader: buf.NewReader(conn)}\n\trequest, err := svrSession.Handshake(reader, conn)\n\tif err != nil {\n\t\tif inbound != nil && inbound.Source.IsValid() {\n\t\t\tlog.Record(&log.AccessMessage{\n\t\t\t\tFrom:   inbound.Source,\n\t\t\t\tTo:     \"\",\n\t\t\t\tStatus: log.AccessRejected,\n\t\t\t\tReason: err,\n\t\t\t})\n\t\t}\n\t\treturn newError(\"failed to read request\").Base(err)\n\t}\n\tif request.User != nil {\n\t\tinbound.User.Email = request.User.Email\n\t}\n\n\tif err := conn.SetReadDeadline(time.Time{}); err != nil {\n\t\tnewError(\"failed to clear deadline\").Base(err).WriteToLog(session.ExportIDToError(ctx))\n\t}\n\n\tif request.Command == protocol.RequestCommandTCP {\n\t\tdest := request.Destination()\n\t\tnewError(\"TCP Connect request to \", dest).WriteToLog(session.ExportIDToError(ctx))\n\t\tif inbound != nil && inbound.Source.IsValid() {\n\t\t\tctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{\n\t\t\t\tFrom:   inbound.Source,\n\t\t\t\tTo:     dest,\n\t\t\t\tStatus: log.AccessAccepted,\n\t\t\t\tReason: \"\",\n\t\t\t})\n\t\t}\n\n\t\treturn s.transport(ctx, reader, conn, dest, dispatcher)\n\t}\n\n\tif request.Command == protocol.RequestCommandUDP {\n\t\treturn s.handleUDP(conn)\n\t}\n\n\treturn nil\n}\n\nfunc (*Server) handleUDP(c io.Reader) error {\n\t// The TCP connection closes after this method returns. We need to wait until\n\t// the client closes it.\n\treturn common.Error2(io.Copy(buf.DiscardBytes, c))\n}\n\nfunc (s *Server) transport(ctx context.Context, reader io.Reader, writer io.Writer, dest net.Destination, dispatcher routing.Dispatcher) error {\n\tctx, cancel := context.WithCancel(ctx)\n\ttimer := signal.CancelAfterInactivity(ctx, cancel, s.policy().Timeouts.ConnectionIdle)\n\n\tplcy := s.policy()\n\tctx = policy.ContextWithBufferPolicy(ctx, plcy.Buffer)\n\tlink, err := dispatcher.Dispatch(ctx, dest)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\trequestDone := func() error {\n\t\tdefer timer.SetTimeout(plcy.Timeouts.DownlinkOnly)\n\t\tif err := buf.Copy(buf.NewReader(reader), link.Writer, buf.UpdateActivity(timer)); err != nil {\n\t\t\treturn newError(\"failed to transport all TCP request\").Base(err)\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tresponseDone := func() error {\n\t\tdefer timer.SetTimeout(plcy.Timeouts.UplinkOnly)\n\n\t\tv2writer := buf.NewWriter(writer)\n\t\tif err := buf.Copy(link.Reader, v2writer, buf.UpdateActivity(timer)); err != nil {\n\t\t\treturn newError(\"failed to transport all TCP response\").Base(err)\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tvar requestDonePost = task.OnSuccess(requestDone, task.Close(link.Writer))\n\tif err := task.Run(ctx, requestDonePost, responseDone); err != nil {\n\t\tcommon.Interrupt(link.Reader)\n\t\tcommon.Interrupt(link.Writer)\n\t\treturn newError(\"connection ends\").Base(err)\n\t}\n\n\treturn nil\n}\n\nfunc (s *Server) handleUDPPayload(ctx context.Context, conn internet.Connection, dispatcher routing.Dispatcher) error {\n\tudpServer := udp.NewDispatcher(dispatcher, func(ctx context.Context, packet *udp_proto.Packet) {\n\t\tpayload := packet.Payload\n\t\tnewError(\"writing back UDP response with \", payload.Len(), \" bytes\").AtDebug().WriteToLog(session.ExportIDToError(ctx))\n\n\t\trequest := protocol.RequestHeaderFromContext(ctx)\n\t\tif request == nil {\n\t\t\treturn\n\t\t}\n\t\tudpMessage, err := EncodeUDPPacket(request, payload.Bytes())\n\t\tpayload.Release()\n\n\t\tdefer udpMessage.Release()\n\t\tif err != nil {\n\t\t\tnewError(\"failed to write UDP response\").AtWarning().Base(err).WriteToLog(session.ExportIDToError(ctx))\n\t\t}\n\n\t\tconn.Write(udpMessage.Bytes()) // nolint: errcheck\n\t})\n\n\tif inbound := session.InboundFromContext(ctx); inbound != nil && inbound.Source.IsValid() {\n\t\tnewError(\"client UDP connection from \", inbound.Source).WriteToLog(session.ExportIDToError(ctx))\n\t}\n\n\treader := buf.NewPacketReader(conn)\n\tfor {\n\t\tmpayload, err := reader.ReadMultiBuffer()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tfor _, payload := range mpayload {\n\t\t\trequest, err := DecodeUDPPacket(payload)\n\n\t\t\tif err != nil {\n\t\t\t\tnewError(\"failed to parse UDP request\").Base(err).WriteToLog(session.ExportIDToError(ctx))\n\t\t\t\tpayload.Release()\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif payload.IsEmpty() {\n\t\t\t\tpayload.Release()\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tcurrentPacketCtx := ctx\n\t\t\tnewError(\"send packet to \", request.Destination(), \" with \", payload.Len(), \" bytes\").AtDebug().WriteToLog(session.ExportIDToError(ctx))\n\t\t\tif inbound := session.InboundFromContext(ctx); inbound != nil && inbound.Source.IsValid() {\n\t\t\t\tcurrentPacketCtx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{\n\t\t\t\t\tFrom:   inbound.Source,\n\t\t\t\t\tTo:     request.Destination(),\n\t\t\t\t\tStatus: log.AccessAccepted,\n\t\t\t\t\tReason: \"\",\n\t\t\t\t})\n\t\t\t}\n\n\t\t\tcurrentPacketCtx = protocol.ContextWithRequestHeader(currentPacketCtx, request)\n\t\t\tudpServer.Dispatch(currentPacketCtx, request.Destination(), payload)\n\t\t}\n\t}\n}\n\nfunc init() {\n\tcommon.Must(common.RegisterConfig((*ServerConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {\n\t\treturn NewServer(ctx, config.(*ServerConfig))\n\t}))\n}\n"
  },
  {
    "path": "proxy/socks/socks.go",
    "content": "// Package socks provides implements of Socks protocol 4, 4a and 5.\npackage socks\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n"
  },
  {
    "path": "proxy/trojan/client.go",
    "content": "// +build !confonly\n\npackage trojan\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/retry\"\n\t\"v2ray.com/core/common/session\"\n\t\"v2ray.com/core/common/signal\"\n\t\"v2ray.com/core/common/task\"\n\t\"v2ray.com/core/features/policy\"\n\t\"v2ray.com/core/transport\"\n\t\"v2ray.com/core/transport/internet\"\n)\n\n// Client is a inbound handler for trojan protocol\ntype Client struct {\n\tserverPicker  protocol.ServerPicker\n\tpolicyManager policy.Manager\n}\n\n// NewClient create a new trojan client.\nfunc NewClient(ctx context.Context, config *ClientConfig) (*Client, error) {\n\tserverList := protocol.NewServerList()\n\tfor _, rec := range config.Server {\n\t\ts, err := protocol.NewServerSpecFromPB(rec)\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"failed to parse server spec\").Base(err)\n\t\t}\n\t\tserverList.AddServer(s)\n\t}\n\tif serverList.Size() == 0 {\n\t\treturn nil, newError(\"0 server\")\n\t}\n\n\tv := core.MustFromContext(ctx)\n\tclient := &Client{\n\t\tserverPicker:  protocol.NewRoundRobinServerPicker(serverList),\n\t\tpolicyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),\n\t}\n\treturn client, nil\n}\n\n// Process implements OutboundHandler.Process().\nfunc (c *Client) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error { // nolint: funlen\n\toutbound := session.OutboundFromContext(ctx)\n\tif outbound == nil || !outbound.Target.IsValid() {\n\t\treturn newError(\"target not specified\")\n\t}\n\tdestination := outbound.Target\n\tnetwork := destination.Network\n\n\tvar server *protocol.ServerSpec\n\tvar conn internet.Connection\n\n\terr := retry.ExponentialBackoff(5, 100).On(func() error { // nolint: gomnd\n\t\tserver = c.serverPicker.PickServer()\n\t\trawConn, err := dialer.Dial(ctx, server.Destination())\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tconn = rawConn\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\treturn newError(\"failed to find an available destination\").AtWarning().Base(err)\n\t}\n\tnewError(\"tunneling request to \", destination, \" via \", server.Destination()).WriteToLog(session.ExportIDToError(ctx))\n\n\tdefer conn.Close()\n\n\tuser := server.PickUser()\n\taccount, ok := user.Account.(*MemoryAccount)\n\tif !ok {\n\t\treturn newError(\"user account is not valid\")\n\t}\n\n\tsessionPolicy := c.policyManager.ForLevel(user.Level)\n\tctx, cancel := context.WithCancel(ctx)\n\ttimer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)\n\n\tpostRequest := func() error {\n\t\tdefer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)\n\n\t\tvar bodyWriter buf.Writer\n\t\tbufferWriter := buf.NewBufferedWriter(buf.NewWriter(conn))\n\t\tconnWriter := &ConnWriter{Writer: bufferWriter, Target: destination, Account: account}\n\n\t\tif destination.Network == net.Network_UDP {\n\t\t\tbodyWriter = &PacketWriter{Writer: connWriter, Target: destination}\n\t\t} else {\n\t\t\tbodyWriter = connWriter\n\t\t}\n\n\t\t// write some request payload to buffer\n\t\tif err = buf.CopyOnceTimeout(link.Reader, bodyWriter, time.Millisecond*100); err != nil && err != buf.ErrNotTimeoutReader && err != buf.ErrReadTimeout { // nolint: lll,gomnd\n\t\t\treturn newError(\"failed to write A reqeust payload\").Base(err).AtWarning()\n\t\t}\n\n\t\t// Flush; bufferWriter.WriteMultiBufer now is bufferWriter.writer.WriteMultiBuffer\n\t\tif err = bufferWriter.SetBuffered(false); err != nil {\n\t\t\treturn newError(\"failed to flush payload\").Base(err).AtWarning()\n\t\t}\n\n\t\tif err = buf.Copy(link.Reader, bodyWriter, buf.UpdateActivity(timer)); err != nil {\n\t\t\treturn newError(\"failed to transfer request payload\").Base(err).AtInfo()\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tgetResponse := func() error {\n\t\tdefer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)\n\n\t\tvar reader buf.Reader\n\t\tif network == net.Network_UDP {\n\t\t\treader = &PacketReader{\n\t\t\t\tReader: conn,\n\t\t\t}\n\t\t} else {\n\t\t\treader = buf.NewReader(conn)\n\t\t}\n\t\treturn buf.Copy(reader, link.Writer, buf.UpdateActivity(timer))\n\t}\n\n\tvar responseDoneAndCloseWriter = task.OnSuccess(getResponse, task.Close(link.Writer))\n\tif err := task.Run(ctx, postRequest, responseDoneAndCloseWriter); err != nil {\n\t\treturn newError(\"connection ends\").Base(err)\n\t}\n\n\treturn nil\n}\n\nfunc init() {\n\tcommon.Must(common.RegisterConfig((*ClientConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { // nolint: lll\n\t\treturn NewClient(ctx, config.(*ClientConfig))\n\t}))\n}\n"
  },
  {
    "path": "proxy/trojan/config.go",
    "content": "package trojan\n\nimport (\n\t\"crypto/sha256\"\n\t\"encoding/hex\"\n\tfmt \"fmt\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/protocol\"\n)\n\n// MemoryAccount is an account type converted from Account.\ntype MemoryAccount struct {\n\tPassword string\n\tKey      []byte\n}\n\n// AsAccount implements protocol.AsAccount.\nfunc (a *Account) AsAccount() (protocol.Account, error) {\n\tpassword := a.GetPassword()\n\tkey := hexSha224(password)\n\treturn &MemoryAccount{\n\t\tPassword: password,\n\t\tKey:      key,\n\t}, nil\n}\n\n// Equals implements protocol.Account.Equals().\nfunc (a *MemoryAccount) Equals(another protocol.Account) bool {\n\tif account, ok := another.(*MemoryAccount); ok {\n\t\treturn a.Password == account.Password\n\t}\n\treturn false\n}\n\nfunc hexSha224(password string) []byte {\n\tbuf := make([]byte, 56)\n\thash := sha256.New224()\n\tcommon.Must2(hash.Write([]byte(password)))\n\thex.Encode(buf, hash.Sum(nil))\n\treturn buf\n}\n\nfunc hexString(data []byte) string {\n\tstr := \"\"\n\tfor _, v := range data {\n\t\tstr += fmt.Sprintf(\"%02x\", v)\n\t}\n\treturn str\n}\n"
  },
  {
    "path": "proxy/trojan/config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: proxy/trojan/config.proto\n\npackage trojan\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n\tprotocol \"v2ray.com/core/common/protocol\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype Account struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tPassword string `protobuf:\"bytes,1,opt,name=password,proto3\" json:\"password,omitempty\"`\n}\n\nfunc (x *Account) Reset() {\n\t*x = Account{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_proxy_trojan_config_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Account) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Account) ProtoMessage() {}\n\nfunc (x *Account) ProtoReflect() protoreflect.Message {\n\tmi := &file_proxy_trojan_config_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Account.ProtoReflect.Descriptor instead.\nfunc (*Account) Descriptor() ([]byte, []int) {\n\treturn file_proxy_trojan_config_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *Account) GetPassword() string {\n\tif x != nil {\n\t\treturn x.Password\n\t}\n\treturn \"\"\n}\n\ntype Fallback struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tAlpn string `protobuf:\"bytes,1,opt,name=alpn,proto3\" json:\"alpn,omitempty\"`\n\tPath string `protobuf:\"bytes,2,opt,name=path,proto3\" json:\"path,omitempty\"`\n\tType string `protobuf:\"bytes,3,opt,name=type,proto3\" json:\"type,omitempty\"`\n\tDest string `protobuf:\"bytes,4,opt,name=dest,proto3\" json:\"dest,omitempty\"`\n\tXver uint64 `protobuf:\"varint,5,opt,name=xver,proto3\" json:\"xver,omitempty\"`\n}\n\nfunc (x *Fallback) Reset() {\n\t*x = Fallback{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_proxy_trojan_config_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Fallback) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Fallback) ProtoMessage() {}\n\nfunc (x *Fallback) ProtoReflect() protoreflect.Message {\n\tmi := &file_proxy_trojan_config_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Fallback.ProtoReflect.Descriptor instead.\nfunc (*Fallback) Descriptor() ([]byte, []int) {\n\treturn file_proxy_trojan_config_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *Fallback) GetAlpn() string {\n\tif x != nil {\n\t\treturn x.Alpn\n\t}\n\treturn \"\"\n}\n\nfunc (x *Fallback) GetPath() string {\n\tif x != nil {\n\t\treturn x.Path\n\t}\n\treturn \"\"\n}\n\nfunc (x *Fallback) GetType() string {\n\tif x != nil {\n\t\treturn x.Type\n\t}\n\treturn \"\"\n}\n\nfunc (x *Fallback) GetDest() string {\n\tif x != nil {\n\t\treturn x.Dest\n\t}\n\treturn \"\"\n}\n\nfunc (x *Fallback) GetXver() uint64 {\n\tif x != nil {\n\t\treturn x.Xver\n\t}\n\treturn 0\n}\n\ntype ClientConfig struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tServer []*protocol.ServerEndpoint `protobuf:\"bytes,1,rep,name=server,proto3\" json:\"server,omitempty\"`\n}\n\nfunc (x *ClientConfig) Reset() {\n\t*x = ClientConfig{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_proxy_trojan_config_proto_msgTypes[2]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *ClientConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ClientConfig) ProtoMessage() {}\n\nfunc (x *ClientConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_proxy_trojan_config_proto_msgTypes[2]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ClientConfig.ProtoReflect.Descriptor instead.\nfunc (*ClientConfig) Descriptor() ([]byte, []int) {\n\treturn file_proxy_trojan_config_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *ClientConfig) GetServer() []*protocol.ServerEndpoint {\n\tif x != nil {\n\t\treturn x.Server\n\t}\n\treturn nil\n}\n\ntype ServerConfig struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tUsers     []*protocol.User `protobuf:\"bytes,1,rep,name=users,proto3\" json:\"users,omitempty\"`\n\tFallbacks []*Fallback      `protobuf:\"bytes,3,rep,name=fallbacks,proto3\" json:\"fallbacks,omitempty\"`\n}\n\nfunc (x *ServerConfig) Reset() {\n\t*x = ServerConfig{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_proxy_trojan_config_proto_msgTypes[3]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *ServerConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ServerConfig) ProtoMessage() {}\n\nfunc (x *ServerConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_proxy_trojan_config_proto_msgTypes[3]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ServerConfig.ProtoReflect.Descriptor instead.\nfunc (*ServerConfig) Descriptor() ([]byte, []int) {\n\treturn file_proxy_trojan_config_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *ServerConfig) GetUsers() []*protocol.User {\n\tif x != nil {\n\t\treturn x.Users\n\t}\n\treturn nil\n}\n\nfunc (x *ServerConfig) GetFallbacks() []*Fallback {\n\tif x != nil {\n\t\treturn x.Fallbacks\n\t}\n\treturn nil\n}\n\nvar File_proxy_trojan_config_proto protoreflect.FileDescriptor\n\nvar file_proxy_trojan_config_proto_rawDesc = []byte{\n\t0x0a, 0x19, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x74, 0x72, 0x6f, 0x6a, 0x61, 0x6e, 0x2f, 0x63,\n\t0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x17, 0x76, 0x32, 0x72,\n\t0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x74, 0x72,\n\t0x6f, 0x6a, 0x61, 0x6e, 0x1a, 0x1a, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f,\n\t0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,\n\t0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,\n\t0x6c, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x2e, 0x70, 0x72,\n\t0x6f, 0x74, 0x6f, 0x22, 0x25, 0x0a, 0x07, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1a,\n\t0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,\n\t0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x6e, 0x0a, 0x08, 0x46, 0x61,\n\t0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x6c, 0x70, 0x6e, 0x18, 0x01,\n\t0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x61, 0x6c, 0x70, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61,\n\t0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x12,\n\t0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79,\n\t0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x65, 0x73, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09,\n\t0x52, 0x04, 0x64, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x78, 0x76, 0x65, 0x72, 0x18, 0x05,\n\t0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x78, 0x76, 0x65, 0x72, 0x22, 0x52, 0x0a, 0x0c, 0x43, 0x6c,\n\t0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x42, 0x0a, 0x06, 0x73, 0x65,\n\t0x72, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x76, 0x32, 0x72,\n\t0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70,\n\t0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e,\n\t0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0x87,\n\t0x01, 0x0a, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,\n\t0x36, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20,\n\t0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,\n\t0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x55, 0x73, 0x65, 0x72,\n\t0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x12, 0x3f, 0x0a, 0x09, 0x66, 0x61, 0x6c, 0x6c, 0x62,\n\t0x61, 0x63, 0x6b, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x76, 0x32, 0x72,\n\t0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x74, 0x72,\n\t0x6f, 0x6a, 0x61, 0x6e, 0x2e, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x09, 0x66,\n\t0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x73, 0x42, 0x56, 0x0a, 0x1b, 0x63, 0x6f, 0x6d, 0x2e,\n\t0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79,\n\t0x2e, 0x74, 0x72, 0x6f, 0x6a, 0x61, 0x6e, 0x50, 0x01, 0x5a, 0x1b, 0x76, 0x32, 0x72, 0x61, 0x79,\n\t0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f,\n\t0x74, 0x72, 0x6f, 0x6a, 0x61, 0x6e, 0xaa, 0x02, 0x17, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43,\n\t0x6f, 0x72, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x54, 0x72, 0x6f, 0x6a, 0x61, 0x6e,\n\t0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_proxy_trojan_config_proto_rawDescOnce sync.Once\n\tfile_proxy_trojan_config_proto_rawDescData = file_proxy_trojan_config_proto_rawDesc\n)\n\nfunc file_proxy_trojan_config_proto_rawDescGZIP() []byte {\n\tfile_proxy_trojan_config_proto_rawDescOnce.Do(func() {\n\t\tfile_proxy_trojan_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_proxy_trojan_config_proto_rawDescData)\n\t})\n\treturn file_proxy_trojan_config_proto_rawDescData\n}\n\nvar file_proxy_trojan_config_proto_msgTypes = make([]protoimpl.MessageInfo, 4)\nvar file_proxy_trojan_config_proto_goTypes = []interface{}{\n\t(*Account)(nil),                 // 0: v2ray.core.proxy.trojan.Account\n\t(*Fallback)(nil),                // 1: v2ray.core.proxy.trojan.Fallback\n\t(*ClientConfig)(nil),            // 2: v2ray.core.proxy.trojan.ClientConfig\n\t(*ServerConfig)(nil),            // 3: v2ray.core.proxy.trojan.ServerConfig\n\t(*protocol.ServerEndpoint)(nil), // 4: v2ray.core.common.protocol.ServerEndpoint\n\t(*protocol.User)(nil),           // 5: v2ray.core.common.protocol.User\n}\nvar file_proxy_trojan_config_proto_depIdxs = []int32{\n\t4, // 0: v2ray.core.proxy.trojan.ClientConfig.server:type_name -> v2ray.core.common.protocol.ServerEndpoint\n\t5, // 1: v2ray.core.proxy.trojan.ServerConfig.users:type_name -> v2ray.core.common.protocol.User\n\t1, // 2: v2ray.core.proxy.trojan.ServerConfig.fallbacks:type_name -> v2ray.core.proxy.trojan.Fallback\n\t3, // [3:3] is the sub-list for method output_type\n\t3, // [3:3] is the sub-list for method input_type\n\t3, // [3:3] is the sub-list for extension type_name\n\t3, // [3:3] is the sub-list for extension extendee\n\t0, // [0:3] is the sub-list for field type_name\n}\n\nfunc init() { file_proxy_trojan_config_proto_init() }\nfunc file_proxy_trojan_config_proto_init() {\n\tif File_proxy_trojan_config_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_proxy_trojan_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Account); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_proxy_trojan_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Fallback); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_proxy_trojan_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*ClientConfig); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_proxy_trojan_config_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*ServerConfig); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_proxy_trojan_config_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   4,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_proxy_trojan_config_proto_goTypes,\n\t\tDependencyIndexes: file_proxy_trojan_config_proto_depIdxs,\n\t\tMessageInfos:      file_proxy_trojan_config_proto_msgTypes,\n\t}.Build()\n\tFile_proxy_trojan_config_proto = out.File\n\tfile_proxy_trojan_config_proto_rawDesc = nil\n\tfile_proxy_trojan_config_proto_goTypes = nil\n\tfile_proxy_trojan_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "proxy/trojan/config.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.proxy.trojan;\noption csharp_namespace = \"V2Ray.Core.Proxy.Trojan\";\noption go_package = \"v2ray.com/core/proxy/trojan\";\noption java_package = \"com.v2ray.core.proxy.trojan\";\noption java_multiple_files = true;\n\nimport \"common/protocol/user.proto\";\nimport \"common/protocol/server_spec.proto\";\n\nmessage Account {\n  string password = 1;\n}\n\nmessage Fallback {\n  string alpn = 1;\n  string path = 2;\n  string type = 3;\n  string dest = 4;\n  uint64 xver = 5;\n}\n\nmessage ClientConfig {\n  repeated v2ray.core.common.protocol.ServerEndpoint server = 1;\n}\n\nmessage ServerConfig {\n  repeated v2ray.core.common.protocol.User users = 1;\n  repeated Fallback fallbacks = 3;\n}\n"
  },
  {
    "path": "proxy/trojan/errors.generated.go",
    "content": "package trojan\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "proxy/trojan/protocol.go",
    "content": "package trojan\n\nimport (\n\t\"encoding/binary\"\n\t\"io\"\n\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n)\n\nvar (\n\tcrlf = []byte{'\\r', '\\n'}\n\n\taddrParser = protocol.NewAddressParser(\n\t\tprotocol.AddressFamilyByte(0x01, net.AddressFamilyIPv4),   // nolint: gomnd\n\t\tprotocol.AddressFamilyByte(0x04, net.AddressFamilyIPv6),   // nolint: gomnd\n\t\tprotocol.AddressFamilyByte(0x03, net.AddressFamilyDomain), // nolint: gomnd\n\t)\n)\n\nconst (\n\tmaxLength = 8192\n\n\tcommandTCP byte = 1\n\tcommandUDP byte = 3\n)\n\n// ConnWriter is TCP Connection Writer Wrapper for trojan protocol\ntype ConnWriter struct {\n\tio.Writer\n\tTarget     net.Destination\n\tAccount    *MemoryAccount\n\theaderSent bool\n}\n\n// Write implements io.Writer\nfunc (c *ConnWriter) Write(p []byte) (n int, err error) {\n\tif !c.headerSent {\n\t\tif err := c.writeHeader(); err != nil {\n\t\t\treturn 0, newError(\"failed to write request header\").Base(err)\n\t\t}\n\t}\n\n\treturn c.Writer.Write(p)\n}\n\n// WriteMultiBuffer implements buf.Writer\nfunc (c *ConnWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {\n\tdefer buf.ReleaseMulti(mb)\n\n\tfor _, b := range mb {\n\t\tif !b.IsEmpty() {\n\t\t\tif _, err := c.Write(b.Bytes()); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (c *ConnWriter) writeHeader() error {\n\tbuffer := buf.StackNew()\n\tdefer buffer.Release()\n\n\tcommand := commandTCP\n\tif c.Target.Network == net.Network_UDP {\n\t\tcommand = commandUDP\n\t}\n\n\tif _, err := buffer.Write(c.Account.Key); err != nil {\n\t\treturn err\n\t}\n\tif _, err := buffer.Write(crlf); err != nil {\n\t\treturn err\n\t}\n\tif err := buffer.WriteByte(command); err != nil {\n\t\treturn err\n\t}\n\tif err := addrParser.WriteAddressPort(&buffer, c.Target.Address, c.Target.Port); err != nil {\n\t\treturn err\n\t}\n\tif _, err := buffer.Write(crlf); err != nil {\n\t\treturn err\n\t}\n\n\t_, err := c.Writer.Write(buffer.Bytes())\n\tif err == nil {\n\t\tc.headerSent = true\n\t}\n\n\treturn err\n}\n\n// PacketWriter UDP Connection Writer Wrapper for trojan protocol\ntype PacketWriter struct {\n\tio.Writer\n\tTarget net.Destination\n}\n\n// WriteMultiBuffer implements buf.Writer\nfunc (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {\n\tb := make([]byte, maxLength)\n\tfor !mb.IsEmpty() {\n\t\tvar length int\n\t\tmb, length = buf.SplitBytes(mb, b)\n\t\tif _, err := w.writePacket(b[:length], w.Target); err != nil {\n\t\t\tbuf.ReleaseMulti(mb)\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// WriteMultiBufferWithMetadata writes udp packet with destination specified\nfunc (w *PacketWriter) WriteMultiBufferWithMetadata(mb buf.MultiBuffer, dest net.Destination) error {\n\tb := make([]byte, maxLength)\n\tfor !mb.IsEmpty() {\n\t\tvar length int\n\t\tmb, length = buf.SplitBytes(mb, b)\n\t\tif _, err := w.writePacket(b[:length], dest); err != nil {\n\t\t\tbuf.ReleaseMulti(mb)\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (w *PacketWriter) writePacket(payload []byte, dest net.Destination) (int, error) { // nolint: unparam\n\tbuffer := buf.StackNew()\n\tdefer buffer.Release()\n\n\tlength := len(payload)\n\tlengthBuf := [2]byte{}\n\tbinary.BigEndian.PutUint16(lengthBuf[:], uint16(length))\n\tif err := addrParser.WriteAddressPort(&buffer, dest.Address, dest.Port); err != nil {\n\t\treturn 0, err\n\t}\n\tif _, err := buffer.Write(lengthBuf[:]); err != nil {\n\t\treturn 0, err\n\t}\n\tif _, err := buffer.Write(crlf); err != nil {\n\t\treturn 0, err\n\t}\n\tif _, err := buffer.Write(payload); err != nil {\n\t\treturn 0, err\n\t}\n\t_, err := w.Write(buffer.Bytes())\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn length, nil\n}\n\n// ConnReader is TCP Connection Reader Wrapper for trojan protocol\ntype ConnReader struct {\n\tio.Reader\n\tTarget       net.Destination\n\theaderParsed bool\n}\n\n// ParseHeader parses the trojan protocol header\nfunc (c *ConnReader) ParseHeader() error {\n\tvar crlf [2]byte\n\tvar command [1]byte\n\tvar hash [56]byte\n\tif _, err := io.ReadFull(c.Reader, hash[:]); err != nil {\n\t\treturn newError(\"failed to read user hash\").Base(err)\n\t}\n\n\tif _, err := io.ReadFull(c.Reader, crlf[:]); err != nil {\n\t\treturn newError(\"failed to read crlf\").Base(err)\n\t}\n\n\tif _, err := io.ReadFull(c.Reader, command[:]); err != nil {\n\t\treturn newError(\"failed to read command\").Base(err)\n\t}\n\n\tnetwork := net.Network_TCP\n\tif command[0] == commandUDP {\n\t\tnetwork = net.Network_UDP\n\t}\n\n\taddr, port, err := addrParser.ReadAddressPort(nil, c.Reader)\n\tif err != nil {\n\t\treturn newError(\"failed to read address and port\").Base(err)\n\t}\n\tc.Target = net.Destination{Network: network, Address: addr, Port: port}\n\n\tif _, err := io.ReadFull(c.Reader, crlf[:]); err != nil {\n\t\treturn newError(\"failed to read crlf\").Base(err)\n\t}\n\n\tc.headerParsed = true\n\treturn nil\n}\n\n// Read implements io.Reader\nfunc (c *ConnReader) Read(p []byte) (int, error) {\n\tif !c.headerParsed {\n\t\tif err := c.ParseHeader(); err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t}\n\n\treturn c.Reader.Read(p)\n}\n\n// ReadMultiBuffer implements buf.Reader\nfunc (c *ConnReader) ReadMultiBuffer() (buf.MultiBuffer, error) {\n\tb := buf.New()\n\t_, err := b.ReadFrom(c)\n\treturn buf.MultiBuffer{b}, err\n}\n\n// PacketPayload combines udp payload and destination\ntype PacketPayload struct {\n\tTarget net.Destination\n\tBuffer buf.MultiBuffer\n}\n\n// PacketReader is UDP Connection Reader Wrapper for trojan protocol\ntype PacketReader struct {\n\tio.Reader\n}\n\n// ReadMultiBuffer implements buf.Reader\nfunc (r *PacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {\n\tp, err := r.ReadMultiBufferWithMetadata()\n\tif p != nil {\n\t\treturn p.Buffer, err\n\t}\n\treturn nil, err\n}\n\n// ReadMultiBufferWithMetadata reads udp packet with destination\nfunc (r *PacketReader) ReadMultiBufferWithMetadata() (*PacketPayload, error) {\n\taddr, port, err := addrParser.ReadAddressPort(nil, r)\n\tif err != nil {\n\t\treturn nil, newError(\"failed to read address and port\").Base(err)\n\t}\n\n\tvar lengthBuf [2]byte\n\tif _, err := io.ReadFull(r, lengthBuf[:]); err != nil {\n\t\treturn nil, newError(\"failed to read payload length\").Base(err)\n\t}\n\n\tremain := int(binary.BigEndian.Uint16(lengthBuf[:]))\n\tif remain > maxLength {\n\t\treturn nil, newError(\"oversize payload\")\n\t}\n\n\tvar crlf [2]byte\n\tif _, err := io.ReadFull(r, crlf[:]); err != nil {\n\t\treturn nil, newError(\"failed to read crlf\").Base(err)\n\t}\n\n\tdest := net.UDPDestination(addr, port)\n\tvar mb buf.MultiBuffer\n\tfor remain > 0 {\n\t\tlength := buf.Size\n\t\tif remain < length {\n\t\t\tlength = remain\n\t\t}\n\n\t\tb := buf.New()\n\t\tmb = append(mb, b)\n\t\tn, err := b.ReadFullFrom(r, int32(length))\n\t\tif err != nil {\n\t\t\tbuf.ReleaseMulti(mb)\n\t\t\treturn nil, newError(\"failed to read payload\").Base(err)\n\t\t}\n\n\t\tremain -= int(n)\n\t}\n\n\treturn &PacketPayload{Target: dest, Buffer: mb}, nil\n}\n"
  },
  {
    "path": "proxy/trojan/protocol_test.go",
    "content": "package trojan_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t. \"v2ray.com/core/proxy/trojan\"\n)\n\nfunc toAccount(a *Account) protocol.Account {\n\taccount, err := a.AsAccount()\n\tcommon.Must(err)\n\treturn account\n}\n\nfunc TestTCPRequest(t *testing.T) {\n\tuser := &protocol.MemoryUser{\n\t\tEmail: \"love@v2ray.com\",\n\t\tAccount: toAccount(&Account{\n\t\t\tPassword: \"password\",\n\t\t}),\n\t}\n\tpayload := []byte(\"test string\")\n\tdata := buf.New()\n\tcommon.Must2(data.Write(payload))\n\n\tbuffer := buf.New()\n\tdefer buffer.Release()\n\n\tdestination := net.Destination{Network: net.Network_TCP, Address: net.LocalHostIP, Port: 1234}\n\twriter := &ConnWriter{Writer: buffer, Target: destination, Account: user.Account.(*MemoryAccount)}\n\tcommon.Must(writer.WriteMultiBuffer(buf.MultiBuffer{data}))\n\n\treader := &ConnReader{Reader: buffer}\n\tcommon.Must(reader.ParseHeader())\n\n\tif r := cmp.Diff(reader.Target, destination); r != \"\" {\n\t\tt.Error(\"destination: \", r)\n\t}\n\n\tdecodedData, err := reader.ReadMultiBuffer()\n\tcommon.Must(err)\n\tif r := cmp.Diff(decodedData[0].Bytes(), payload); r != \"\" {\n\t\tt.Error(\"data: \", r)\n\t}\n}\n\nfunc TestUDPRequest(t *testing.T) {\n\tuser := &protocol.MemoryUser{\n\t\tEmail: \"love@v2ray.com\",\n\t\tAccount: toAccount(&Account{\n\t\t\tPassword: \"password\",\n\t\t}),\n\t}\n\tpayload := []byte(\"test string\")\n\tdata := buf.New()\n\tcommon.Must2(data.Write(payload))\n\n\tbuffer := buf.New()\n\tdefer buffer.Release()\n\n\tdestination := net.Destination{Network: net.Network_UDP, Address: net.LocalHostIP, Port: 1234}\n\twriter := &PacketWriter{Writer: &ConnWriter{Writer: buffer, Target: destination, Account: user.Account.(*MemoryAccount)}, Target: destination}\n\tcommon.Must(writer.WriteMultiBuffer(buf.MultiBuffer{data}))\n\n\tconnReader := &ConnReader{Reader: buffer}\n\tcommon.Must(connReader.ParseHeader())\n\n\tpacketReader := &PacketReader{Reader: connReader}\n\tp, err := packetReader.ReadMultiBufferWithMetadata()\n\tcommon.Must(err)\n\n\tif p.Buffer.IsEmpty() {\n\t\tt.Error(\"no request data\")\n\t}\n\n\tif r := cmp.Diff(p.Target, destination); r != \"\" {\n\t\tt.Error(\"destination: \", r)\n\t}\n\n\tmb, decoded := buf.SplitFirst(p.Buffer)\n\tbuf.ReleaseMulti(mb)\n\n\tif r := cmp.Diff(decoded.Bytes(), payload); r != \"\" {\n\t\tt.Error(\"data: \", r)\n\t}\n}\n"
  },
  {
    "path": "proxy/trojan/server.go",
    "content": "// +build !confonly\n\npackage trojan\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"io\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/errors\"\n\t\"v2ray.com/core/common/log\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\tudp_proto \"v2ray.com/core/common/protocol/udp\"\n\t\"v2ray.com/core/common/retry\"\n\t\"v2ray.com/core/common/session\"\n\t\"v2ray.com/core/common/signal\"\n\t\"v2ray.com/core/common/task\"\n\t\"v2ray.com/core/features/policy\"\n\t\"v2ray.com/core/features/routing\"\n\t\"v2ray.com/core/transport/internet\"\n\t\"v2ray.com/core/transport/internet/udp\"\n\t\"v2ray.com/core/transport/internet/xtls\"\n)\n\nfunc init() {\n\tcommon.Must(common.RegisterConfig((*ServerConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { // nolint: lll\n\t\treturn NewServer(ctx, config.(*ServerConfig))\n\t}))\n}\n\n// Server is an inbound connection handler that handles messages in trojan protocol.\ntype Server struct {\n\tpolicyManager policy.Manager\n\tvalidator     *Validator\n\tfallbacks     map[string]map[string]*Fallback // or nil\n}\n\n// NewServer creates a new trojan inbound handler.\nfunc NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {\n\tvalidator := new(Validator)\n\tfor _, user := range config.Users {\n\t\tu, err := user.ToMemoryUser()\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"failed to get trojan user\").Base(err).AtError()\n\t\t}\n\n\t\tif err := validator.Add(u); err != nil {\n\t\t\treturn nil, newError(\"failed to add user\").Base(err).AtError()\n\t\t}\n\t}\n\n\tv := core.MustFromContext(ctx)\n\tserver := &Server{\n\t\tpolicyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),\n\t\tvalidator:     validator,\n\t}\n\n\tif config.Fallbacks != nil {\n\t\tserver.fallbacks = make(map[string]map[string]*Fallback)\n\t\tfor _, fb := range config.Fallbacks {\n\t\t\tif server.fallbacks[fb.Alpn] == nil {\n\t\t\t\tserver.fallbacks[fb.Alpn] = make(map[string]*Fallback)\n\t\t\t}\n\t\t\tserver.fallbacks[fb.Alpn][fb.Path] = fb\n\t\t}\n\t\tif server.fallbacks[\"\"] != nil {\n\t\t\tfor alpn, pfb := range server.fallbacks {\n\t\t\t\tif alpn != \"\" { // && alpn != \"h2\" {\n\t\t\t\t\tfor path, fb := range server.fallbacks[\"\"] {\n\t\t\t\t\t\tif pfb[path] == nil {\n\t\t\t\t\t\t\tpfb[path] = fb\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\treturn server, nil\n}\n\n// Network implements proxy.Inbound.Network().\nfunc (s *Server) Network() []net.Network {\n\treturn []net.Network{net.Network_TCP}\n}\n\n// Process implements proxy.Inbound.Process().\nfunc (s *Server) Process(ctx context.Context, network net.Network, conn internet.Connection, dispatcher routing.Dispatcher) error { // nolint: funlen,lll\n\n\tsid := session.ExportIDToError(ctx)\n\n\tiConn := conn\n\tif statConn, ok := iConn.(*internet.StatCouterConnection); ok {\n\t\tiConn = statConn.Connection\n\t}\n\n\tsessionPolicy := s.policyManager.ForLevel(0)\n\tif err := conn.SetReadDeadline(time.Now().Add(sessionPolicy.Timeouts.Handshake)); err != nil {\n\t\treturn newError(\"unable to set read deadline\").Base(err).AtWarning()\n\t}\n\n\tfirst := buf.New()\n\tdefer first.Release()\n\n\tfirstLen, err := first.ReadFrom(conn)\n\tif err != nil {\n\t\treturn newError(\"failed to read first request\").Base(err)\n\t}\n\tnewError(\"firstLen = \", firstLen).AtInfo().WriteToLog(sid)\n\n\tbufferedReader := &buf.BufferedReader{\n\t\tReader: buf.NewReader(conn),\n\t\tBuffer: buf.MultiBuffer{first},\n\t}\n\n\tvar user *protocol.MemoryUser\n\n\tapfb := s.fallbacks\n\tisfb := apfb != nil\n\n\tshouldFallback := false\n\tif firstLen < 58 || first.Byte(56) != '\\r' { // nolint: gomnd\n\t\t// invalid protocol\n\t\terr = newError(\"not trojan protocol\")\n\t\tlog.Record(&log.AccessMessage{\n\t\t\tFrom:   conn.RemoteAddr(),\n\t\t\tTo:     \"\",\n\t\t\tStatus: log.AccessRejected,\n\t\t\tReason: err,\n\t\t})\n\n\t\tshouldFallback = true\n\t} else {\n\t\tuser = s.validator.Get(hexString(first.BytesTo(56))) // nolint: gomnd\n\t\tif user == nil {\n\t\t\t// invalid user, let's fallback\n\t\t\terr = newError(\"not a valid user\")\n\t\t\tlog.Record(&log.AccessMessage{\n\t\t\t\tFrom:   conn.RemoteAddr(),\n\t\t\t\tTo:     \"\",\n\t\t\t\tStatus: log.AccessRejected,\n\t\t\t\tReason: err,\n\t\t\t})\n\n\t\t\tshouldFallback = true\n\t\t}\n\t}\n\n\tif isfb && shouldFallback {\n\t\treturn s.fallback(ctx, sid, err, sessionPolicy, conn, iConn, apfb, first, firstLen, bufferedReader)\n\t} else if shouldFallback {\n\t\treturn newError(\"invalid protocol or invalid user\")\n\t}\n\n\tclientReader := &ConnReader{Reader: bufferedReader}\n\tif err := clientReader.ParseHeader(); err != nil {\n\t\tlog.Record(&log.AccessMessage{\n\t\t\tFrom:   conn.RemoteAddr(),\n\t\t\tTo:     \"\",\n\t\t\tStatus: log.AccessRejected,\n\t\t\tReason: err,\n\t\t})\n\t\treturn newError(\"failed to create request from: \", conn.RemoteAddr()).Base(err)\n\t}\n\n\tdestination := clientReader.Target\n\tif err := conn.SetReadDeadline(time.Time{}); err != nil {\n\t\treturn newError(\"unable to set read deadline\").Base(err).AtWarning()\n\t}\n\n\tinbound := session.InboundFromContext(ctx)\n\tif inbound == nil {\n\t\tpanic(\"no inbound metadata\")\n\t}\n\tinbound.User = user\n\tsessionPolicy = s.policyManager.ForLevel(user.Level)\n\n\tif destination.Network == net.Network_UDP { // handle udp request\n\t\treturn s.handleUDPPayload(ctx, &PacketReader{Reader: clientReader}, &PacketWriter{Writer: conn}, dispatcher)\n\t}\n\n\t// handle tcp request\n\n\tctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{\n\t\tFrom:   conn.RemoteAddr(),\n\t\tTo:     destination,\n\t\tStatus: log.AccessAccepted,\n\t\tReason: \"\",\n\t\tEmail:  user.Email,\n\t})\n\n\tnewError(\"received request for \", destination).WriteToLog(sid)\n\treturn s.handleConnection(ctx, sessionPolicy, destination, clientReader, buf.NewWriter(conn), dispatcher)\n}\n\nfunc (s *Server) handleUDPPayload(ctx context.Context, clientReader *PacketReader, clientWriter *PacketWriter, dispatcher routing.Dispatcher) error { // nolint: lll\n\tudpServer := udp.NewDispatcher(dispatcher, func(ctx context.Context, packet *udp_proto.Packet) {\n\t\tcommon.Must(clientWriter.WriteMultiBufferWithMetadata(buf.MultiBuffer{packet.Payload}, packet.Source))\n\t})\n\n\tinbound := session.InboundFromContext(ctx)\n\tuser := inbound.User\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tdefault:\n\t\t\tp, err := clientReader.ReadMultiBufferWithMetadata()\n\t\t\tif err != nil {\n\t\t\t\tif errors.Cause(err) != io.EOF {\n\t\t\t\t\treturn newError(\"unexpected EOF\").Base(err)\n\t\t\t\t}\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\tctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{\n\t\t\t\tFrom:   inbound.Source,\n\t\t\t\tTo:     p.Target,\n\t\t\t\tStatus: log.AccessAccepted,\n\t\t\t\tReason: \"\",\n\t\t\t\tEmail:  user.Email,\n\t\t\t})\n\t\t\tnewError(\"tunnelling request to \", p.Target).WriteToLog(session.ExportIDToError(ctx))\n\n\t\t\tfor _, b := range p.Buffer {\n\t\t\t\tudpServer.Dispatch(ctx, p.Target, b)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (s *Server) handleConnection(ctx context.Context, sessionPolicy policy.Session,\n\tdestination net.Destination,\n\tclientReader buf.Reader,\n\tclientWriter buf.Writer, dispatcher routing.Dispatcher) error {\n\tctx, cancel := context.WithCancel(ctx)\n\ttimer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)\n\tctx = policy.ContextWithBufferPolicy(ctx, sessionPolicy.Buffer)\n\n\tlink, err := dispatcher.Dispatch(ctx, destination)\n\tif err != nil {\n\t\treturn newError(\"failed to dispatch request to \", destination).Base(err)\n\t}\n\n\trequestDone := func() error {\n\t\tdefer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)\n\n\t\tif err := buf.Copy(clientReader, link.Writer, buf.UpdateActivity(timer)); err != nil {\n\t\t\treturn newError(\"failed to transfer request\").Base(err)\n\t\t}\n\t\treturn nil\n\t}\n\n\tresponseDone := func() error {\n\t\tdefer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)\n\n\t\tif err := buf.Copy(link.Reader, clientWriter, buf.UpdateActivity(timer)); err != nil {\n\t\t\treturn newError(\"failed to write response\").Base(err)\n\t\t}\n\t\treturn nil\n\t}\n\n\tvar requestDonePost = task.OnSuccess(requestDone, task.Close(link.Writer))\n\tif err := task.Run(ctx, requestDonePost, responseDone); err != nil {\n\t\tcommon.Must(common.Interrupt(link.Reader))\n\t\tcommon.Must(common.Interrupt(link.Writer))\n\t\treturn newError(\"connection ends\").Base(err)\n\t}\n\n\treturn nil\n}\n\nfunc (s *Server) fallback(ctx context.Context, sid errors.ExportOption, err error, sessionPolicy policy.Session, connection internet.Connection, iConn internet.Connection, apfb map[string]map[string]*Fallback, first *buf.Buffer, firstLen int64, reader buf.Reader) error { // nolint: lll\n\tif err := connection.SetReadDeadline(time.Time{}); err != nil {\n\t\tnewError(\"unable to set back read deadline\").Base(err).AtWarning().WriteToLog(sid)\n\t}\n\tnewError(\"fallback starts\").Base(err).AtInfo().WriteToLog(sid)\n\n\talpn := \"\"\n\tif len(apfb) > 1 || apfb[\"\"] == nil {\n\t\tif tlsConn, ok := iConn.(*tls.Conn); ok {\n\t\t\talpn = tlsConn.ConnectionState().NegotiatedProtocol\n\t\t\tnewError(\"realAlpn = \" + alpn).AtInfo().WriteToLog(sid)\n\t\t} else if xtlsConn, ok := iConn.(*xtls.Conn); ok {\n\t\t\talpn = xtlsConn.ConnectionState().NegotiatedProtocol\n\t\t\tnewError(\"realAlpn = \" + alpn).AtInfo().WriteToLog(sid)\n\t\t}\n\t\tif apfb[alpn] == nil {\n\t\t\talpn = \"\"\n\t\t}\n\t}\n\tpfb := apfb[alpn]\n\tif pfb == nil {\n\t\treturn newError(`failed to find the default \"alpn\" config`).AtWarning()\n\t}\n\n\tpath := \"\"\n\tif len(pfb) > 1 || pfb[\"\"] == nil {\n\t\tif firstLen >= 18 && first.Byte(4) != '*' { // not h2c\n\t\t\tfirstBytes := first.Bytes()\n\t\t\tfor i := 4; i <= 8; i++ { // 5 -> 9\n\t\t\t\tif firstBytes[i] == '/' && firstBytes[i-1] == ' ' {\n\t\t\t\t\tsearch := len(firstBytes)\n\t\t\t\t\tif search > 64 {\n\t\t\t\t\t\tsearch = 64 // up to about 60\n\t\t\t\t\t}\n\t\t\t\t\tfor j := i + 1; j < search; j++ {\n\t\t\t\t\t\tk := firstBytes[j]\n\t\t\t\t\t\tif k == '\\r' || k == '\\n' { // avoid logging \\r or \\n\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif k == ' ' {\n\t\t\t\t\t\t\tpath = string(firstBytes[i:j])\n\t\t\t\t\t\t\tnewError(\"realPath = \" + path).AtInfo().WriteToLog(sid)\n\t\t\t\t\t\t\tif pfb[path] == nil {\n\t\t\t\t\t\t\t\tpath = \"\"\n\t\t\t\t\t\t\t}\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\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tfb := pfb[path]\n\tif fb == nil {\n\t\treturn newError(`failed to find the default \"path\" config`).AtWarning()\n\t}\n\n\tctx, cancel := context.WithCancel(ctx)\n\ttimer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)\n\tctx = policy.ContextWithBufferPolicy(ctx, sessionPolicy.Buffer)\n\n\tvar conn net.Conn\n\tif err := retry.ExponentialBackoff(5, 100).On(func() error {\n\t\tvar dialer net.Dialer\n\t\tconn, err = dialer.DialContext(ctx, fb.Type, fb.Dest)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t}); err != nil {\n\t\treturn newError(\"failed to dial to \" + fb.Dest).Base(err).AtWarning()\n\t}\n\tdefer conn.Close()\n\n\tserverReader := buf.NewReader(conn)\n\tserverWriter := buf.NewWriter(conn)\n\n\tpostRequest := func() error {\n\t\tdefer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)\n\t\tif fb.Xver != 0 {\n\t\t\tremoteAddr, remotePort, err := net.SplitHostPort(connection.RemoteAddr().String())\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tlocalAddr, localPort, err := net.SplitHostPort(connection.LocalAddr().String())\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tipv4 := true\n\t\t\tfor i := 0; i < len(remoteAddr); i++ {\n\t\t\t\tif remoteAddr[i] == ':' {\n\t\t\t\t\tipv4 = false\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tpro := buf.New()\n\t\t\tdefer pro.Release()\n\t\t\tswitch fb.Xver {\n\t\t\tcase 1:\n\t\t\t\tif ipv4 {\n\t\t\t\t\tcommon.Must2(pro.Write([]byte(\"PROXY TCP4 \" + remoteAddr + \" \" + localAddr + \" \" + remotePort + \" \" + localPort + \"\\r\\n\")))\n\t\t\t\t} else {\n\t\t\t\t\tcommon.Must2(pro.Write([]byte(\"PROXY TCP6 \" + remoteAddr + \" \" + localAddr + \" \" + remotePort + \" \" + localPort + \"\\r\\n\")))\n\t\t\t\t}\n\t\t\tcase 2:\n\t\t\t\tcommon.Must2(pro.Write([]byte(\"\\x0D\\x0A\\x0D\\x0A\\x00\\x0D\\x0A\\x51\\x55\\x49\\x54\\x0A\\x21\"))) // signature + v2 + PROXY\n\t\t\t\tif ipv4 {\n\t\t\t\t\tcommon.Must2(pro.Write([]byte(\"\\x11\\x00\\x0C\"))) // AF_INET + STREAM + 12 bytes\n\t\t\t\t\tcommon.Must2(pro.Write(net.ParseIP(remoteAddr).To4()))\n\t\t\t\t\tcommon.Must2(pro.Write(net.ParseIP(localAddr).To4()))\n\t\t\t\t} else {\n\t\t\t\t\tcommon.Must2(pro.Write([]byte(\"\\x21\\x00\\x24\"))) // AF_INET6 + STREAM + 36 bytes\n\t\t\t\t\tcommon.Must2(pro.Write(net.ParseIP(remoteAddr).To16()))\n\t\t\t\t\tcommon.Must2(pro.Write(net.ParseIP(localAddr).To16()))\n\t\t\t\t}\n\t\t\t\tp1, _ := strconv.ParseUint(remotePort, 10, 16)\n\t\t\t\tp2, _ := strconv.ParseUint(localPort, 10, 16)\n\t\t\t\tcommon.Must2(pro.Write([]byte{byte(p1 >> 8), byte(p1), byte(p2 >> 8), byte(p2)}))\n\t\t\t}\n\t\t\tif err := serverWriter.WriteMultiBuffer(buf.MultiBuffer{pro}); err != nil {\n\t\t\t\treturn newError(\"failed to set PROXY protocol v\", fb.Xver).Base(err).AtWarning()\n\t\t\t}\n\t\t}\n\t\tif err := buf.Copy(reader, serverWriter, buf.UpdateActivity(timer)); err != nil {\n\t\t\treturn newError(\"failed to fallback request payload\").Base(err).AtInfo()\n\t\t}\n\t\treturn nil\n\t}\n\n\twriter := buf.NewWriter(connection)\n\n\tgetResponse := func() error {\n\t\tdefer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)\n\t\tif err := buf.Copy(serverReader, writer, buf.UpdateActivity(timer)); err != nil {\n\t\t\treturn newError(\"failed to deliver response payload\").Base(err).AtInfo()\n\t\t}\n\t\treturn nil\n\t}\n\n\tif err := task.Run(ctx, task.OnSuccess(postRequest, task.Close(serverWriter)), task.OnSuccess(getResponse, task.Close(writer))); err != nil {\n\t\tcommon.Must(common.Interrupt(serverReader))\n\t\tcommon.Must(common.Interrupt(serverWriter))\n\t\treturn newError(\"fallback ends\").Base(err).AtInfo()\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "proxy/trojan/trojan.go",
    "content": "package trojan\n"
  },
  {
    "path": "proxy/trojan/validator.go",
    "content": "package trojan\n\nimport (\n\t\"sync\"\n\n\t\"v2ray.com/core/common/protocol\"\n)\n\n// Validator stores valid trojan users\ntype Validator struct {\n\tusers sync.Map\n}\n\n// Add a trojan user\nfunc (v *Validator) Add(u *protocol.MemoryUser) error {\n\tuser := u.Account.(*MemoryAccount)\n\tv.users.Store(hexString(user.Key), u)\n\treturn nil\n}\n\n// Get user with hashed key, nil if user doesn't exist.\nfunc (v *Validator) Get(hash string) *protocol.MemoryUser {\n\tu, _ := v.users.Load(hash)\n\tif u != nil {\n\t\treturn u.(*protocol.MemoryUser)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "proxy/vless/account.go",
    "content": "// +build !confonly\n\npackage vless\n\nimport (\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/uuid\"\n)\n\n// AsAccount implements protocol.Account.AsAccount().\nfunc (a *Account) AsAccount() (protocol.Account, error) {\n\tid, err := uuid.ParseString(a.Id)\n\tif err != nil {\n\t\treturn nil, newError(\"failed to parse ID\").Base(err).AtError()\n\t}\n\treturn &MemoryAccount{\n\t\tID:         protocol.NewID(id),\n\t\tFlow:       a.Flow,       // needs parser here?\n\t\tEncryption: a.Encryption, // needs parser here?\n\t}, nil\n}\n\n// MemoryAccount is an in-memory form of VLess account.\ntype MemoryAccount struct {\n\t// ID of the account.\n\tID *protocol.ID\n\t// Flow of the account. May be \"xtls-rprx-origin\".\n\tFlow string\n\t// Encryption of the account. Used for client connections, and only accepts \"none\" for now.\n\tEncryption string\n}\n\n// Equals implements protocol.Account.Equals().\nfunc (a *MemoryAccount) Equals(account protocol.Account) bool {\n\tvlessAccount, ok := account.(*MemoryAccount)\n\tif !ok {\n\t\treturn false\n\t}\n\treturn a.ID.Equals(vlessAccount.ID)\n}\n"
  },
  {
    "path": "proxy/vless/account.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: proxy/vless/account.proto\n\npackage vless\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype Account struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// ID of the account, in the form of a UUID, e.g., \"66ad4540-b58c-4ad2-9926-ea63445a9b57\".\n\tId string `protobuf:\"bytes,1,opt,name=id,proto3\" json:\"id,omitempty\"`\n\t// Flow settings. May be \"xtls-rprx-origin\".\n\tFlow string `protobuf:\"bytes,2,opt,name=flow,proto3\" json:\"flow,omitempty\"`\n\t// Encryption settings. Only applies to client side, and only accepts \"none\" for now.\n\tEncryption string `protobuf:\"bytes,3,opt,name=encryption,proto3\" json:\"encryption,omitempty\"`\n}\n\nfunc (x *Account) Reset() {\n\t*x = Account{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_proxy_vless_account_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Account) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Account) ProtoMessage() {}\n\nfunc (x *Account) ProtoReflect() protoreflect.Message {\n\tmi := &file_proxy_vless_account_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Account.ProtoReflect.Descriptor instead.\nfunc (*Account) Descriptor() ([]byte, []int) {\n\treturn file_proxy_vless_account_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *Account) GetId() string {\n\tif x != nil {\n\t\treturn x.Id\n\t}\n\treturn \"\"\n}\n\nfunc (x *Account) GetFlow() string {\n\tif x != nil {\n\t\treturn x.Flow\n\t}\n\treturn \"\"\n}\n\nfunc (x *Account) GetEncryption() string {\n\tif x != nil {\n\t\treturn x.Encryption\n\t}\n\treturn \"\"\n}\n\nvar File_proxy_vless_account_proto protoreflect.FileDescriptor\n\nvar file_proxy_vless_account_proto_rawDesc = []byte{\n\t0x0a, 0x19, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2f, 0x61, 0x63,\n\t0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x16, 0x76, 0x32, 0x72,\n\t0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c,\n\t0x65, 0x73, 0x73, 0x22, 0x4d, 0x0a, 0x07, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x0e,\n\t0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12,\n\t0x0a, 0x04, 0x66, 0x6c, 0x6f, 0x77, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x6c,\n\t0x6f, 0x77, 0x12, 0x1e, 0x0a, 0x0a, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e,\n\t0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69,\n\t0x6f, 0x6e, 0x42, 0x53, 0x0a, 0x1a, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,\n\t0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73,\n\t0x50, 0x01, 0x5a, 0x1a, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f,\n\t0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6c, 0x65, 0x73, 0x73, 0xaa, 0x02,\n\t0x16, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x78,\n\t0x79, 0x2e, 0x56, 0x6c, 0x65, 0x73, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_proxy_vless_account_proto_rawDescOnce sync.Once\n\tfile_proxy_vless_account_proto_rawDescData = file_proxy_vless_account_proto_rawDesc\n)\n\nfunc file_proxy_vless_account_proto_rawDescGZIP() []byte {\n\tfile_proxy_vless_account_proto_rawDescOnce.Do(func() {\n\t\tfile_proxy_vless_account_proto_rawDescData = protoimpl.X.CompressGZIP(file_proxy_vless_account_proto_rawDescData)\n\t})\n\treturn file_proxy_vless_account_proto_rawDescData\n}\n\nvar file_proxy_vless_account_proto_msgTypes = make([]protoimpl.MessageInfo, 1)\nvar file_proxy_vless_account_proto_goTypes = []interface{}{\n\t(*Account)(nil), // 0: v2ray.core.proxy.vless.Account\n}\nvar file_proxy_vless_account_proto_depIdxs = []int32{\n\t0, // [0:0] is the sub-list for method output_type\n\t0, // [0:0] is the sub-list for method input_type\n\t0, // [0:0] is the sub-list for extension type_name\n\t0, // [0:0] is the sub-list for extension extendee\n\t0, // [0:0] is the sub-list for field type_name\n}\n\nfunc init() { file_proxy_vless_account_proto_init() }\nfunc file_proxy_vless_account_proto_init() {\n\tif File_proxy_vless_account_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_proxy_vless_account_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Account); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_proxy_vless_account_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   1,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_proxy_vless_account_proto_goTypes,\n\t\tDependencyIndexes: file_proxy_vless_account_proto_depIdxs,\n\t\tMessageInfos:      file_proxy_vless_account_proto_msgTypes,\n\t}.Build()\n\tFile_proxy_vless_account_proto = out.File\n\tfile_proxy_vless_account_proto_rawDesc = nil\n\tfile_proxy_vless_account_proto_goTypes = nil\n\tfile_proxy_vless_account_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "proxy/vless/account.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.proxy.vless;\noption csharp_namespace = \"V2Ray.Core.Proxy.Vless\";\noption go_package = \"v2ray.com/core/proxy/vless\";\noption java_package = \"com.v2ray.core.proxy.vless\";\noption java_multiple_files = true;\n\nmessage Account {\n  // ID of the account, in the form of a UUID, e.g., \"66ad4540-b58c-4ad2-9926-ea63445a9b57\".\n  string id = 1;\n  // Flow settings. May be \"xtls-rprx-origin\".\n  string flow = 2;\n  // Encryption settings. Only applies to client side, and only accepts \"none\" for now.\n  string encryption = 3;\n}\n"
  },
  {
    "path": "proxy/vless/encoding/addons.go",
    "content": "// +build !confonly\n\npackage encoding\n\nimport (\n\t\"io\"\n\n\t\"github.com/golang/protobuf/proto\"\n\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/proxy/vless\"\n)\n\nfunc EncodeHeaderAddons(buffer *buf.Buffer, addons *Addons) error {\n\n\tswitch addons.Flow {\n\tcase vless.XRO, vless.XRD:\n\n\t\tbytes, err := proto.Marshal(addons)\n\t\tif err != nil {\n\t\t\treturn newError(\"failed to marshal addons protobuf value\").Base(err)\n\t\t}\n\t\tif err := buffer.WriteByte(byte(len(bytes))); err != nil {\n\t\t\treturn newError(\"failed to write addons protobuf length\").Base(err)\n\t\t}\n\t\tif _, err := buffer.Write(bytes); err != nil {\n\t\t\treturn newError(\"failed to write addons protobuf value\").Base(err)\n\t\t}\n\n\tdefault:\n\n\t\tif err := buffer.WriteByte(0); err != nil {\n\t\t\treturn newError(\"failed to write addons protobuf length\").Base(err)\n\t\t}\n\n\t}\n\n\treturn nil\n\n}\n\nfunc DecodeHeaderAddons(buffer *buf.Buffer, reader io.Reader) (*Addons, error) {\n\n\taddons := new(Addons)\n\n\tbuffer.Clear()\n\tif _, err := buffer.ReadFullFrom(reader, 1); err != nil {\n\t\treturn nil, newError(\"failed to read addons protobuf length\").Base(err)\n\t}\n\n\tif length := int32(buffer.Byte(0)); length != 0 {\n\n\t\tbuffer.Clear()\n\t\tif _, err := buffer.ReadFullFrom(reader, length); err != nil {\n\t\t\treturn nil, newError(\"failed to read addons protobuf value\").Base(err)\n\t\t}\n\n\t\tif err := proto.Unmarshal(buffer.Bytes(), addons); err != nil {\n\t\t\treturn nil, newError(\"failed to unmarshal addons protobuf value\").Base(err)\n\t\t}\n\n\t\t// Verification.\n\t\tswitch addons.Flow {\n\t\tdefault:\n\n\t\t}\n\n\t}\n\n\treturn addons, nil\n\n}\n\n// EncodeBodyAddons returns a Writer that auto-encrypt content written by caller.\nfunc EncodeBodyAddons(writer io.Writer, request *protocol.RequestHeader, addons *Addons) buf.Writer {\n\n\tswitch addons.Flow {\n\tdefault:\n\n\t\tif request.Command == protocol.RequestCommandUDP {\n\t\t\treturn NewMultiLengthPacketWriter(writer.(buf.Writer))\n\t\t}\n\n\t}\n\n\treturn buf.NewWriter(writer)\n\n}\n\n// DecodeBodyAddons returns a Reader from which caller can fetch decrypted body.\nfunc DecodeBodyAddons(reader io.Reader, request *protocol.RequestHeader, addons *Addons) buf.Reader {\n\n\tswitch addons.Flow {\n\tdefault:\n\n\t\tif request.Command == protocol.RequestCommandUDP {\n\t\t\treturn NewLengthPacketReader(reader)\n\t\t}\n\n\t}\n\n\treturn buf.NewReader(reader)\n\n}\n\nfunc NewMultiLengthPacketWriter(writer buf.Writer) *MultiLengthPacketWriter {\n\treturn &MultiLengthPacketWriter{\n\t\tWriter: writer,\n\t}\n}\n\ntype MultiLengthPacketWriter struct {\n\tbuf.Writer\n}\n\nfunc (w *MultiLengthPacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {\n\tdefer buf.ReleaseMulti(mb)\n\tmb2Write := make(buf.MultiBuffer, 0, len(mb)+1)\n\tfor _, b := range mb {\n\t\tlength := b.Len()\n\t\tif length == 0 || length+2 > buf.Size {\n\t\t\tcontinue\n\t\t}\n\t\teb := buf.New()\n\t\tif err := eb.WriteByte(byte(length >> 8)); err != nil {\n\t\t\teb.Release()\n\t\t\tcontinue\n\t\t}\n\t\tif err := eb.WriteByte(byte(length)); err != nil {\n\t\t\teb.Release()\n\t\t\tcontinue\n\t\t}\n\t\tif _, err := eb.Write(b.Bytes()); err != nil {\n\t\t\teb.Release()\n\t\t\tcontinue\n\t\t}\n\t\tmb2Write = append(mb2Write, eb)\n\t}\n\tif mb2Write.IsEmpty() {\n\t\treturn nil\n\t}\n\treturn w.Writer.WriteMultiBuffer(mb2Write)\n}\n\nfunc NewLengthPacketWriter(writer io.Writer) *LengthPacketWriter {\n\treturn &LengthPacketWriter{\n\t\tWriter: writer,\n\t\tcache:  make([]byte, 0, 65536),\n\t}\n}\n\ntype LengthPacketWriter struct {\n\tio.Writer\n\tcache []byte\n}\n\nfunc (w *LengthPacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {\n\tlength := mb.Len() // none of mb is nil\n\t//fmt.Println(\"Write\", length)\n\tif length == 0 {\n\t\treturn nil\n\t}\n\tdefer func() {\n\t\tw.cache = w.cache[:0]\n\t}()\n\tw.cache = append(w.cache, byte(length>>8), byte(length))\n\tfor i, b := range mb {\n\t\tw.cache = append(w.cache, b.Bytes()...)\n\t\tb.Release()\n\t\tmb[i] = nil\n\t}\n\tif _, err := w.Write(w.cache); err != nil {\n\t\treturn newError(\"failed to write a packet\").Base(err)\n\t}\n\treturn nil\n}\n\nfunc NewLengthPacketReader(reader io.Reader) *LengthPacketReader {\n\treturn &LengthPacketReader{\n\t\tReader: reader,\n\t\tcache:  make([]byte, 2),\n\t}\n}\n\ntype LengthPacketReader struct {\n\tio.Reader\n\tcache []byte\n}\n\nfunc (r *LengthPacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {\n\tif _, err := io.ReadFull(r.Reader, r.cache); err != nil { // maybe EOF\n\t\treturn nil, newError(\"failed to read packet length\").Base(err)\n\t}\n\tlength := int32(r.cache[0])<<8 | int32(r.cache[1])\n\t//fmt.Println(\"Read\", length)\n\tmb := make(buf.MultiBuffer, 0, length/buf.Size+1)\n\tfor length > 0 {\n\t\tsize := length\n\t\tif size > buf.Size {\n\t\t\tsize = buf.Size\n\t\t}\n\t\tlength -= size\n\t\tb := buf.New()\n\t\tif _, err := b.ReadFullFrom(r.Reader, size); err != nil {\n\t\t\treturn nil, newError(\"failed to read packet payload\").Base(err)\n\t\t}\n\t\tmb = append(mb, b)\n\t}\n\treturn mb, nil\n}\n"
  },
  {
    "path": "proxy/vless/encoding/addons.pb.go",
    "content": "// Code generated by protoc-gen-gogo. DO NOT EDIT.\n// source: proxy/vless/encoding/addons.proto\n\npackage encoding\n\nimport (\n\tfmt \"fmt\"\n\tproto \"github.com/golang/protobuf/proto\"\n\tio \"io\"\n\tmath \"math\"\n\tmath_bits \"math/bits\"\n)\n\n// Reference imports to suppress errors if they are not otherwise used.\nvar _ = proto.Marshal\nvar _ = fmt.Errorf\nvar _ = math.Inf\n\n// This is a compile-time assertion to ensure that this generated file\n// is compatible with the proto package it is being compiled against.\n// A compilation error at this line likely means your copy of the\n// proto package needs to be updated.\nconst _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package\n\ntype Addons struct {\n\tFlow                 string   `protobuf:\"bytes,1,opt,name=Flow,proto3\" json:\"Flow,omitempty\"`\n\tSeed                 []byte   `protobuf:\"bytes,2,opt,name=Seed,proto3\" json:\"Seed,omitempty\"`\n\tXXX_NoUnkeyedLiteral struct{} `json:\"-\"`\n\tXXX_unrecognized     []byte   `json:\"-\"`\n\tXXX_sizecache        int32    `json:\"-\"`\n}\n\nfunc (m *Addons) Reset()         { *m = Addons{} }\nfunc (m *Addons) String() string { return proto.CompactTextString(m) }\nfunc (*Addons) ProtoMessage()    {}\nfunc (*Addons) Descriptor() ([]byte, []int) {\n\treturn fileDescriptor_75ab671b0ca8b1cc, []int{0}\n}\nfunc (m *Addons) XXX_Unmarshal(b []byte) error {\n\treturn m.Unmarshal(b)\n}\nfunc (m *Addons) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {\n\tif deterministic {\n\t\treturn xxx_messageInfo_Addons.Marshal(b, m, deterministic)\n\t} else {\n\t\tb = b[:cap(b)]\n\t\tn, err := m.MarshalToSizedBuffer(b)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn b[:n], nil\n\t}\n}\nfunc (m *Addons) XXX_Merge(src proto.Message) {\n\txxx_messageInfo_Addons.Merge(m, src)\n}\nfunc (m *Addons) XXX_Size() int {\n\treturn m.Size()\n}\nfunc (m *Addons) XXX_DiscardUnknown() {\n\txxx_messageInfo_Addons.DiscardUnknown(m)\n}\n\nvar xxx_messageInfo_Addons proto.InternalMessageInfo\n\nfunc (m *Addons) GetFlow() string {\n\tif m != nil {\n\t\treturn m.Flow\n\t}\n\treturn \"\"\n}\n\nfunc (m *Addons) GetSeed() []byte {\n\tif m != nil {\n\t\treturn m.Seed\n\t}\n\treturn nil\n}\n\nfunc init() {\n\tproto.RegisterType((*Addons)(nil), \"v2ray.core.proxy.vless.encoding.Addons\")\n}\n\nfunc init() { proto.RegisterFile(\"proxy/vless/encoding/addons.proto\", fileDescriptor_75ab671b0ca8b1cc) }\n\nvar fileDescriptor_75ab671b0ca8b1cc = []byte{\n\t// 186 bytes of a gzipped FileDescriptorProto\n\t0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x2c, 0x28, 0xca, 0xaf,\n\t0xa8, 0xd4, 0x2f, 0xcb, 0x49, 0x2d, 0x2e, 0xd6, 0x4f, 0xcd, 0x4b, 0xce, 0x4f, 0xc9, 0xcc, 0x4b,\n\t0xd7, 0x4f, 0x4c, 0x49, 0xc9, 0xcf, 0x2b, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x92, 0x2f,\n\t0x33, 0x2a, 0x4a, 0xac, 0xd4, 0x4b, 0xce, 0x2f, 0x4a, 0xd5, 0x03, 0xab, 0xd6, 0x03, 0xab, 0xd6,\n\t0x83, 0xa9, 0x56, 0x32, 0xe0, 0x62, 0x73, 0x04, 0x6b, 0x10, 0x12, 0xe2, 0x62, 0x71, 0xcb, 0xc9,\n\t0x2f, 0x97, 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x0c, 0x02, 0xb3, 0x41, 0x62, 0xc1, 0xa9, 0xa9, 0x29,\n\t0x12, 0x4c, 0x0a, 0x8c, 0x1a, 0x3c, 0x41, 0x60, 0xb6, 0x53, 0xdd, 0x89, 0x47, 0x72, 0x8c, 0x17,\n\t0x1e, 0xc9, 0x31, 0x3e, 0x78, 0x24, 0xc7, 0x38, 0xe3, 0xb1, 0x1c, 0x03, 0x97, 0x72, 0x72, 0x7e,\n\t0xae, 0x1e, 0x01, 0x8b, 0x02, 0x18, 0xa3, 0x94, 0x61, 0x4a, 0x72, 0xf5, 0x41, 0xca, 0xf4, 0xb1,\n\t0xb9, 0x7e, 0x15, 0x93, 0x7c, 0x98, 0x51, 0x50, 0x62, 0xa5, 0x9e, 0x33, 0xc8, 0xa0, 0x00, 0xb0,\n\t0x41, 0x61, 0x60, 0x83, 0x5c, 0xa1, 0x2a, 0x92, 0xd8, 0xc0, 0x3e, 0x33, 0x06, 0x04, 0x00, 0x00,\n\t0xff, 0xff, 0x36, 0x32, 0x14, 0x7c, 0xfe, 0x00, 0x00, 0x00,\n}\n\nfunc (m *Addons) Marshal() (dAtA []byte, err error) {\n\tsize := m.Size()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBuffer(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *Addons) MarshalTo(dAtA []byte) (int, error) {\n\tsize := m.Size()\n\treturn m.MarshalToSizedBuffer(dAtA[:size])\n}\n\nfunc (m *Addons) MarshalToSizedBuffer(dAtA []byte) (int, error) {\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.XXX_unrecognized != nil {\n\t\ti -= len(m.XXX_unrecognized)\n\t\tcopy(dAtA[i:], m.XXX_unrecognized)\n\t}\n\tif len(m.Seed) > 0 {\n\t\ti -= len(m.Seed)\n\t\tcopy(dAtA[i:], m.Seed)\n\t\ti = encodeVarintAddons(dAtA, i, uint64(len(m.Seed)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Flow) > 0 {\n\t\ti -= len(m.Flow)\n\t\tcopy(dAtA[i:], m.Flow)\n\t\ti = encodeVarintAddons(dAtA, i, uint64(len(m.Flow)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc encodeVarintAddons(dAtA []byte, offset int, v uint64) int {\n\toffset -= sovAddons(v)\n\tbase := offset\n\tfor v >= 1<<7 {\n\t\tdAtA[offset] = uint8(v&0x7f | 0x80)\n\t\tv >>= 7\n\t\toffset++\n\t}\n\tdAtA[offset] = uint8(v)\n\treturn base\n}\nfunc (m *Addons) Size() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Flow)\n\tif l > 0 {\n\t\tn += 1 + l + sovAddons(uint64(l))\n\t}\n\tl = len(m.Seed)\n\tif l > 0 {\n\t\tn += 1 + l + sovAddons(uint64(l))\n\t}\n\tif m.XXX_unrecognized != nil {\n\t\tn += len(m.XXX_unrecognized)\n\t}\n\treturn n\n}\n\nfunc sovAddons(x uint64) (n int) {\n\treturn (math_bits.Len64(x|1) + 6) / 7\n}\nfunc sozAddons(x uint64) (n int) {\n\treturn sovAddons(uint64((x << 1) ^ uint64((int64(x) >> 63))))\n}\nfunc (m *Addons) Unmarshal(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn ErrIntOverflowAddons\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: Addons: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: Addons: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Flow\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowAddons\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn ErrInvalidLengthAddons\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn ErrInvalidLengthAddons\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Flow = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Seed\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowAddons\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn ErrInvalidLengthAddons\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn ErrInvalidLengthAddons\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Seed = append(m.Seed[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.Seed == nil {\n\t\t\t\tm.Seed = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := skipAddons(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif skippy < 0 {\n\t\t\t\treturn ErrInvalidLengthAddons\n\t\t\t}\n\t\t\tif (iNdEx + skippy) < 0 {\n\t\t\t\treturn ErrInvalidLengthAddons\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc skipAddons(dAtA []byte) (n int, err error) {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tdepth := 0\n\tfor iNdEx < l {\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn 0, ErrIntOverflowAddons\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn 0, io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= (uint64(b) & 0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\twireType := int(wire & 0x7)\n\t\tswitch wireType {\n\t\tcase 0:\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn 0, ErrIntOverflowAddons\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn 0, io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tiNdEx++\n\t\t\t\tif dAtA[iNdEx-1] < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 1:\n\t\t\tiNdEx += 8\n\t\tcase 2:\n\t\t\tvar length int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn 0, ErrIntOverflowAddons\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn 0, io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tlength |= (int(b) & 0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif length < 0 {\n\t\t\t\treturn 0, ErrInvalidLengthAddons\n\t\t\t}\n\t\t\tiNdEx += length\n\t\tcase 3:\n\t\t\tdepth++\n\t\tcase 4:\n\t\t\tif depth == 0 {\n\t\t\t\treturn 0, ErrUnexpectedEndOfGroupAddons\n\t\t\t}\n\t\t\tdepth--\n\t\tcase 5:\n\t\t\tiNdEx += 4\n\t\tdefault:\n\t\t\treturn 0, fmt.Errorf(\"proto: illegal wireType %d\", wireType)\n\t\t}\n\t\tif iNdEx < 0 {\n\t\t\treturn 0, ErrInvalidLengthAddons\n\t\t}\n\t\tif depth == 0 {\n\t\t\treturn iNdEx, nil\n\t\t}\n\t}\n\treturn 0, io.ErrUnexpectedEOF\n}\n\nvar (\n\tErrInvalidLengthAddons        = fmt.Errorf(\"proto: negative length found during unmarshaling\")\n\tErrIntOverflowAddons          = fmt.Errorf(\"proto: integer overflow\")\n\tErrUnexpectedEndOfGroupAddons = fmt.Errorf(\"proto: unexpected end of group\")\n)\n"
  },
  {
    "path": "proxy/vless/encoding/addons.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.proxy.vless.encoding;\noption csharp_namespace = \"V2Ray.Core.Proxy.Vless.Encoding\";\noption go_package = \"v2ray.com/core/proxy/vless/encoding\";\noption java_package = \"com.v2ray.core.proxy.vless.encoding\";\noption java_multiple_files = true;\n\nmessage Addons {\n  string Flow = 1;\n  bytes Seed = 2;\n}\n"
  },
  {
    "path": "proxy/vless/encoding/encoding.go",
    "content": "// +build !confonly\n\npackage encoding\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n\nimport (\n\t\"io\"\n\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/proxy/vless\"\n)\n\nconst (\n\tVersion = byte(0)\n)\n\nvar addrParser = protocol.NewAddressParser(\n\tprotocol.AddressFamilyByte(byte(protocol.AddressTypeIPv4), net.AddressFamilyIPv4),\n\tprotocol.AddressFamilyByte(byte(protocol.AddressTypeDomain), net.AddressFamilyDomain),\n\tprotocol.AddressFamilyByte(byte(protocol.AddressTypeIPv6), net.AddressFamilyIPv6),\n\tprotocol.PortThenAddress(),\n)\n\n// EncodeRequestHeader writes encoded request header into the given writer.\nfunc EncodeRequestHeader(writer io.Writer, request *protocol.RequestHeader, requestAddons *Addons) error {\n\n\tbuffer := buf.StackNew()\n\tdefer buffer.Release()\n\n\tif err := buffer.WriteByte(request.Version); err != nil {\n\t\treturn newError(\"failed to write request version\").Base(err)\n\t}\n\n\tif _, err := buffer.Write(request.User.Account.(*vless.MemoryAccount).ID.Bytes()); err != nil {\n\t\treturn newError(\"failed to write request user id\").Base(err)\n\t}\n\n\tif err := EncodeHeaderAddons(&buffer, requestAddons); err != nil {\n\t\treturn newError(\"failed to encode request header addons\").Base(err)\n\t}\n\n\tif err := buffer.WriteByte(byte(request.Command)); err != nil {\n\t\treturn newError(\"failed to write request command\").Base(err)\n\t}\n\n\tif request.Command != protocol.RequestCommandMux {\n\t\tif err := addrParser.WriteAddressPort(&buffer, request.Address, request.Port); err != nil {\n\t\t\treturn newError(\"failed to write request address and port\").Base(err)\n\t\t}\n\t}\n\n\tif _, err := writer.Write(buffer.Bytes()); err != nil {\n\t\treturn newError(\"failed to write request header\").Base(err)\n\t}\n\n\treturn nil\n}\n\n// DecodeRequestHeader decodes and returns (if successful) a RequestHeader from an input stream.\nfunc DecodeRequestHeader(isfb bool, first *buf.Buffer, reader io.Reader, validator *vless.Validator) (*protocol.RequestHeader, *Addons, error, bool) {\n\n\tbuffer := buf.StackNew()\n\tdefer buffer.Release()\n\n\trequest := new(protocol.RequestHeader)\n\n\tif isfb {\n\t\trequest.Version = first.Byte(0)\n\t} else {\n\t\tif _, err := buffer.ReadFullFrom(reader, 1); err != nil {\n\t\t\treturn nil, nil, newError(\"failed to read request version\").Base(err), false\n\t\t}\n\t\trequest.Version = buffer.Byte(0)\n\t}\n\n\tswitch request.Version {\n\tcase 0:\n\n\t\tvar id [16]byte\n\n\t\tif isfb {\n\t\t\tcopy(id[:], first.BytesRange(1, 17))\n\t\t} else {\n\t\t\tbuffer.Clear()\n\t\t\tif _, err := buffer.ReadFullFrom(reader, 16); err != nil {\n\t\t\t\treturn nil, nil, newError(\"failed to read request user id\").Base(err), false\n\t\t\t}\n\t\t\tcopy(id[:], buffer.Bytes())\n\t\t}\n\n\t\tif request.User = validator.Get(id); request.User == nil {\n\t\t\treturn nil, nil, newError(\"invalid request user id\"), isfb\n\t\t}\n\n\t\tif isfb {\n\t\t\tfirst.Advance(17)\n\t\t}\n\n\t\trequestAddons, err := DecodeHeaderAddons(&buffer, reader)\n\t\tif err != nil {\n\t\t\treturn nil, nil, newError(\"failed to decode request header addons\").Base(err), false\n\t\t}\n\n\t\tbuffer.Clear()\n\t\tif _, err := buffer.ReadFullFrom(reader, 1); err != nil {\n\t\t\treturn nil, nil, newError(\"failed to read request command\").Base(err), false\n\t\t}\n\n\t\trequest.Command = protocol.RequestCommand(buffer.Byte(0))\n\t\tswitch request.Command {\n\t\tcase protocol.RequestCommandMux:\n\t\t\trequest.Address = net.DomainAddress(\"v1.mux.cool\")\n\t\t\trequest.Port = 0\n\t\tcase protocol.RequestCommandTCP, protocol.RequestCommandUDP:\n\t\t\tif addr, port, err := addrParser.ReadAddressPort(&buffer, reader); err == nil {\n\t\t\t\trequest.Address = addr\n\t\t\t\trequest.Port = port\n\t\t\t}\n\t\t}\n\n\t\tif request.Address == nil {\n\t\t\treturn nil, nil, newError(\"invalid request address\"), false\n\t\t}\n\n\t\treturn request, requestAddons, nil, false\n\n\tdefault:\n\n\t\treturn nil, nil, newError(\"invalid request version\"), isfb\n\n\t}\n\n}\n\n// EncodeResponseHeader writes encoded response header into the given writer.\nfunc EncodeResponseHeader(writer io.Writer, request *protocol.RequestHeader, responseAddons *Addons) error {\n\n\tbuffer := buf.StackNew()\n\tdefer buffer.Release()\n\n\tif err := buffer.WriteByte(request.Version); err != nil {\n\t\treturn newError(\"failed to write response version\").Base(err)\n\t}\n\n\tif err := EncodeHeaderAddons(&buffer, responseAddons); err != nil {\n\t\treturn newError(\"failed to encode response header addons\").Base(err)\n\t}\n\n\tif _, err := writer.Write(buffer.Bytes()); err != nil {\n\t\treturn newError(\"failed to write response header\").Base(err)\n\t}\n\n\treturn nil\n}\n\n// DecodeResponseHeader decodes and returns (if successful) a ResponseHeader from an input stream.\nfunc DecodeResponseHeader(reader io.Reader, request *protocol.RequestHeader) (*Addons, error) {\n\n\tbuffer := buf.StackNew()\n\tdefer buffer.Release()\n\n\tif _, err := buffer.ReadFullFrom(reader, 1); err != nil {\n\t\treturn nil, newError(\"failed to read response version\").Base(err)\n\t}\n\n\tif buffer.Byte(0) != request.Version {\n\t\treturn nil, newError(\"unexpected response version. Expecting \", int(request.Version), \" but actually \", int(buffer.Byte(0)))\n\t}\n\n\tresponseAddons, err := DecodeHeaderAddons(&buffer, reader)\n\tif err != nil {\n\t\treturn nil, newError(\"failed to decode response header addons\").Base(err)\n\t}\n\n\treturn responseAddons, nil\n}\n"
  },
  {
    "path": "proxy/vless/encoding/encoding_test.go",
    "content": "package encoding_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/uuid\"\n\t\"v2ray.com/core/proxy/vless\"\n\t. \"v2ray.com/core/proxy/vless/encoding\"\n)\n\nfunc toAccount(a *vless.Account) protocol.Account {\n\taccount, err := a.AsAccount()\n\tcommon.Must(err)\n\treturn account\n}\n\nfunc TestRequestSerialization(t *testing.T) {\n\tuser := &protocol.MemoryUser{\n\t\tLevel: 0,\n\t\tEmail: \"test@v2fly.org\",\n\t}\n\tid := uuid.New()\n\taccount := &vless.Account{\n\t\tId: id.String(),\n\t}\n\tuser.Account = toAccount(account)\n\n\texpectedRequest := &protocol.RequestHeader{\n\t\tVersion: Version,\n\t\tUser:    user,\n\t\tCommand: protocol.RequestCommandTCP,\n\t\tAddress: net.DomainAddress(\"www.v2fly.org\"),\n\t\tPort:    net.Port(443),\n\t}\n\texpectedAddons := &Addons{}\n\n\tbuffer := buf.StackNew()\n\tcommon.Must(EncodeRequestHeader(&buffer, expectedRequest, expectedAddons))\n\n\tValidator := new(vless.Validator)\n\tValidator.Add(user)\n\n\tactualRequest, actualAddons, err, _ := DecodeRequestHeader(false, nil, &buffer, Validator)\n\tcommon.Must(err)\n\n\tif r := cmp.Diff(actualRequest, expectedRequest, cmp.AllowUnexported(protocol.ID{})); r != \"\" {\n\t\tt.Error(r)\n\t}\n\tif r := cmp.Diff(actualAddons, expectedAddons); r != \"\" {\n\t\tt.Error(r)\n\t}\n}\n\nfunc TestInvalidRequest(t *testing.T) {\n\tuser := &protocol.MemoryUser{\n\t\tLevel: 0,\n\t\tEmail: \"test@v2fly.org\",\n\t}\n\tid := uuid.New()\n\taccount := &vless.Account{\n\t\tId: id.String(),\n\t}\n\tuser.Account = toAccount(account)\n\n\texpectedRequest := &protocol.RequestHeader{\n\t\tVersion: Version,\n\t\tUser:    user,\n\t\tCommand: protocol.RequestCommand(100),\n\t\tAddress: net.DomainAddress(\"www.v2fly.org\"),\n\t\tPort:    net.Port(443),\n\t}\n\texpectedAddons := &Addons{}\n\n\tbuffer := buf.StackNew()\n\tcommon.Must(EncodeRequestHeader(&buffer, expectedRequest, expectedAddons))\n\n\tValidator := new(vless.Validator)\n\tValidator.Add(user)\n\n\t_, _, err, _ := DecodeRequestHeader(false, nil, &buffer, Validator)\n\tif err == nil {\n\t\tt.Error(\"nil error\")\n\t}\n}\n\nfunc TestMuxRequest(t *testing.T) {\n\tuser := &protocol.MemoryUser{\n\t\tLevel: 0,\n\t\tEmail: \"test@v2fly.org\",\n\t}\n\tid := uuid.New()\n\taccount := &vless.Account{\n\t\tId: id.String(),\n\t}\n\tuser.Account = toAccount(account)\n\n\texpectedRequest := &protocol.RequestHeader{\n\t\tVersion: Version,\n\t\tUser:    user,\n\t\tCommand: protocol.RequestCommandMux,\n\t\tAddress: net.DomainAddress(\"v1.mux.cool\"),\n\t}\n\texpectedAddons := &Addons{}\n\n\tbuffer := buf.StackNew()\n\tcommon.Must(EncodeRequestHeader(&buffer, expectedRequest, expectedAddons))\n\n\tValidator := new(vless.Validator)\n\tValidator.Add(user)\n\n\tactualRequest, actualAddons, err, _ := DecodeRequestHeader(false, nil, &buffer, Validator)\n\tcommon.Must(err)\n\n\tif r := cmp.Diff(actualRequest, expectedRequest, cmp.AllowUnexported(protocol.ID{})); r != \"\" {\n\t\tt.Error(r)\n\t}\n\tif r := cmp.Diff(actualAddons, expectedAddons); r != \"\" {\n\t\tt.Error(r)\n\t}\n}\n"
  },
  {
    "path": "proxy/vless/encoding/errors.generated.go",
    "content": "package encoding\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "proxy/vless/errors.generated.go",
    "content": "package vless\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "proxy/vless/inbound/config.go",
    "content": "// +build !confonly\n\npackage inbound\n"
  },
  {
    "path": "proxy/vless/inbound/config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: proxy/vless/inbound/config.proto\n\npackage inbound\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n\tprotocol \"v2ray.com/core/common/protocol\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype Fallback struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tAlpn string `protobuf:\"bytes,1,opt,name=alpn,proto3\" json:\"alpn,omitempty\"`\n\tPath string `protobuf:\"bytes,2,opt,name=path,proto3\" json:\"path,omitempty\"`\n\tType string `protobuf:\"bytes,3,opt,name=type,proto3\" json:\"type,omitempty\"`\n\tDest string `protobuf:\"bytes,4,opt,name=dest,proto3\" json:\"dest,omitempty\"`\n\tXver uint64 `protobuf:\"varint,5,opt,name=xver,proto3\" json:\"xver,omitempty\"`\n}\n\nfunc (x *Fallback) Reset() {\n\t*x = Fallback{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_proxy_vless_inbound_config_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Fallback) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Fallback) ProtoMessage() {}\n\nfunc (x *Fallback) ProtoReflect() protoreflect.Message {\n\tmi := &file_proxy_vless_inbound_config_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Fallback.ProtoReflect.Descriptor instead.\nfunc (*Fallback) Descriptor() ([]byte, []int) {\n\treturn file_proxy_vless_inbound_config_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *Fallback) GetAlpn() string {\n\tif x != nil {\n\t\treturn x.Alpn\n\t}\n\treturn \"\"\n}\n\nfunc (x *Fallback) GetPath() string {\n\tif x != nil {\n\t\treturn x.Path\n\t}\n\treturn \"\"\n}\n\nfunc (x *Fallback) GetType() string {\n\tif x != nil {\n\t\treturn x.Type\n\t}\n\treturn \"\"\n}\n\nfunc (x *Fallback) GetDest() string {\n\tif x != nil {\n\t\treturn x.Dest\n\t}\n\treturn \"\"\n}\n\nfunc (x *Fallback) GetXver() uint64 {\n\tif x != nil {\n\t\treturn x.Xver\n\t}\n\treturn 0\n}\n\ntype Config struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tClients []*protocol.User `protobuf:\"bytes,1,rep,name=clients,proto3\" json:\"clients,omitempty\"`\n\t// Decryption settings. Only applies to server side, and only accepts \"none\"\n\t// for now.\n\tDecryption string      `protobuf:\"bytes,2,opt,name=decryption,proto3\" json:\"decryption,omitempty\"`\n\tFallbacks  []*Fallback `protobuf:\"bytes,3,rep,name=fallbacks,proto3\" json:\"fallbacks,omitempty\"`\n}\n\nfunc (x *Config) Reset() {\n\t*x = Config{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_proxy_vless_inbound_config_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Config) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Config) ProtoMessage() {}\n\nfunc (x *Config) ProtoReflect() protoreflect.Message {\n\tmi := &file_proxy_vless_inbound_config_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Config.ProtoReflect.Descriptor instead.\nfunc (*Config) Descriptor() ([]byte, []int) {\n\treturn file_proxy_vless_inbound_config_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *Config) GetClients() []*protocol.User {\n\tif x != nil {\n\t\treturn x.Clients\n\t}\n\treturn nil\n}\n\nfunc (x *Config) GetDecryption() string {\n\tif x != nil {\n\t\treturn x.Decryption\n\t}\n\treturn \"\"\n}\n\nfunc (x *Config) GetFallbacks() []*Fallback {\n\tif x != nil {\n\t\treturn x.Fallbacks\n\t}\n\treturn nil\n}\n\nvar File_proxy_vless_inbound_config_proto protoreflect.FileDescriptor\n\nvar file_proxy_vless_inbound_config_proto_rawDesc = []byte{\n\t0x0a, 0x20, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2f, 0x69, 0x6e,\n\t0x62, 0x6f, 0x75, 0x6e, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f,\n\t0x74, 0x6f, 0x12, 0x1e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70,\n\t0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x69, 0x6e, 0x62, 0x6f, 0x75,\n\t0x6e, 0x64, 0x1a, 0x1a, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,\n\t0x63, 0x6f, 0x6c, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x6e,\n\t0x0a, 0x08, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x6c,\n\t0x70, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x61, 0x6c, 0x70, 0x6e, 0x12, 0x12,\n\t0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61,\n\t0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,\n\t0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x65, 0x73, 0x74, 0x18, 0x04,\n\t0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x78, 0x76,\n\t0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x78, 0x76, 0x65, 0x72, 0x22, 0xac,\n\t0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3a, 0x0a, 0x07, 0x63, 0x6c, 0x69,\n\t0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x76, 0x32, 0x72,\n\t0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70,\n\t0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x07, 0x63, 0x6c,\n\t0x69, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74,\n\t0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x65, 0x63, 0x72, 0x79,\n\t0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x46, 0x0a, 0x09, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63,\n\t0x6b, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,\n\t0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73,\n\t0x73, 0x2e, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x2e, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61,\n\t0x63, 0x6b, 0x52, 0x09, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x73, 0x42, 0x6b, 0x0a,\n\t0x22, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,\n\t0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x69, 0x6e, 0x62, 0x6f,\n\t0x75, 0x6e, 0x64, 0x50, 0x01, 0x5a, 0x22, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d,\n\t0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6c, 0x65, 0x73,\n\t0x73, 0x2f, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0xaa, 0x02, 0x1e, 0x56, 0x32, 0x52, 0x61,\n\t0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x56, 0x6c, 0x65,\n\t0x73, 0x73, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,\n\t0x6f, 0x33,\n}\n\nvar (\n\tfile_proxy_vless_inbound_config_proto_rawDescOnce sync.Once\n\tfile_proxy_vless_inbound_config_proto_rawDescData = file_proxy_vless_inbound_config_proto_rawDesc\n)\n\nfunc file_proxy_vless_inbound_config_proto_rawDescGZIP() []byte {\n\tfile_proxy_vless_inbound_config_proto_rawDescOnce.Do(func() {\n\t\tfile_proxy_vless_inbound_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_proxy_vless_inbound_config_proto_rawDescData)\n\t})\n\treturn file_proxy_vless_inbound_config_proto_rawDescData\n}\n\nvar file_proxy_vless_inbound_config_proto_msgTypes = make([]protoimpl.MessageInfo, 2)\nvar file_proxy_vless_inbound_config_proto_goTypes = []interface{}{\n\t(*Fallback)(nil),      // 0: v2ray.core.proxy.vless.inbound.Fallback\n\t(*Config)(nil),        // 1: v2ray.core.proxy.vless.inbound.Config\n\t(*protocol.User)(nil), // 2: v2ray.core.common.protocol.User\n}\nvar file_proxy_vless_inbound_config_proto_depIdxs = []int32{\n\t2, // 0: v2ray.core.proxy.vless.inbound.Config.clients:type_name -> v2ray.core.common.protocol.User\n\t0, // 1: v2ray.core.proxy.vless.inbound.Config.fallbacks:type_name -> v2ray.core.proxy.vless.inbound.Fallback\n\t2, // [2:2] is the sub-list for method output_type\n\t2, // [2:2] is the sub-list for method input_type\n\t2, // [2:2] is the sub-list for extension type_name\n\t2, // [2:2] is the sub-list for extension extendee\n\t0, // [0:2] is the sub-list for field type_name\n}\n\nfunc init() { file_proxy_vless_inbound_config_proto_init() }\nfunc file_proxy_vless_inbound_config_proto_init() {\n\tif File_proxy_vless_inbound_config_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_proxy_vless_inbound_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Fallback); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_proxy_vless_inbound_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Config); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_proxy_vless_inbound_config_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   2,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_proxy_vless_inbound_config_proto_goTypes,\n\t\tDependencyIndexes: file_proxy_vless_inbound_config_proto_depIdxs,\n\t\tMessageInfos:      file_proxy_vless_inbound_config_proto_msgTypes,\n\t}.Build()\n\tFile_proxy_vless_inbound_config_proto = out.File\n\tfile_proxy_vless_inbound_config_proto_rawDesc = nil\n\tfile_proxy_vless_inbound_config_proto_goTypes = nil\n\tfile_proxy_vless_inbound_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "proxy/vless/inbound/config.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.proxy.vless.inbound;\noption csharp_namespace = \"V2Ray.Core.Proxy.Vless.Inbound\";\noption go_package = \"v2ray.com/core/proxy/vless/inbound\";\noption java_package = \"com.v2ray.core.proxy.vless.inbound\";\noption java_multiple_files = true;\n\nimport \"common/protocol/user.proto\";\n\nmessage Fallback {\n  string alpn = 1;\n  string path = 2;\n  string type = 3;\n  string dest = 4;\n  uint64 xver = 5;\n}\n\nmessage Config {\n  repeated v2ray.core.common.protocol.User clients = 1;\n  // Decryption settings. Only applies to server side, and only accepts \"none\"\n  // for now.\n  string decryption = 2;\n  repeated Fallback fallbacks = 3;\n}\n"
  },
  {
    "path": "proxy/vless/inbound/errors.generated.go",
    "content": "package inbound\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "proxy/vless/inbound/inbound.go",
    "content": "// +build !confonly\n\npackage inbound\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/errors\"\n\t\"v2ray.com/core/common/log\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/platform\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/retry\"\n\t\"v2ray.com/core/common/session\"\n\t\"v2ray.com/core/common/signal\"\n\t\"v2ray.com/core/common/task\"\n\t\"v2ray.com/core/features/dns\"\n\tfeature_inbound \"v2ray.com/core/features/inbound\"\n\t\"v2ray.com/core/features/policy\"\n\t\"v2ray.com/core/features/routing\"\n\t\"v2ray.com/core/proxy/vless\"\n\t\"v2ray.com/core/proxy/vless/encoding\"\n\t\"v2ray.com/core/transport/internet\"\n\t\"v2ray.com/core/transport/internet/tls\"\n\t\"v2ray.com/core/transport/internet/xtls\"\n)\n\nvar (\n\txtls_show = false\n)\n\nfunc init() {\n\tcommon.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {\n\t\tvar dc dns.Client\n\t\tif err := core.RequireFeatures(ctx, func(d dns.Client) error {\n\t\t\tdc = d\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn New(ctx, config.(*Config), dc)\n\t}))\n\n\tconst defaultFlagValue = \"NOT_DEFINED_AT_ALL\"\n\n\txtlsShow := platform.NewEnvFlag(\"v2ray.vless.xtls.show\").GetValue(func() string { return defaultFlagValue })\n\tif xtlsShow == \"true\" {\n\t\txtls_show = true\n\t}\n}\n\n// Handler is an inbound connection handler that handles messages in VLess protocol.\ntype Handler struct {\n\tinboundHandlerManager feature_inbound.Manager\n\tpolicyManager         policy.Manager\n\tvalidator             *vless.Validator\n\tdns                   dns.Client\n\tfallbacks             map[string]map[string]*Fallback // or nil\n\t//regexps               map[string]*regexp.Regexp       // or nil\n}\n\n// New creates a new VLess inbound handler.\nfunc New(ctx context.Context, config *Config, dc dns.Client) (*Handler, error) {\n\n\tv := core.MustFromContext(ctx)\n\thandler := &Handler{\n\t\tinboundHandlerManager: v.GetFeature(feature_inbound.ManagerType()).(feature_inbound.Manager),\n\t\tpolicyManager:         v.GetFeature(policy.ManagerType()).(policy.Manager),\n\t\tvalidator:             new(vless.Validator),\n\t\tdns:                   dc,\n\t}\n\n\tfor _, user := range config.Clients {\n\t\tu, err := user.ToMemoryUser()\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"failed to get VLESS user\").Base(err).AtError()\n\t\t}\n\t\tif err := handler.AddUser(ctx, u); err != nil {\n\t\t\treturn nil, newError(\"failed to initiate user\").Base(err).AtError()\n\t\t}\n\t}\n\n\tif config.Fallbacks != nil {\n\t\thandler.fallbacks = make(map[string]map[string]*Fallback)\n\t\t//handler.regexps = make(map[string]*regexp.Regexp)\n\t\tfor _, fb := range config.Fallbacks {\n\t\t\tif handler.fallbacks[fb.Alpn] == nil {\n\t\t\t\thandler.fallbacks[fb.Alpn] = make(map[string]*Fallback)\n\t\t\t}\n\t\t\thandler.fallbacks[fb.Alpn][fb.Path] = fb\n\t\t\t/*\n\t\t\t\tif fb.Path != \"\" {\n\t\t\t\t\tif r, err := regexp.Compile(fb.Path); err != nil {\n\t\t\t\t\t\treturn nil, newError(\"invalid path regexp\").Base(err).AtError()\n\t\t\t\t\t} else {\n\t\t\t\t\t\thandler.regexps[fb.Path] = r\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t*/\n\t\t}\n\t\tif handler.fallbacks[\"\"] != nil {\n\t\t\tfor alpn, pfb := range handler.fallbacks {\n\t\t\t\tif alpn != \"\" { // && alpn != \"h2\" {\n\t\t\t\t\tfor path, fb := range handler.fallbacks[\"\"] {\n\t\t\t\t\t\tif pfb[path] == nil {\n\t\t\t\t\t\t\tpfb[path] = fb\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\treturn handler, nil\n}\n\n// Close implements common.Closable.Close().\nfunc (h *Handler) Close() error {\n\treturn errors.Combine(common.Close(h.validator))\n}\n\n// AddUser implements proxy.UserManager.AddUser().\nfunc (h *Handler) AddUser(ctx context.Context, u *protocol.MemoryUser) error {\n\treturn h.validator.Add(u)\n}\n\n// RemoveUser implements proxy.UserManager.RemoveUser().\nfunc (h *Handler) RemoveUser(ctx context.Context, e string) error {\n\treturn h.validator.Del(e)\n}\n\n// Network implements proxy.Inbound.Network().\nfunc (*Handler) Network() []net.Network {\n\treturn []net.Network{net.Network_TCP}\n}\n\n// Process implements proxy.Inbound.Process().\nfunc (h *Handler) Process(ctx context.Context, network net.Network, connection internet.Connection, dispatcher routing.Dispatcher) error {\n\n\tsid := session.ExportIDToError(ctx)\n\n\tiConn := connection\n\tif statConn, ok := iConn.(*internet.StatCouterConnection); ok {\n\t\tiConn = statConn.Connection\n\t}\n\n\tsessionPolicy := h.policyManager.ForLevel(0)\n\tif err := connection.SetReadDeadline(time.Now().Add(sessionPolicy.Timeouts.Handshake)); err != nil {\n\t\treturn newError(\"unable to set read deadline\").Base(err).AtWarning()\n\t}\n\n\tfirst := buf.New()\n\tdefer first.Release()\n\n\tfirstLen, _ := first.ReadFrom(connection)\n\tnewError(\"firstLen = \", firstLen).AtInfo().WriteToLog(sid)\n\n\treader := &buf.BufferedReader{\n\t\tReader: buf.NewReader(connection),\n\t\tBuffer: buf.MultiBuffer{first},\n\t}\n\n\tvar request *protocol.RequestHeader\n\tvar requestAddons *encoding.Addons\n\tvar err error\n\n\tapfb := h.fallbacks\n\tisfb := apfb != nil\n\n\tif isfb && firstLen < 18 {\n\t\terr = newError(\"fallback directly\")\n\t} else {\n\t\trequest, requestAddons, err, isfb = encoding.DecodeRequestHeader(isfb, first, reader, h.validator)\n\t}\n\n\tif err != nil {\n\n\t\tif isfb {\n\t\t\tif err := connection.SetReadDeadline(time.Time{}); err != nil {\n\t\t\t\tnewError(\"unable to set back read deadline\").Base(err).AtWarning().WriteToLog(sid)\n\t\t\t}\n\t\t\tnewError(\"fallback starts\").Base(err).AtInfo().WriteToLog(sid)\n\n\t\t\talpn := \"\"\n\t\t\tif len(apfb) > 1 || apfb[\"\"] == nil {\n\t\t\t\tif tlsConn, ok := iConn.(*tls.Conn); ok {\n\t\t\t\t\talpn = tlsConn.ConnectionState().NegotiatedProtocol\n\t\t\t\t\tnewError(\"realAlpn = \" + alpn).AtInfo().WriteToLog(sid)\n\t\t\t\t} else if xtlsConn, ok := iConn.(*xtls.Conn); ok {\n\t\t\t\t\talpn = xtlsConn.ConnectionState().NegotiatedProtocol\n\t\t\t\t\tnewError(\"realAlpn = \" + alpn).AtInfo().WriteToLog(sid)\n\t\t\t\t}\n\t\t\t\tif apfb[alpn] == nil {\n\t\t\t\t\talpn = \"\"\n\t\t\t\t}\n\t\t\t}\n\t\t\tpfb := apfb[alpn]\n\t\t\tif pfb == nil {\n\t\t\t\treturn newError(`failed to find the default \"alpn\" config`).AtWarning()\n\t\t\t}\n\n\t\t\tpath := \"\"\n\t\t\tif len(pfb) > 1 || pfb[\"\"] == nil {\n\t\t\t\t/*\n\t\t\t\t\tif lines := bytes.Split(firstBytes, []byte{'\\r', '\\n'}); len(lines) > 1 {\n\t\t\t\t\t\tif s := bytes.Split(lines[0], []byte{' '}); len(s) == 3 {\n\t\t\t\t\t\t\tif len(s[0]) < 8 && len(s[1]) > 0 && len(s[2]) == 8 {\n\t\t\t\t\t\t\t\tnewError(\"realPath = \" + string(s[1])).AtInfo().WriteToLog(sid)\n\t\t\t\t\t\t\t\tfor _, fb := range pfb {\n\t\t\t\t\t\t\t\t\tif fb.Path != \"\" && h.regexps[fb.Path].Match(s[1]) {\n\t\t\t\t\t\t\t\t\t\tpath = fb.Path\n\t\t\t\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\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\tif firstLen >= 18 && first.Byte(4) != '*' { // not h2c\n\t\t\t\t\tfirstBytes := first.Bytes()\n\t\t\t\t\tfor i := 4; i <= 8; i++ { // 5 -> 9\n\t\t\t\t\t\tif firstBytes[i] == '/' && firstBytes[i-1] == ' ' {\n\t\t\t\t\t\t\tsearch := len(firstBytes)\n\t\t\t\t\t\t\tif search > 64 {\n\t\t\t\t\t\t\t\tsearch = 64 // up to about 60\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tfor j := i + 1; j < search; j++ {\n\t\t\t\t\t\t\t\tk := firstBytes[j]\n\t\t\t\t\t\t\t\tif k == '\\r' || k == '\\n' { // avoid logging \\r or \\n\n\t\t\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif k == ' ' {\n\t\t\t\t\t\t\t\t\tpath = string(firstBytes[i:j])\n\t\t\t\t\t\t\t\t\tnewError(\"realPath = \" + path).AtInfo().WriteToLog(sid)\n\t\t\t\t\t\t\t\t\tif pfb[path] == nil {\n\t\t\t\t\t\t\t\t\t\tpath = \"\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\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}\n\t\t\t}\n\t\t\tfb := pfb[path]\n\t\t\tif fb == nil {\n\t\t\t\treturn newError(`failed to find the default \"path\" config`).AtWarning()\n\t\t\t}\n\n\t\t\tctx, cancel := context.WithCancel(ctx)\n\t\t\ttimer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)\n\t\t\tctx = policy.ContextWithBufferPolicy(ctx, sessionPolicy.Buffer)\n\n\t\t\tvar conn net.Conn\n\t\t\tif err := retry.ExponentialBackoff(5, 100).On(func() error {\n\t\t\t\tvar dialer net.Dialer\n\t\t\t\tconn, err = dialer.DialContext(ctx, fb.Type, fb.Dest)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\t\treturn newError(\"failed to dial to \" + fb.Dest).Base(err).AtWarning()\n\t\t\t}\n\t\t\tdefer conn.Close() // nolint: errcheck\n\n\t\t\tserverReader := buf.NewReader(conn)\n\t\t\tserverWriter := buf.NewWriter(conn)\n\n\t\t\tpostRequest := func() error {\n\t\t\t\tdefer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)\n\t\t\t\tif fb.Xver != 0 {\n\t\t\t\t\tremoteAddr, remotePort, err := net.SplitHostPort(connection.RemoteAddr().String())\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\tlocalAddr, localPort, err := net.SplitHostPort(connection.LocalAddr().String())\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\tipv4 := true\n\t\t\t\t\tfor i := 0; i < len(remoteAddr); i++ {\n\t\t\t\t\t\tif remoteAddr[i] == ':' {\n\t\t\t\t\t\t\tipv4 = false\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\tpro := buf.New()\n\t\t\t\t\tdefer pro.Release()\n\t\t\t\t\tswitch fb.Xver {\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\tif ipv4 {\n\t\t\t\t\t\t\tpro.Write([]byte(\"PROXY TCP4 \" + remoteAddr + \" \" + localAddr + \" \" + remotePort + \" \" + localPort + \"\\r\\n\"))\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tpro.Write([]byte(\"PROXY TCP6 \" + remoteAddr + \" \" + localAddr + \" \" + remotePort + \" \" + localPort + \"\\r\\n\"))\n\t\t\t\t\t\t}\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\tpro.Write([]byte(\"\\x0D\\x0A\\x0D\\x0A\\x00\\x0D\\x0A\\x51\\x55\\x49\\x54\\x0A\\x21\")) // signature + v2 + PROXY\n\t\t\t\t\t\tif ipv4 {\n\t\t\t\t\t\t\tpro.Write([]byte(\"\\x11\\x00\\x0C\")) // AF_INET + STREAM + 12 bytes\n\t\t\t\t\t\t\tpro.Write(net.ParseIP(remoteAddr).To4())\n\t\t\t\t\t\t\tpro.Write(net.ParseIP(localAddr).To4())\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tpro.Write([]byte(\"\\x21\\x00\\x24\")) // AF_INET6 + STREAM + 36 bytes\n\t\t\t\t\t\t\tpro.Write(net.ParseIP(remoteAddr).To16())\n\t\t\t\t\t\t\tpro.Write(net.ParseIP(localAddr).To16())\n\t\t\t\t\t\t}\n\t\t\t\t\t\tp1, _ := strconv.ParseUint(remotePort, 10, 16)\n\t\t\t\t\t\tp2, _ := strconv.ParseUint(localPort, 10, 16)\n\t\t\t\t\t\tpro.Write([]byte{byte(p1 >> 8), byte(p1), byte(p2 >> 8), byte(p2)})\n\t\t\t\t\t}\n\t\t\t\t\tif err := serverWriter.WriteMultiBuffer(buf.MultiBuffer{pro}); err != nil {\n\t\t\t\t\t\treturn newError(\"failed to set PROXY protocol v\", fb.Xver).Base(err).AtWarning()\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif err := buf.Copy(reader, serverWriter, buf.UpdateActivity(timer)); err != nil {\n\t\t\t\t\treturn newError(\"failed to fallback request payload\").Base(err).AtInfo()\n\t\t\t\t}\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\twriter := buf.NewWriter(connection)\n\n\t\t\tgetResponse := func() error {\n\t\t\t\tdefer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)\n\t\t\t\tif err := buf.Copy(serverReader, writer, buf.UpdateActivity(timer)); err != nil {\n\t\t\t\t\treturn newError(\"failed to deliver response payload\").Base(err).AtInfo()\n\t\t\t\t}\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\tif err := task.Run(ctx, task.OnSuccess(postRequest, task.Close(serverWriter)), task.OnSuccess(getResponse, task.Close(writer))); err != nil {\n\t\t\t\tcommon.Interrupt(serverReader)\n\t\t\t\tcommon.Interrupt(serverWriter)\n\t\t\t\treturn newError(\"fallback ends\").Base(err).AtInfo()\n\t\t\t}\n\t\t\treturn nil\n\t\t}\n\n\t\tif errors.Cause(err) != io.EOF {\n\t\t\tlog.Record(&log.AccessMessage{\n\t\t\t\tFrom:   connection.RemoteAddr(),\n\t\t\t\tTo:     \"\",\n\t\t\t\tStatus: log.AccessRejected,\n\t\t\t\tReason: err,\n\t\t\t})\n\t\t\terr = newError(\"invalid request from \", connection.RemoteAddr()).Base(err).AtWarning()\n\t\t}\n\t\treturn err\n\t}\n\n\tif err := connection.SetReadDeadline(time.Time{}); err != nil {\n\t\tnewError(\"unable to set back read deadline\").Base(err).AtWarning().WriteToLog(sid)\n\t}\n\tnewError(\"received request for \", request.Destination()).AtInfo().WriteToLog(sid)\n\n\tinbound := session.InboundFromContext(ctx)\n\tif inbound == nil {\n\t\tpanic(\"no inbound metadata\")\n\t}\n\tinbound.User = request.User\n\n\taccount := request.User.Account.(*vless.MemoryAccount)\n\n\tresponseAddons := &encoding.Addons{\n\t\t//Flow: requestAddons.Flow,\n\t}\n\n\tswitch requestAddons.Flow {\n\tcase vless.XRO, vless.XRD:\n\t\tif account.Flow == requestAddons.Flow {\n\t\t\tswitch request.Command {\n\t\t\tcase protocol.RequestCommandMux:\n\t\t\t\treturn newError(requestAddons.Flow + \" doesn't support Mux\").AtWarning()\n\t\t\tcase protocol.RequestCommandUDP:\n\t\t\t\treturn newError(requestAddons.Flow + \" doesn't support UDP\").AtWarning()\n\t\t\tcase protocol.RequestCommandTCP:\n\t\t\t\tif xtlsConn, ok := iConn.(*xtls.Conn); ok {\n\t\t\t\t\txtlsConn.RPRX = true\n\t\t\t\t\txtlsConn.SHOW = xtls_show\n\t\t\t\t\txtlsConn.MARK = \"XTLS\"\n\t\t\t\t\tif requestAddons.Flow == vless.XRD {\n\t\t\t\t\t\txtlsConn.DirectMode = true\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\treturn newError(`failed to use ` + requestAddons.Flow + `, maybe \"security\" is not \"xtls\"`).AtWarning()\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\treturn newError(account.ID.String() + \" is not able to use \" + requestAddons.Flow).AtWarning()\n\t\t}\n\tcase \"\":\n\tdefault:\n\t\treturn newError(\"unknown request flow \" + requestAddons.Flow).AtWarning()\n\t}\n\n\tif request.Command != protocol.RequestCommandMux {\n\t\tctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{\n\t\t\tFrom:   connection.RemoteAddr(),\n\t\t\tTo:     request.Destination(),\n\t\t\tStatus: log.AccessAccepted,\n\t\t\tReason: \"\",\n\t\t\tEmail:  request.User.Email,\n\t\t})\n\t}\n\n\tsessionPolicy = h.policyManager.ForLevel(request.User.Level)\n\tctx, cancel := context.WithCancel(ctx)\n\ttimer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)\n\tctx = policy.ContextWithBufferPolicy(ctx, sessionPolicy.Buffer)\n\n\tlink, err := dispatcher.Dispatch(ctx, request.Destination())\n\tif err != nil {\n\t\treturn newError(\"failed to dispatch request to \", request.Destination()).Base(err).AtWarning()\n\t}\n\n\tserverReader := link.Reader // .(*pipe.Reader)\n\tserverWriter := link.Writer // .(*pipe.Writer)\n\n\tpostRequest := func() error {\n\t\tdefer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)\n\n\t\t// default: clientReader := reader\n\t\tclientReader := encoding.DecodeBodyAddons(reader, request, requestAddons)\n\n\t\t// from clientReader.ReadMultiBuffer to serverWriter.WriteMultiBufer\n\t\tif err := buf.Copy(clientReader, serverWriter, buf.UpdateActivity(timer)); err != nil {\n\t\t\treturn newError(\"failed to transfer request payload\").Base(err).AtInfo()\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tgetResponse := func() error {\n\t\tdefer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)\n\n\t\tbufferWriter := buf.NewBufferedWriter(buf.NewWriter(connection))\n\t\tif err := encoding.EncodeResponseHeader(bufferWriter, request, responseAddons); err != nil {\n\t\t\treturn newError(\"failed to encode response header\").Base(err).AtWarning()\n\t\t}\n\n\t\t// default: clientWriter := bufferWriter\n\t\tclientWriter := encoding.EncodeBodyAddons(bufferWriter, request, responseAddons)\n\t\t{\n\t\t\tmultiBuffer, err := serverReader.ReadMultiBuffer()\n\t\t\tif err != nil {\n\t\t\t\treturn err // ...\n\t\t\t}\n\t\t\tif err := clientWriter.WriteMultiBuffer(multiBuffer); err != nil {\n\t\t\t\treturn err // ...\n\t\t\t}\n\t\t}\n\n\t\t// Flush; bufferWriter.WriteMultiBufer now is bufferWriter.writer.WriteMultiBuffer\n\t\tif err := bufferWriter.SetBuffered(false); err != nil {\n\t\t\treturn newError(\"failed to write A response payload\").Base(err).AtWarning()\n\t\t}\n\n\t\t// from serverReader.ReadMultiBuffer to clientWriter.WriteMultiBufer\n\t\tif err := buf.Copy(serverReader, clientWriter, buf.UpdateActivity(timer)); err != nil {\n\t\t\treturn newError(\"failed to transfer response payload\").Base(err).AtInfo()\n\t\t}\n\n\t\t// Indicates the end of response payload.\n\t\tswitch responseAddons.Flow {\n\t\tdefault:\n\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tif err := task.Run(ctx, task.OnSuccess(postRequest, task.Close(serverWriter)), getResponse); err != nil {\n\t\tcommon.Interrupt(serverReader)\n\t\tcommon.Interrupt(serverWriter)\n\t\treturn newError(\"connection ends\").Base(err).AtInfo()\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "proxy/vless/outbound/config.go",
    "content": "// +build !confonly\n\npackage outbound\n"
  },
  {
    "path": "proxy/vless/outbound/config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: proxy/vless/outbound/config.proto\n\npackage outbound\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n\tprotocol \"v2ray.com/core/common/protocol\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype Config struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tVnext []*protocol.ServerEndpoint `protobuf:\"bytes,1,rep,name=vnext,proto3\" json:\"vnext,omitempty\"`\n}\n\nfunc (x *Config) Reset() {\n\t*x = Config{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_proxy_vless_outbound_config_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Config) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Config) ProtoMessage() {}\n\nfunc (x *Config) ProtoReflect() protoreflect.Message {\n\tmi := &file_proxy_vless_outbound_config_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Config.ProtoReflect.Descriptor instead.\nfunc (*Config) Descriptor() ([]byte, []int) {\n\treturn file_proxy_vless_outbound_config_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *Config) GetVnext() []*protocol.ServerEndpoint {\n\tif x != nil {\n\t\treturn x.Vnext\n\t}\n\treturn nil\n}\n\nvar File_proxy_vless_outbound_config_proto protoreflect.FileDescriptor\n\nvar file_proxy_vless_outbound_config_proto_rawDesc = []byte{\n\t0x0a, 0x21, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2f, 0x6f, 0x75,\n\t0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72,\n\t0x6f, 0x74, 0x6f, 0x12, 0x1f, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,\n\t0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x6f, 0x75, 0x74, 0x62,\n\t0x6f, 0x75, 0x6e, 0x64, 0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f,\n\t0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x70, 0x65,\n\t0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x4a, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69,\n\t0x67, 0x12, 0x40, 0x0a, 0x05, 0x76, 0x6e, 0x65, 0x78, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b,\n\t0x32, 0x2a, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f,\n\t0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65,\n\t0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x05, 0x76, 0x6e,\n\t0x65, 0x78, 0x74, 0x42, 0x6e, 0x0a, 0x23, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,\n\t0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73,\n\t0x73, 0x2e, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x50, 0x01, 0x5a, 0x23, 0x76, 0x32,\n\t0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f,\n\t0x78, 0x79, 0x2f, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2f, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e,\n\t0x64, 0xaa, 0x02, 0x1f, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x50,\n\t0x72, 0x6f, 0x78, 0x79, 0x2e, 0x56, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x4f, 0x75, 0x74, 0x62, 0x6f,\n\t0x75, 0x6e, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_proxy_vless_outbound_config_proto_rawDescOnce sync.Once\n\tfile_proxy_vless_outbound_config_proto_rawDescData = file_proxy_vless_outbound_config_proto_rawDesc\n)\n\nfunc file_proxy_vless_outbound_config_proto_rawDescGZIP() []byte {\n\tfile_proxy_vless_outbound_config_proto_rawDescOnce.Do(func() {\n\t\tfile_proxy_vless_outbound_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_proxy_vless_outbound_config_proto_rawDescData)\n\t})\n\treturn file_proxy_vless_outbound_config_proto_rawDescData\n}\n\nvar file_proxy_vless_outbound_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)\nvar file_proxy_vless_outbound_config_proto_goTypes = []interface{}{\n\t(*Config)(nil),                  // 0: v2ray.core.proxy.vless.outbound.Config\n\t(*protocol.ServerEndpoint)(nil), // 1: v2ray.core.common.protocol.ServerEndpoint\n}\nvar file_proxy_vless_outbound_config_proto_depIdxs = []int32{\n\t1, // 0: v2ray.core.proxy.vless.outbound.Config.vnext:type_name -> v2ray.core.common.protocol.ServerEndpoint\n\t1, // [1:1] is the sub-list for method output_type\n\t1, // [1:1] is the sub-list for method input_type\n\t1, // [1:1] is the sub-list for extension type_name\n\t1, // [1:1] is the sub-list for extension extendee\n\t0, // [0:1] is the sub-list for field type_name\n}\n\nfunc init() { file_proxy_vless_outbound_config_proto_init() }\nfunc file_proxy_vless_outbound_config_proto_init() {\n\tif File_proxy_vless_outbound_config_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_proxy_vless_outbound_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Config); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_proxy_vless_outbound_config_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   1,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_proxy_vless_outbound_config_proto_goTypes,\n\t\tDependencyIndexes: file_proxy_vless_outbound_config_proto_depIdxs,\n\t\tMessageInfos:      file_proxy_vless_outbound_config_proto_msgTypes,\n\t}.Build()\n\tFile_proxy_vless_outbound_config_proto = out.File\n\tfile_proxy_vless_outbound_config_proto_rawDesc = nil\n\tfile_proxy_vless_outbound_config_proto_goTypes = nil\n\tfile_proxy_vless_outbound_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "proxy/vless/outbound/config.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.proxy.vless.outbound;\noption csharp_namespace = \"V2Ray.Core.Proxy.Vless.Outbound\";\noption go_package = \"v2ray.com/core/proxy/vless/outbound\";\noption java_package = \"com.v2ray.core.proxy.vless.outbound\";\noption java_multiple_files = true;\n\nimport \"common/protocol/server_spec.proto\";\n\nmessage Config {\n  repeated v2ray.core.common.protocol.ServerEndpoint vnext = 1;\n}\n"
  },
  {
    "path": "proxy/vless/outbound/errors.generated.go",
    "content": "package outbound\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "proxy/vless/outbound/outbound.go",
    "content": "// +build !confonly\n\npackage outbound\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/platform\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/retry\"\n\t\"v2ray.com/core/common/session\"\n\t\"v2ray.com/core/common/signal\"\n\t\"v2ray.com/core/common/task\"\n\t\"v2ray.com/core/features/policy\"\n\t\"v2ray.com/core/proxy/vless\"\n\t\"v2ray.com/core/proxy/vless/encoding\"\n\t\"v2ray.com/core/transport\"\n\t\"v2ray.com/core/transport/internet\"\n\t\"v2ray.com/core/transport/internet/xtls\"\n)\n\nvar (\n\txtls_show = false\n)\n\nfunc init() {\n\tcommon.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {\n\t\treturn New(ctx, config.(*Config))\n\t}))\n\n\tconst defaultFlagValue = \"NOT_DEFINED_AT_ALL\"\n\n\txtlsShow := platform.NewEnvFlag(\"v2ray.vless.xtls.show\").GetValue(func() string { return defaultFlagValue })\n\tif xtlsShow == \"true\" {\n\t\txtls_show = true\n\t}\n}\n\n// Handler is an outbound connection handler for VLess protocol.\ntype Handler struct {\n\tserverList    *protocol.ServerList\n\tserverPicker  protocol.ServerPicker\n\tpolicyManager policy.Manager\n}\n\n// New creates a new VLess outbound handler.\nfunc New(ctx context.Context, config *Config) (*Handler, error) {\n\n\tserverList := protocol.NewServerList()\n\tfor _, rec := range config.Vnext {\n\t\ts, err := protocol.NewServerSpecFromPB(rec)\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"failed to parse server spec\").Base(err).AtError()\n\t\t}\n\t\tserverList.AddServer(s)\n\t}\n\n\tv := core.MustFromContext(ctx)\n\thandler := &Handler{\n\t\tserverList:    serverList,\n\t\tserverPicker:  protocol.NewRoundRobinServerPicker(serverList),\n\t\tpolicyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),\n\t}\n\n\treturn handler, nil\n}\n\n// Process implements proxy.Outbound.Process().\nfunc (h *Handler) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {\n\n\tvar rec *protocol.ServerSpec\n\tvar conn internet.Connection\n\n\tif err := retry.ExponentialBackoff(5, 200).On(func() error {\n\t\trec = h.serverPicker.PickServer()\n\t\tvar err error\n\t\tconn, err = dialer.Dial(ctx, rec.Destination())\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t}); err != nil {\n\t\treturn newError(\"failed to find an available destination\").Base(err).AtWarning()\n\t}\n\tdefer conn.Close() // nolint: errcheck\n\n\tiConn := conn\n\tif statConn, ok := iConn.(*internet.StatCouterConnection); ok {\n\t\tiConn = statConn.Connection\n\t}\n\n\toutbound := session.OutboundFromContext(ctx)\n\tif outbound == nil || !outbound.Target.IsValid() {\n\t\treturn newError(\"target not specified\").AtError()\n\t}\n\n\ttarget := outbound.Target\n\tnewError(\"tunneling request to \", target, \" via \", rec.Destination()).AtInfo().WriteToLog(session.ExportIDToError(ctx))\n\n\tcommand := protocol.RequestCommandTCP\n\tif target.Network == net.Network_UDP {\n\t\tcommand = protocol.RequestCommandUDP\n\t}\n\tif target.Address.Family().IsDomain() && target.Address.Domain() == \"v1.mux.cool\" {\n\t\tcommand = protocol.RequestCommandMux\n\t}\n\n\trequest := &protocol.RequestHeader{\n\t\tVersion: encoding.Version,\n\t\tUser:    rec.PickUser(),\n\t\tCommand: command,\n\t\tAddress: target.Address,\n\t\tPort:    target.Port,\n\t}\n\n\taccount := request.User.Account.(*vless.MemoryAccount)\n\n\trequestAddons := &encoding.Addons{\n\t\tFlow: account.Flow,\n\t}\n\n\tallowUDP443 := false\n\tswitch requestAddons.Flow {\n\tcase vless.XRO + \"-udp443\", vless.XRD + \"-udp443\":\n\t\tallowUDP443 = true\n\t\trequestAddons.Flow = requestAddons.Flow[:16]\n\t\tfallthrough\n\tcase vless.XRO, vless.XRD:\n\t\tswitch request.Command {\n\t\tcase protocol.RequestCommandMux:\n\t\t\treturn newError(requestAddons.Flow + \" doesn't support Mux\").AtWarning()\n\t\tcase protocol.RequestCommandUDP:\n\t\t\tif !allowUDP443 && request.Port == 443 {\n\t\t\t\treturn newError(requestAddons.Flow + \" stopped UDP/443\").AtInfo()\n\t\t\t}\n\t\t\trequestAddons.Flow = \"\"\n\t\tcase protocol.RequestCommandTCP:\n\t\t\tif xtlsConn, ok := iConn.(*xtls.Conn); ok {\n\t\t\t\txtlsConn.RPRX = true\n\t\t\t\txtlsConn.SHOW = xtls_show\n\t\t\t\txtlsConn.MARK = \"XTLS\"\n\t\t\t\tif requestAddons.Flow == vless.XRD {\n\t\t\t\t\txtlsConn.DirectMode = true\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn newError(`failed to use ` + requestAddons.Flow + `, maybe \"security\" is not \"xtls\"`).AtWarning()\n\t\t\t}\n\t\t}\n\tdefault:\n\t\tif _, ok := iConn.(*xtls.Conn); ok {\n\t\t\tpanic(`To avoid misunderstanding, you must fill in VLESS \"flow\" when using XTLS.`)\n\t\t}\n\t}\n\n\tsessionPolicy := h.policyManager.ForLevel(request.User.Level)\n\tctx, cancel := context.WithCancel(ctx)\n\ttimer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)\n\n\tclientReader := link.Reader // .(*pipe.Reader)\n\tclientWriter := link.Writer // .(*pipe.Writer)\n\n\tpostRequest := func() error {\n\t\tdefer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)\n\n\t\tbufferWriter := buf.NewBufferedWriter(buf.NewWriter(conn))\n\t\tif err := encoding.EncodeRequestHeader(bufferWriter, request, requestAddons); err != nil {\n\t\t\treturn newError(\"failed to encode request header\").Base(err).AtWarning()\n\t\t}\n\n\t\t// default: serverWriter := bufferWriter\n\t\tserverWriter := encoding.EncodeBodyAddons(bufferWriter, request, requestAddons)\n\t\tif err := buf.CopyOnceTimeout(clientReader, serverWriter, time.Millisecond*100); err != nil && err != buf.ErrNotTimeoutReader && err != buf.ErrReadTimeout {\n\t\t\treturn err // ...\n\t\t}\n\n\t\t// Flush; bufferWriter.WriteMultiBufer now is bufferWriter.writer.WriteMultiBuffer\n\t\tif err := bufferWriter.SetBuffered(false); err != nil {\n\t\t\treturn newError(\"failed to write A request payload\").Base(err).AtWarning()\n\t\t}\n\n\t\t// from clientReader.ReadMultiBuffer to serverWriter.WriteMultiBufer\n\t\tif err := buf.Copy(clientReader, serverWriter, buf.UpdateActivity(timer)); err != nil {\n\t\t\treturn newError(\"failed to transfer request payload\").Base(err).AtInfo()\n\t\t}\n\n\t\t// Indicates the end of request payload.\n\t\tswitch requestAddons.Flow {\n\t\tdefault:\n\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tgetResponse := func() error {\n\t\tdefer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)\n\n\t\tresponseAddons, err := encoding.DecodeResponseHeader(conn, request)\n\t\tif err != nil {\n\t\t\treturn newError(\"failed to decode response header\").Base(err).AtWarning()\n\t\t}\n\n\t\t// default: serverReader := buf.NewReader(conn)\n\t\tserverReader := encoding.DecodeBodyAddons(conn, request, responseAddons)\n\n\t\t// from serverReader.ReadMultiBuffer to clientWriter.WriteMultiBufer\n\t\tif err := buf.Copy(serverReader, clientWriter, buf.UpdateActivity(timer)); err != nil {\n\t\t\treturn newError(\"failed to transfer response payload\").Base(err).AtInfo()\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tif err := task.Run(ctx, postRequest, task.OnSuccess(getResponse, task.Close(clientWriter))); err != nil {\n\t\treturn newError(\"connection ends\").Base(err).AtInfo()\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "proxy/vless/validator.go",
    "content": "// +build !confonly\n\npackage vless\n\nimport (\n\t\"strings\"\n\t\"sync\"\n\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/uuid\"\n)\n\ntype Validator struct {\n\t// Considering email's usage here, map + sync.Mutex/RWMutex may have better performance.\n\temail sync.Map\n\tusers sync.Map\n}\n\nfunc (v *Validator) Add(u *protocol.MemoryUser) error {\n\tif u.Email != \"\" {\n\t\t_, loaded := v.email.LoadOrStore(strings.ToLower(u.Email), u)\n\t\tif loaded {\n\t\t\treturn newError(\"User \", u.Email, \" already exists.\")\n\t\t}\n\t}\n\tv.users.Store(u.Account.(*MemoryAccount).ID.UUID(), u)\n\treturn nil\n}\n\nfunc (v *Validator) Del(e string) error {\n\tif e == \"\" {\n\t\treturn newError(\"Email must not be empty.\")\n\t}\n\tle := strings.ToLower(e)\n\tu, _ := v.email.Load(le)\n\tif u == nil {\n\t\treturn newError(\"User \", e, \" not found.\")\n\t}\n\tv.email.Delete(le)\n\tv.users.Delete(u.(*protocol.MemoryUser).Account.(*MemoryAccount).ID.UUID())\n\treturn nil\n}\n\nfunc (v *Validator) Get(id uuid.UUID) *protocol.MemoryUser {\n\tu, _ := v.users.Load(id)\n\tif u != nil {\n\t\treturn u.(*protocol.MemoryUser)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "proxy/vless/vless.go",
    "content": "// Package vless contains the implementation of VLess protocol and transportation.\n//\n// VLess contains both inbound and outbound connections. VLess inbound is usually used on servers\n// together with 'freedom' to talk to final destination, while VLess outbound is usually used on\n// clients with 'socks' for proxying.\npackage vless\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n\nconst (\n\tXRO = \"xtls-rprx-origin\"\n\tXRD = \"xtls-rprx-direct\"\n)\n"
  },
  {
    "path": "proxy/vmess/account.go",
    "content": "// +build !confonly\n\npackage vmess\n\nimport (\n\t\"v2ray.com/core/common/dice\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/uuid\"\n)\n\n// MemoryAccount is an in-memory form of VMess account.\ntype MemoryAccount struct {\n\t// ID is the main ID of the account.\n\tID *protocol.ID\n\t// AlterIDs are the alternative IDs of the account.\n\tAlterIDs []*protocol.ID\n\t// Security type of the account. Used for client connections.\n\tSecurity protocol.SecurityType\n}\n\n// AnyValidID returns an ID that is either the main ID or one of the alternative IDs if any.\nfunc (a *MemoryAccount) AnyValidID() *protocol.ID {\n\tif len(a.AlterIDs) == 0 {\n\t\treturn a.ID\n\t}\n\treturn a.AlterIDs[dice.Roll(len(a.AlterIDs))]\n}\n\n// Equals implements protocol.Account.\nfunc (a *MemoryAccount) Equals(account protocol.Account) bool {\n\tvmessAccount, ok := account.(*MemoryAccount)\n\tif !ok {\n\t\treturn false\n\t}\n\t// TODO: handle AlterIds difference\n\treturn a.ID.Equals(vmessAccount.ID)\n}\n\n// AsAccount implements protocol.Account.\nfunc (a *Account) AsAccount() (protocol.Account, error) {\n\tid, err := uuid.ParseString(a.Id)\n\tif err != nil {\n\t\treturn nil, newError(\"failed to parse ID\").Base(err).AtError()\n\t}\n\tprotoID := protocol.NewID(id)\n\treturn &MemoryAccount{\n\t\tID:       protoID,\n\t\tAlterIDs: protocol.NewAlterIDs(protoID, uint16(a.AlterId)),\n\t\tSecurity: a.SecuritySettings.GetSecurityType(),\n\t}, nil\n}\n"
  },
  {
    "path": "proxy/vmess/account.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: proxy/vmess/account.proto\n\npackage vmess\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n\tprotocol \"v2ray.com/core/common/protocol\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype Account struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// ID of the account, in the form of a UUID, e.g.,\n\t// \"66ad4540-b58c-4ad2-9926-ea63445a9b57\".\n\tId string `protobuf:\"bytes,1,opt,name=id,proto3\" json:\"id,omitempty\"`\n\t// Number of alternative IDs. Client and server must share the same number.\n\tAlterId uint32 `protobuf:\"varint,2,opt,name=alter_id,json=alterId,proto3\" json:\"alter_id,omitempty\"`\n\t// Security settings. Only applies to client side.\n\tSecuritySettings *protocol.SecurityConfig `protobuf:\"bytes,3,opt,name=security_settings,json=securitySettings,proto3\" json:\"security_settings,omitempty\"`\n\t// Define tests enabled for this account\n\tTestsEnabled string `protobuf:\"bytes,4,opt,name=tests_enabled,json=testsEnabled,proto3\" json:\"tests_enabled,omitempty\"`\n}\n\nfunc (x *Account) Reset() {\n\t*x = Account{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_proxy_vmess_account_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Account) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Account) ProtoMessage() {}\n\nfunc (x *Account) ProtoReflect() protoreflect.Message {\n\tmi := &file_proxy_vmess_account_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Account.ProtoReflect.Descriptor instead.\nfunc (*Account) Descriptor() ([]byte, []int) {\n\treturn file_proxy_vmess_account_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *Account) GetId() string {\n\tif x != nil {\n\t\treturn x.Id\n\t}\n\treturn \"\"\n}\n\nfunc (x *Account) GetAlterId() uint32 {\n\tif x != nil {\n\t\treturn x.AlterId\n\t}\n\treturn 0\n}\n\nfunc (x *Account) GetSecuritySettings() *protocol.SecurityConfig {\n\tif x != nil {\n\t\treturn x.SecuritySettings\n\t}\n\treturn nil\n}\n\nfunc (x *Account) GetTestsEnabled() string {\n\tif x != nil {\n\t\treturn x.TestsEnabled\n\t}\n\treturn \"\"\n}\n\nvar File_proxy_vmess_account_proto protoreflect.FileDescriptor\n\nvar file_proxy_vmess_account_proto_rawDesc = []byte{\n\t0x0a, 0x19, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6d, 0x65, 0x73, 0x73, 0x2f, 0x61, 0x63,\n\t0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x16, 0x76, 0x32, 0x72,\n\t0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6d,\n\t0x65, 0x73, 0x73, 0x1a, 0x1d, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74,\n\t0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f,\n\t0x74, 0x6f, 0x22, 0xb2, 0x01, 0x0a, 0x07, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x0e,\n\t0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x19,\n\t0x0a, 0x08, 0x61, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d,\n\t0x52, 0x07, 0x61, 0x6c, 0x74, 0x65, 0x72, 0x49, 0x64, 0x12, 0x57, 0x0a, 0x11, 0x73, 0x65, 0x63,\n\t0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x03,\n\t0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72,\n\t0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,\n\t0x6c, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,\n\t0x52, 0x10, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e,\n\t0x67, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x74, 0x65, 0x73, 0x74, 0x73, 0x5f, 0x65, 0x6e, 0x61, 0x62,\n\t0x6c, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x74, 0x65, 0x73, 0x74, 0x73,\n\t0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x42, 0x53, 0x0a, 0x1a, 0x63, 0x6f, 0x6d, 0x2e, 0x76,\n\t0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e,\n\t0x76, 0x6d, 0x65, 0x73, 0x73, 0x50, 0x01, 0x5a, 0x1a, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,\n\t0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6d,\n\t0x65, 0x73, 0x73, 0xaa, 0x02, 0x16, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65,\n\t0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x56, 0x6d, 0x65, 0x73, 0x73, 0x62, 0x06, 0x70, 0x72,\n\t0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_proxy_vmess_account_proto_rawDescOnce sync.Once\n\tfile_proxy_vmess_account_proto_rawDescData = file_proxy_vmess_account_proto_rawDesc\n)\n\nfunc file_proxy_vmess_account_proto_rawDescGZIP() []byte {\n\tfile_proxy_vmess_account_proto_rawDescOnce.Do(func() {\n\t\tfile_proxy_vmess_account_proto_rawDescData = protoimpl.X.CompressGZIP(file_proxy_vmess_account_proto_rawDescData)\n\t})\n\treturn file_proxy_vmess_account_proto_rawDescData\n}\n\nvar file_proxy_vmess_account_proto_msgTypes = make([]protoimpl.MessageInfo, 1)\nvar file_proxy_vmess_account_proto_goTypes = []interface{}{\n\t(*Account)(nil),                 // 0: v2ray.core.proxy.vmess.Account\n\t(*protocol.SecurityConfig)(nil), // 1: v2ray.core.common.protocol.SecurityConfig\n}\nvar file_proxy_vmess_account_proto_depIdxs = []int32{\n\t1, // 0: v2ray.core.proxy.vmess.Account.security_settings:type_name -> v2ray.core.common.protocol.SecurityConfig\n\t1, // [1:1] is the sub-list for method output_type\n\t1, // [1:1] is the sub-list for method input_type\n\t1, // [1:1] is the sub-list for extension type_name\n\t1, // [1:1] is the sub-list for extension extendee\n\t0, // [0:1] is the sub-list for field type_name\n}\n\nfunc init() { file_proxy_vmess_account_proto_init() }\nfunc file_proxy_vmess_account_proto_init() {\n\tif File_proxy_vmess_account_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_proxy_vmess_account_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Account); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_proxy_vmess_account_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   1,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_proxy_vmess_account_proto_goTypes,\n\t\tDependencyIndexes: file_proxy_vmess_account_proto_depIdxs,\n\t\tMessageInfos:      file_proxy_vmess_account_proto_msgTypes,\n\t}.Build()\n\tFile_proxy_vmess_account_proto = out.File\n\tfile_proxy_vmess_account_proto_rawDesc = nil\n\tfile_proxy_vmess_account_proto_goTypes = nil\n\tfile_proxy_vmess_account_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "proxy/vmess/account.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.proxy.vmess;\noption csharp_namespace = \"V2Ray.Core.Proxy.Vmess\";\noption go_package = \"v2ray.com/core/proxy/vmess\";\noption java_package = \"com.v2ray.core.proxy.vmess\";\noption java_multiple_files = true;\n\nimport \"common/protocol/headers.proto\";\n\nmessage Account {\n  // ID of the account, in the form of a UUID, e.g.,\n  // \"66ad4540-b58c-4ad2-9926-ea63445a9b57\".\n  string id = 1;\n  // Number of alternative IDs. Client and server must share the same number.\n  uint32 alter_id = 2;\n  // Security settings. Only applies to client side.\n  v2ray.core.common.protocol.SecurityConfig security_settings = 3;\n  // Define tests enabled for this account\n  string tests_enabled = 4;\n}\n"
  },
  {
    "path": "proxy/vmess/aead/authid.go",
    "content": "package aead\n\nimport (\n\t\"bytes\"\n\t\"crypto/aes\"\n\t\"crypto/cipher\"\n\trand3 \"crypto/rand\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"hash/crc32\"\n\t\"io\"\n\t\"math\"\n\t\"time\"\n\t\"v2ray.com/core/common\"\n\tantiReplayWindow \"v2ray.com/core/common/antireplay\"\n)\n\nfunc CreateAuthID(cmdKey []byte, time int64) [16]byte {\n\tbuf := bytes.NewBuffer(nil)\n\tcommon.Must(binary.Write(buf, binary.BigEndian, time))\n\tvar zero uint32\n\tcommon.Must2(io.CopyN(buf, rand3.Reader, 4))\n\tzero = crc32.ChecksumIEEE(buf.Bytes())\n\tcommon.Must(binary.Write(buf, binary.BigEndian, zero))\n\taesBlock := NewCipherFromKey(cmdKey)\n\tif buf.Len() != 16 {\n\t\tpanic(\"Size unexpected\")\n\t}\n\tvar result [16]byte\n\taesBlock.Encrypt(result[:], buf.Bytes())\n\treturn result\n}\n\nfunc NewCipherFromKey(cmdKey []byte) cipher.Block {\n\taesBlock, err := aes.NewCipher(KDF16(cmdKey, KDFSaltConst_AuthIDEncryptionKey))\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn aesBlock\n}\n\ntype AuthIDDecoder struct {\n\ts cipher.Block\n}\n\nfunc NewAuthIDDecoder(cmdKey []byte) *AuthIDDecoder {\n\treturn &AuthIDDecoder{NewCipherFromKey(cmdKey)}\n}\n\nfunc (aidd *AuthIDDecoder) Decode(data [16]byte) (int64, uint32, int32, []byte) {\n\taidd.s.Decrypt(data[:], data[:])\n\tvar t int64\n\tvar zero uint32\n\tvar rand int32\n\treader := bytes.NewReader(data[:])\n\tcommon.Must(binary.Read(reader, binary.BigEndian, &t))\n\tcommon.Must(binary.Read(reader, binary.BigEndian, &rand))\n\tcommon.Must(binary.Read(reader, binary.BigEndian, &zero))\n\treturn t, zero, rand, data[:]\n}\n\nfunc NewAuthIDDecoderHolder() *AuthIDDecoderHolder {\n\treturn &AuthIDDecoderHolder{make(map[string]*AuthIDDecoderItem), antiReplayWindow.NewAntiReplayWindow(120)}\n}\n\ntype AuthIDDecoderHolder struct {\n\taidhi map[string]*AuthIDDecoderItem\n\tapw   *antiReplayWindow.AntiReplayWindow\n}\n\ntype AuthIDDecoderItem struct {\n\tdec    *AuthIDDecoder\n\tticket interface{}\n}\n\nfunc NewAuthIDDecoderItem(key [16]byte, ticket interface{}) *AuthIDDecoderItem {\n\treturn &AuthIDDecoderItem{\n\t\tdec:    NewAuthIDDecoder(key[:]),\n\t\tticket: ticket,\n\t}\n}\n\nfunc (a *AuthIDDecoderHolder) AddUser(key [16]byte, ticket interface{}) {\n\ta.aidhi[string(key[:])] = NewAuthIDDecoderItem(key, ticket)\n}\n\nfunc (a *AuthIDDecoderHolder) RemoveUser(key [16]byte) {\n\tdelete(a.aidhi, string(key[:]))\n}\n\nfunc (a *AuthIDDecoderHolder) Match(AuthID [16]byte) (interface{}, error) {\n\tfor _, v := range a.aidhi {\n\n\t\tt, z, r, d := v.dec.Decode(AuthID)\n\t\tif z != crc32.ChecksumIEEE(d[:12]) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif t < 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tif math.Abs(math.Abs(float64(t))-float64(time.Now().Unix())) > 120 {\n\t\t\tcontinue\n\t\t}\n\n\t\tif !a.apw.Check(AuthID[:]) {\n\t\t\treturn nil, ErrReplay\n\t\t}\n\n\t\t_ = r\n\n\t\treturn v.ticket, nil\n\n\t}\n\treturn nil, ErrNotFound\n}\n\nvar ErrNotFound = errors.New(\"user do not exist\")\n\nvar ErrReplay = errors.New(\"replayed request\")\n"
  },
  {
    "path": "proxy/vmess/aead/authid_test.go",
    "content": "package aead\n\nimport (\n\t\"fmt\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"strconv\"\n\t\"testing\"\n\t\"time\"\n)\n\nfunc TestCreateAuthID(t *testing.T) {\n\tkey := KDF16([]byte(\"Demo Key for Auth ID Test\"), \"Demo Path for Auth ID Test\")\n\tauthid := CreateAuthID(key, time.Now().Unix())\n\n\tfmt.Println(key)\n\tfmt.Println(authid)\n}\n\nfunc TestCreateAuthIDAndDecode(t *testing.T) {\n\tkey := KDF16([]byte(\"Demo Key for Auth ID Test\"), \"Demo Path for Auth ID Test\")\n\tauthid := CreateAuthID(key, time.Now().Unix())\n\n\tfmt.Println(key)\n\tfmt.Println(authid)\n\n\tAuthDecoder := NewAuthIDDecoderHolder()\n\tvar keyw [16]byte\n\tcopy(keyw[:], key)\n\tAuthDecoder.AddUser(keyw, \"Demo User\")\n\tres, err := AuthDecoder.Match(authid)\n\tfmt.Println(res)\n\tfmt.Println(err)\n\tassert.Equal(t, \"Demo User\", res)\n\tassert.Nil(t, err)\n}\n\nfunc TestCreateAuthIDAndDecode2(t *testing.T) {\n\tkey := KDF16([]byte(\"Demo Key for Auth ID Test\"), \"Demo Path for Auth ID Test\")\n\tauthid := CreateAuthID(key, time.Now().Unix())\n\n\tfmt.Println(key)\n\tfmt.Println(authid)\n\n\tAuthDecoder := NewAuthIDDecoderHolder()\n\tvar keyw [16]byte\n\tcopy(keyw[:], key)\n\tAuthDecoder.AddUser(keyw, \"Demo User\")\n\tres, err := AuthDecoder.Match(authid)\n\tfmt.Println(res)\n\tfmt.Println(err)\n\tassert.Equal(t, \"Demo User\", res)\n\tassert.Nil(t, err)\n\n\tkey2 := KDF16([]byte(\"Demo Key for Auth ID Test2\"), \"Demo Path for Auth ID Test\")\n\tauthid2 := CreateAuthID(key2, time.Now().Unix())\n\n\tres2, err2 := AuthDecoder.Match(authid2)\n\tassert.EqualError(t, err2, \"user do not exist\")\n\tassert.Nil(t, res2)\n\n}\n\nfunc TestCreateAuthIDAndDecodeMassive(t *testing.T) {\n\tkey := KDF16([]byte(\"Demo Key for Auth ID Test\"), \"Demo Path for Auth ID Test\")\n\tauthid := CreateAuthID(key, time.Now().Unix())\n\n\tfmt.Println(key)\n\tfmt.Println(authid)\n\n\tAuthDecoder := NewAuthIDDecoderHolder()\n\tvar keyw [16]byte\n\tcopy(keyw[:], key)\n\tAuthDecoder.AddUser(keyw, \"Demo User\")\n\tres, err := AuthDecoder.Match(authid)\n\tfmt.Println(res)\n\tfmt.Println(err)\n\tassert.Equal(t, \"Demo User\", res)\n\tassert.Nil(t, err)\n\n\tfor i := 0; i <= 10000; i++ {\n\t\tkey2 := KDF16([]byte(\"Demo Key for Auth ID Test2\"), \"Demo Path for Auth ID Test\", strconv.Itoa(i))\n\t\tvar keyw2 [16]byte\n\t\tcopy(keyw2[:], key2)\n\t\tAuthDecoder.AddUser(keyw2, \"Demo User\"+strconv.Itoa(i))\n\t}\n\n\tauthid3 := CreateAuthID(key, time.Now().Unix())\n\n\tres2, err2 := AuthDecoder.Match(authid3)\n\tassert.Equal(t, \"Demo User\", res2)\n\tassert.Nil(t, err2)\n\n}\n\nfunc TestCreateAuthIDAndDecodeSuperMassive(t *testing.T) {\n\tkey := KDF16([]byte(\"Demo Key for Auth ID Test\"), \"Demo Path for Auth ID Test\")\n\tauthid := CreateAuthID(key, time.Now().Unix())\n\n\tfmt.Println(key)\n\tfmt.Println(authid)\n\n\tAuthDecoder := NewAuthIDDecoderHolder()\n\tvar keyw [16]byte\n\tcopy(keyw[:], key)\n\tAuthDecoder.AddUser(keyw, \"Demo User\")\n\tres, err := AuthDecoder.Match(authid)\n\tfmt.Println(res)\n\tfmt.Println(err)\n\tassert.Equal(t, \"Demo User\", res)\n\tassert.Nil(t, err)\n\n\tfor i := 0; i <= 1000000; i++ {\n\t\tkey2 := KDF16([]byte(\"Demo Key for Auth ID Test2\"), \"Demo Path for Auth ID Test\", strconv.Itoa(i))\n\t\tvar keyw2 [16]byte\n\t\tcopy(keyw2[:], key2)\n\t\tAuthDecoder.AddUser(keyw2, \"Demo User\"+strconv.Itoa(i))\n\t}\n\n\tauthid3 := CreateAuthID(key, time.Now().Unix())\n\n\tbefore := time.Now()\n\tres2, err2 := AuthDecoder.Match(authid3)\n\tafter := time.Now()\n\tassert.Equal(t, \"Demo User\", res2)\n\tassert.Nil(t, err2)\n\n\tfmt.Println(after.Sub(before).Seconds())\n\n}\n"
  },
  {
    "path": "proxy/vmess/aead/consts.go",
    "content": "package aead\n\nconst KDFSaltConst_AuthIDEncryptionKey = \"AES Auth ID Encryption\"\n\nconst KDFSaltConst_AEADRespHeaderLenKey = \"AEAD Resp Header Len Key\"\n\nconst KDFSaltConst_AEADRespHeaderLenIV = \"AEAD Resp Header Len IV\"\n\nconst KDFSaltConst_AEADRespHeaderPayloadKey = \"AEAD Resp Header Key\"\n\nconst KDFSaltConst_AEADRespHeaderPayloadIV = \"AEAD Resp Header IV\"\n\nconst KDFSaltConst_VMessAEADKDF = \"VMess AEAD KDF\"\n\nconst KDFSaltConst_VMessHeaderPayloadAEADKey = \"VMess Header AEAD Key\"\n\nconst KDFSaltConst_VMessHeaderPayloadAEADIV = \"VMess Header AEAD Nonce\"\n\nconst KDFSaltConst_VMessHeaderPayloadLengthAEADKey = \"VMess Header AEAD Key_Length\"\n\nconst KDFSaltConst_VMessHeaderPayloadLengthAEADIV = \"VMess Header AEAD Nonce_Length\"\n"
  },
  {
    "path": "proxy/vmess/aead/encrypt.go",
    "content": "package aead\n\nimport (\n\t\"bytes\"\n\t\"crypto/aes\"\n\t\"crypto/cipher\"\n\t\"crypto/rand\"\n\t\"encoding/binary\"\n\t\"io\"\n\t\"time\"\n\n\t\"v2ray.com/core/common\"\n)\n\nfunc SealVMessAEADHeader(key [16]byte, data []byte) []byte {\n\tgeneratedAuthID := CreateAuthID(key[:], time.Now().Unix())\n\n\tconnectionNonce := make([]byte, 8)\n\tif _, err := io.ReadFull(rand.Reader, connectionNonce); err != nil {\n\t\tpanic(err.Error())\n\t}\n\n\taeadPayloadLengthSerializeBuffer := bytes.NewBuffer(nil)\n\n\theaderPayloadDataLen := uint16(len(data))\n\n\tcommon.Must(binary.Write(aeadPayloadLengthSerializeBuffer, binary.BigEndian, headerPayloadDataLen))\n\n\taeadPayloadLengthSerializedByte := aeadPayloadLengthSerializeBuffer.Bytes()\n\tvar payloadHeaderLengthAEADEncrypted []byte\n\n\t{\n\t\tpayloadHeaderLengthAEADKey := KDF16(key[:], KDFSaltConst_VMessHeaderPayloadLengthAEADKey, string(generatedAuthID[:]), string(connectionNonce))\n\n\t\tpayloadHeaderLengthAEADNonce := KDF(key[:], KDFSaltConst_VMessHeaderPayloadLengthAEADIV, string(generatedAuthID[:]), string(connectionNonce))[:12]\n\n\t\tpayloadHeaderLengthAEADAESBlock, err := aes.NewCipher(payloadHeaderLengthAEADKey)\n\t\tif err != nil {\n\t\t\tpanic(err.Error())\n\t\t}\n\n\t\tpayloadHeaderAEAD, err := cipher.NewGCM(payloadHeaderLengthAEADAESBlock)\n\n\t\tif err != nil {\n\t\t\tpanic(err.Error())\n\t\t}\n\n\t\tpayloadHeaderLengthAEADEncrypted = payloadHeaderAEAD.Seal(nil, payloadHeaderLengthAEADNonce, aeadPayloadLengthSerializedByte, generatedAuthID[:])\n\t}\n\n\tvar payloadHeaderAEADEncrypted []byte\n\n\t{\n\t\tpayloadHeaderAEADKey := KDF16(key[:], KDFSaltConst_VMessHeaderPayloadAEADKey, string(generatedAuthID[:]), string(connectionNonce))\n\n\t\tpayloadHeaderAEADNonce := KDF(key[:], KDFSaltConst_VMessHeaderPayloadAEADIV, string(generatedAuthID[:]), string(connectionNonce))[:12]\n\n\t\tpayloadHeaderAEADAESBlock, err := aes.NewCipher(payloadHeaderAEADKey)\n\t\tif err != nil {\n\t\t\tpanic(err.Error())\n\t\t}\n\n\t\tpayloadHeaderAEAD, err := cipher.NewGCM(payloadHeaderAEADAESBlock)\n\n\t\tif err != nil {\n\t\t\tpanic(err.Error())\n\t\t}\n\n\t\tpayloadHeaderAEADEncrypted = payloadHeaderAEAD.Seal(nil, payloadHeaderAEADNonce, data, generatedAuthID[:])\n\t}\n\n\tvar outputBuffer = bytes.NewBuffer(nil)\n\n\tcommon.Must2(outputBuffer.Write(generatedAuthID[:])) //16\n\n\tcommon.Must2(outputBuffer.Write(payloadHeaderLengthAEADEncrypted)) //2+16\n\n\tcommon.Must2(outputBuffer.Write(connectionNonce)) //8\n\n\tcommon.Must2(outputBuffer.Write(payloadHeaderAEADEncrypted))\n\n\treturn outputBuffer.Bytes()\n}\n\nfunc OpenVMessAEADHeader(key [16]byte, authid [16]byte, data io.Reader) ([]byte, bool, error, int) {\n\tvar payloadHeaderLengthAEADEncrypted [18]byte\n\tvar nonce [8]byte\n\n\tvar bytesRead int\n\n\tauthidCheckValueReadBytesCounts, err := io.ReadFull(data, payloadHeaderLengthAEADEncrypted[:])\n\tbytesRead += authidCheckValueReadBytesCounts\n\tif err != nil {\n\t\treturn nil, false, err, bytesRead\n\t}\n\n\tnonceReadBytesCounts, err := io.ReadFull(data, nonce[:])\n\tbytesRead += nonceReadBytesCounts\n\tif err != nil {\n\t\treturn nil, false, err, bytesRead\n\t}\n\n\t//Decrypt Length\n\n\tvar decryptedAEADHeaderLengthPayloadResult []byte\n\n\t{\n\t\tpayloadHeaderLengthAEADKey := KDF16(key[:], KDFSaltConst_VMessHeaderPayloadLengthAEADKey, string(authid[:]), string(nonce[:]))\n\n\t\tpayloadHeaderLengthAEADNonce := KDF(key[:], KDFSaltConst_VMessHeaderPayloadLengthAEADIV, string(authid[:]), string(nonce[:]))[:12]\n\n\t\tpayloadHeaderAEADAESBlock, err := aes.NewCipher(payloadHeaderLengthAEADKey)\n\t\tif err != nil {\n\t\t\tpanic(err.Error())\n\t\t}\n\n\t\tpayloadHeaderLengthAEAD, err := cipher.NewGCM(payloadHeaderAEADAESBlock)\n\n\t\tif err != nil {\n\t\t\tpanic(err.Error())\n\t\t}\n\n\t\tdecryptedAEADHeaderLengthPayload, erropenAEAD := payloadHeaderLengthAEAD.Open(nil, payloadHeaderLengthAEADNonce, payloadHeaderLengthAEADEncrypted[:], authid[:])\n\n\t\tif erropenAEAD != nil {\n\t\t\treturn nil, true, erropenAEAD, bytesRead\n\t\t}\n\n\t\tdecryptedAEADHeaderLengthPayloadResult = decryptedAEADHeaderLengthPayload\n\t}\n\n\tvar length uint16\n\n\tcommon.Must(binary.Read(bytes.NewReader(decryptedAEADHeaderLengthPayloadResult[:]), binary.BigEndian, &length))\n\n\tvar decryptedAEADHeaderPayloadR []byte\n\n\tvar payloadHeaderAEADEncryptedReadedBytesCounts int\n\n\t{\n\t\tpayloadHeaderAEADKey := KDF16(key[:], KDFSaltConst_VMessHeaderPayloadAEADKey, string(authid[:]), string(nonce[:]))\n\n\t\tpayloadHeaderAEADNonce := KDF(key[:], KDFSaltConst_VMessHeaderPayloadAEADIV, string(authid[:]), string(nonce[:]))[:12]\n\n\t\t//16 == AEAD Tag size\n\t\tpayloadHeaderAEADEncrypted := make([]byte, length+16)\n\n\t\tpayloadHeaderAEADEncryptedReadedBytesCounts, err = io.ReadFull(data, payloadHeaderAEADEncrypted)\n\t\tbytesRead += payloadHeaderAEADEncryptedReadedBytesCounts\n\t\tif err != nil {\n\t\t\treturn nil, false, err, bytesRead\n\t\t}\n\n\t\tpayloadHeaderAEADAESBlock, err := aes.NewCipher(payloadHeaderAEADKey)\n\t\tif err != nil {\n\t\t\tpanic(err.Error())\n\t\t}\n\n\t\tpayloadHeaderAEAD, err := cipher.NewGCM(payloadHeaderAEADAESBlock)\n\n\t\tif err != nil {\n\t\t\tpanic(err.Error())\n\t\t}\n\n\t\tdecryptedAEADHeaderPayload, erropenAEAD := payloadHeaderAEAD.Open(nil, payloadHeaderAEADNonce, payloadHeaderAEADEncrypted, authid[:])\n\n\t\tif erropenAEAD != nil {\n\t\t\treturn nil, true, erropenAEAD, bytesRead\n\t\t}\n\n\t\tdecryptedAEADHeaderPayloadR = decryptedAEADHeaderPayload\n\t}\n\n\treturn decryptedAEADHeaderPayloadR, false, nil, bytesRead\n}\n"
  },
  {
    "path": "proxy/vmess/aead/encrypt_test.go",
    "content": "package aead\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestOpenVMessAEADHeader(t *testing.T) {\n\tTestHeader := []byte(\"Test Header\")\n\tkey := KDF16([]byte(\"Demo Key for Auth ID Test\"), \"Demo Path for Auth ID Test\")\n\tvar keyw [16]byte\n\tcopy(keyw[:], key)\n\tsealed := SealVMessAEADHeader(keyw, TestHeader)\n\n\tvar AEADR = bytes.NewReader(sealed)\n\n\tvar authid [16]byte\n\n\tio.ReadFull(AEADR, authid[:])\n\n\tout, _, err, _ := OpenVMessAEADHeader(keyw, authid, AEADR)\n\n\tfmt.Println(string(out))\n\tfmt.Println(err)\n}\n\nfunc TestOpenVMessAEADHeader2(t *testing.T) {\n\tTestHeader := []byte(\"Test Header\")\n\tkey := KDF16([]byte(\"Demo Key for Auth ID Test\"), \"Demo Path for Auth ID Test\")\n\tvar keyw [16]byte\n\tcopy(keyw[:], key)\n\tsealed := SealVMessAEADHeader(keyw, TestHeader)\n\n\tvar AEADR = bytes.NewReader(sealed)\n\n\tvar authid [16]byte\n\n\tio.ReadFull(AEADR, authid[:])\n\n\tout, _, err, readen := OpenVMessAEADHeader(keyw, authid, AEADR)\n\tassert.Equal(t, len(sealed)-16-AEADR.Len(), readen)\n\tassert.Equal(t, string(TestHeader), string(out))\n\tassert.Nil(t, err)\n}\n\nfunc TestOpenVMessAEADHeader4(t *testing.T) {\n\tfor i := 0; i <= 60; i++ {\n\t\tTestHeader := []byte(\"Test Header\")\n\t\tkey := KDF16([]byte(\"Demo Key for Auth ID Test\"), \"Demo Path for Auth ID Test\")\n\t\tvar keyw [16]byte\n\t\tcopy(keyw[:], key)\n\t\tsealed := SealVMessAEADHeader(keyw, TestHeader)\n\t\tvar sealedm [16]byte\n\t\tcopy(sealedm[:], sealed)\n\t\tsealed[i] ^= 0xff\n\t\tvar AEADR = bytes.NewReader(sealed)\n\n\t\tvar authid [16]byte\n\n\t\tio.ReadFull(AEADR, authid[:])\n\n\t\tout, drain, err, readen := OpenVMessAEADHeader(keyw, authid, AEADR)\n\t\tassert.Equal(t, len(sealed)-16-AEADR.Len(), readen)\n\t\tassert.Equal(t, true, drain)\n\t\tassert.NotNil(t, err)\n\t\tif err == nil {\n\t\t\tfmt.Println(\">\")\n\t\t}\n\t\tassert.Nil(t, out)\n\t}\n\n}\n\nfunc TestOpenVMessAEADHeader4Massive(t *testing.T) {\n\tfor j := 0; j < 1000; j++ {\n\n\t\tfor i := 0; i <= 60; i++ {\n\t\t\tTestHeader := []byte(\"Test Header\")\n\t\t\tkey := KDF16([]byte(\"Demo Key for Auth ID Test\"), \"Demo Path for Auth ID Test\")\n\t\t\tvar keyw [16]byte\n\t\t\tcopy(keyw[:], key)\n\t\t\tsealed := SealVMessAEADHeader(keyw, TestHeader)\n\t\t\tvar sealedm [16]byte\n\t\t\tcopy(sealedm[:], sealed)\n\t\t\tsealed[i] ^= 0xff\n\t\t\tvar AEADR = bytes.NewReader(sealed)\n\n\t\t\tvar authid [16]byte\n\n\t\t\tio.ReadFull(AEADR, authid[:])\n\n\t\t\tout, drain, err, readen := OpenVMessAEADHeader(keyw, authid, AEADR)\n\t\t\tassert.Equal(t, len(sealed)-16-AEADR.Len(), readen)\n\t\t\tassert.Equal(t, true, drain)\n\t\t\tassert.NotNil(t, err)\n\t\t\tif err == nil {\n\t\t\t\tfmt.Println(\">\")\n\t\t\t}\n\t\t\tassert.Nil(t, out)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "proxy/vmess/aead/kdf.go",
    "content": "package aead\n\nimport (\n\t\"crypto/hmac\"\n\t\"crypto/sha256\"\n\t\"hash\"\n)\n\nfunc KDF(key []byte, path ...string) []byte {\n\thmacf := hmac.New(func() hash.Hash {\n\t\treturn sha256.New()\n\t}, []byte(KDFSaltConst_VMessAEADKDF))\n\n\tfor _, v := range path {\n\t\thmacf = hmac.New(func() hash.Hash {\n\t\t\treturn hmacf\n\t\t}, []byte(v))\n\t}\n\thmacf.Write(key)\n\treturn hmacf.Sum(nil)\n}\n\nfunc KDF16(key []byte, path ...string) []byte {\n\tr := KDF(key, path...)\n\treturn r[:16]\n}\n"
  },
  {
    "path": "proxy/vmess/encoding/auth.go",
    "content": "package encoding\n\nimport (\n\t\"crypto/md5\"\n\t\"encoding/binary\"\n\t\"hash/fnv\"\n\n\t\"v2ray.com/core/common\"\n\n\t\"golang.org/x/crypto/sha3\"\n)\n\n// Authenticate authenticates a byte array using Fnv hash.\nfunc Authenticate(b []byte) uint32 {\n\tfnv1hash := fnv.New32a()\n\tcommon.Must2(fnv1hash.Write(b))\n\treturn fnv1hash.Sum32()\n}\n\ntype NoOpAuthenticator struct{}\n\nfunc (NoOpAuthenticator) NonceSize() int {\n\treturn 0\n}\n\nfunc (NoOpAuthenticator) Overhead() int {\n\treturn 0\n}\n\n// Seal implements AEAD.Seal().\nfunc (NoOpAuthenticator) Seal(dst, nonce, plaintext, additionalData []byte) []byte {\n\treturn append(dst[:0], plaintext...)\n}\n\n// Open implements AEAD.Open().\nfunc (NoOpAuthenticator) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {\n\treturn append(dst[:0], ciphertext...), nil\n}\n\n// FnvAuthenticator is an AEAD based on Fnv hash.\ntype FnvAuthenticator struct {\n}\n\n// NonceSize implements AEAD.NonceSize().\nfunc (*FnvAuthenticator) NonceSize() int {\n\treturn 0\n}\n\n// Overhead impelements AEAD.Overhead().\nfunc (*FnvAuthenticator) Overhead() int {\n\treturn 4\n}\n\n// Seal implements AEAD.Seal().\nfunc (*FnvAuthenticator) Seal(dst, nonce, plaintext, additionalData []byte) []byte {\n\tdst = append(dst, 0, 0, 0, 0)\n\tbinary.BigEndian.PutUint32(dst, Authenticate(plaintext))\n\treturn append(dst, plaintext...)\n}\n\n// Open implements AEAD.Open().\nfunc (*FnvAuthenticator) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {\n\tif binary.BigEndian.Uint32(ciphertext[:4]) != Authenticate(ciphertext[4:]) {\n\t\treturn dst, newError(\"invalid authentication\")\n\t}\n\treturn append(dst, ciphertext[4:]...), nil\n}\n\n// GenerateChacha20Poly1305Key generates a 32-byte key from a given 16-byte array.\nfunc GenerateChacha20Poly1305Key(b []byte) []byte {\n\tkey := make([]byte, 32)\n\tt := md5.Sum(b)\n\tcopy(key, t[:])\n\tt = md5.Sum(key[:16])\n\tcopy(key[16:], t[:])\n\treturn key\n}\n\ntype ShakeSizeParser struct {\n\tshake  sha3.ShakeHash\n\tbuffer [2]byte\n}\n\nfunc NewShakeSizeParser(nonce []byte) *ShakeSizeParser {\n\tshake := sha3.NewShake128()\n\tcommon.Must2(shake.Write(nonce))\n\treturn &ShakeSizeParser{\n\t\tshake: shake,\n\t}\n}\n\nfunc (*ShakeSizeParser) SizeBytes() int32 {\n\treturn 2\n}\n\nfunc (s *ShakeSizeParser) next() uint16 {\n\tcommon.Must2(s.shake.Read(s.buffer[:]))\n\treturn binary.BigEndian.Uint16(s.buffer[:])\n}\n\nfunc (s *ShakeSizeParser) Decode(b []byte) (uint16, error) {\n\tmask := s.next()\n\tsize := binary.BigEndian.Uint16(b)\n\treturn mask ^ size, nil\n}\n\nfunc (s *ShakeSizeParser) Encode(size uint16, b []byte) []byte {\n\tmask := s.next()\n\tbinary.BigEndian.PutUint16(b, mask^size)\n\treturn b[:2]\n}\n\nfunc (s *ShakeSizeParser) NextPaddingLen() uint16 {\n\treturn s.next() % 64\n}\n\nfunc (s *ShakeSizeParser) MaxPaddingLen() uint16 {\n\treturn 64\n}\n"
  },
  {
    "path": "proxy/vmess/encoding/auth_test.go",
    "content": "package encoding_test\n\nimport (\n\t\"crypto/rand\"\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\n\t\"v2ray.com/core/common\"\n\t. \"v2ray.com/core/proxy/vmess/encoding\"\n)\n\nfunc TestFnvAuth(t *testing.T) {\n\tfnvAuth := new(FnvAuthenticator)\n\n\texpectedText := make([]byte, 256)\n\t_, err := rand.Read(expectedText)\n\tcommon.Must(err)\n\n\tbuffer := make([]byte, 512)\n\tb := fnvAuth.Seal(buffer[:0], nil, expectedText, nil)\n\tb, err = fnvAuth.Open(buffer[:0], nil, b, nil)\n\tcommon.Must(err)\n\tif r := cmp.Diff(b, expectedText); r != \"\" {\n\t\tt.Error(r)\n\t}\n}\n"
  },
  {
    "path": "proxy/vmess/encoding/client.go",
    "content": "package encoding\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"crypto/aes\"\n\t\"crypto/cipher\"\n\t\"crypto/md5\"\n\t\"crypto/rand\"\n\t\"crypto/sha256\"\n\t\"encoding/binary\"\n\t\"hash\"\n\t\"hash/fnv\"\n\t\"io\"\n\n\t\"golang.org/x/crypto/chacha20poly1305\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/bitmask\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/crypto\"\n\t\"v2ray.com/core/common/dice\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/serial\"\n\t\"v2ray.com/core/proxy/vmess\"\n\tvmessaead \"v2ray.com/core/proxy/vmess/aead\"\n)\n\nfunc hashTimestamp(h hash.Hash, t protocol.Timestamp) []byte {\n\tcommon.Must2(serial.WriteUint64(h, uint64(t)))\n\tcommon.Must2(serial.WriteUint64(h, uint64(t)))\n\tcommon.Must2(serial.WriteUint64(h, uint64(t)))\n\tcommon.Must2(serial.WriteUint64(h, uint64(t)))\n\treturn h.Sum(nil)\n}\n\n// ClientSession stores connection session info for VMess client.\ntype ClientSession struct {\n\tisAEAD          bool\n\tidHash          protocol.IDHash\n\trequestBodyKey  [16]byte\n\trequestBodyIV   [16]byte\n\tresponseBodyKey [16]byte\n\tresponseBodyIV  [16]byte\n\tresponseReader  io.Reader\n\tresponseHeader  byte\n}\n\n// NewClientSession creates a new ClientSession.\nfunc NewClientSession(isAEAD bool, idHash protocol.IDHash, ctx context.Context) *ClientSession {\n\n\tsession := &ClientSession{\n\t\tisAEAD: isAEAD,\n\t\tidHash: idHash,\n\t}\n\n\trandomBytes := make([]byte, 33) // 16 + 16 + 1\n\tcommon.Must2(rand.Read(randomBytes))\n\tcopy(session.requestBodyKey[:], randomBytes[:16])\n\tcopy(session.requestBodyIV[:], randomBytes[16:32])\n\tsession.responseHeader = randomBytes[32]\n\n\tif !session.isAEAD {\n\t\tsession.responseBodyKey = md5.Sum(session.requestBodyKey[:])\n\t\tsession.responseBodyIV = md5.Sum(session.requestBodyIV[:])\n\t} else {\n\t\tBodyKey := sha256.Sum256(session.requestBodyKey[:])\n\t\tcopy(session.responseBodyKey[:], BodyKey[:16])\n\t\tBodyIV := sha256.Sum256(session.requestBodyIV[:])\n\t\tcopy(session.responseBodyIV[:], BodyIV[:16])\n\t}\n\n\treturn session\n}\n\nfunc (c *ClientSession) EncodeRequestHeader(header *protocol.RequestHeader, writer io.Writer) error {\n\ttimestamp := protocol.NewTimestampGenerator(protocol.NowTime(), 30)()\n\taccount := header.User.Account.(*vmess.MemoryAccount)\n\tif !c.isAEAD {\n\t\tidHash := c.idHash(account.AnyValidID().Bytes())\n\t\tcommon.Must2(serial.WriteUint64(idHash, uint64(timestamp)))\n\t\tcommon.Must2(writer.Write(idHash.Sum(nil)))\n\t}\n\n\tbuffer := buf.New()\n\tdefer buffer.Release()\n\n\tcommon.Must(buffer.WriteByte(Version))\n\tcommon.Must2(buffer.Write(c.requestBodyIV[:]))\n\tcommon.Must2(buffer.Write(c.requestBodyKey[:]))\n\tcommon.Must(buffer.WriteByte(c.responseHeader))\n\tcommon.Must(buffer.WriteByte(byte(header.Option)))\n\n\tpadingLen := dice.Roll(16)\n\tsecurity := byte(padingLen<<4) | byte(header.Security)\n\tcommon.Must2(buffer.Write([]byte{security, byte(0), byte(header.Command)}))\n\n\tif header.Command != protocol.RequestCommandMux {\n\t\tif err := addrParser.WriteAddressPort(buffer, header.Address, header.Port); err != nil {\n\t\t\treturn newError(\"failed to writer address and port\").Base(err)\n\t\t}\n\t}\n\n\tif padingLen > 0 {\n\t\tcommon.Must2(buffer.ReadFullFrom(rand.Reader, int32(padingLen)))\n\t}\n\n\t{\n\t\tfnv1a := fnv.New32a()\n\t\tcommon.Must2(fnv1a.Write(buffer.Bytes()))\n\t\thashBytes := buffer.Extend(int32(fnv1a.Size()))\n\t\tfnv1a.Sum(hashBytes[:0])\n\t}\n\n\tif !c.isAEAD {\n\t\tiv := hashTimestamp(md5.New(), timestamp)\n\t\taesStream := crypto.NewAesEncryptionStream(account.ID.CmdKey(), iv[:])\n\t\taesStream.XORKeyStream(buffer.Bytes(), buffer.Bytes())\n\t\tcommon.Must2(writer.Write(buffer.Bytes()))\n\t} else {\n\t\tvar fixedLengthCmdKey [16]byte\n\t\tcopy(fixedLengthCmdKey[:], account.ID.CmdKey())\n\t\tvmessout := vmessaead.SealVMessAEADHeader(fixedLengthCmdKey, buffer.Bytes())\n\t\tcommon.Must2(io.Copy(writer, bytes.NewReader(vmessout)))\n\t}\n\n\treturn nil\n}\n\nfunc (c *ClientSession) EncodeRequestBody(request *protocol.RequestHeader, writer io.Writer) buf.Writer {\n\tvar sizeParser crypto.ChunkSizeEncoder = crypto.PlainChunkSizeParser{}\n\tif request.Option.Has(protocol.RequestOptionChunkMasking) {\n\t\tsizeParser = NewShakeSizeParser(c.requestBodyIV[:])\n\t}\n\tvar padding crypto.PaddingLengthGenerator\n\tif request.Option.Has(protocol.RequestOptionGlobalPadding) {\n\t\tpadding = sizeParser.(crypto.PaddingLengthGenerator)\n\t}\n\n\tswitch request.Security {\n\tcase protocol.SecurityType_NONE:\n\t\tif request.Option.Has(protocol.RequestOptionChunkStream) {\n\t\t\tif request.Command.TransferType() == protocol.TransferTypeStream {\n\t\t\t\treturn crypto.NewChunkStreamWriter(sizeParser, writer)\n\t\t\t}\n\t\t\tauth := &crypto.AEADAuthenticator{\n\t\t\t\tAEAD:                    new(NoOpAuthenticator),\n\t\t\t\tNonceGenerator:          crypto.GenerateEmptyBytes(),\n\t\t\t\tAdditionalDataGenerator: crypto.GenerateEmptyBytes(),\n\t\t\t}\n\t\t\treturn crypto.NewAuthenticationWriter(auth, sizeParser, writer, protocol.TransferTypePacket, padding)\n\t\t}\n\n\t\treturn buf.NewWriter(writer)\n\tcase protocol.SecurityType_LEGACY:\n\t\taesStream := crypto.NewAesEncryptionStream(c.requestBodyKey[:], c.requestBodyIV[:])\n\t\tcryptionWriter := crypto.NewCryptionWriter(aesStream, writer)\n\t\tif request.Option.Has(protocol.RequestOptionChunkStream) {\n\t\t\tauth := &crypto.AEADAuthenticator{\n\t\t\t\tAEAD:                    new(FnvAuthenticator),\n\t\t\t\tNonceGenerator:          crypto.GenerateEmptyBytes(),\n\t\t\t\tAdditionalDataGenerator: crypto.GenerateEmptyBytes(),\n\t\t\t}\n\t\t\treturn crypto.NewAuthenticationWriter(auth, sizeParser, cryptionWriter, request.Command.TransferType(), padding)\n\t\t}\n\n\t\treturn &buf.SequentialWriter{Writer: cryptionWriter}\n\tcase protocol.SecurityType_AES128_GCM:\n\t\taead := crypto.NewAesGcm(c.requestBodyKey[:])\n\t\tauth := &crypto.AEADAuthenticator{\n\t\t\tAEAD:                    aead,\n\t\t\tNonceGenerator:          GenerateChunkNonce(c.requestBodyIV[:], uint32(aead.NonceSize())),\n\t\t\tAdditionalDataGenerator: crypto.GenerateEmptyBytes(),\n\t\t}\n\t\treturn crypto.NewAuthenticationWriter(auth, sizeParser, writer, request.Command.TransferType(), padding)\n\tcase protocol.SecurityType_CHACHA20_POLY1305:\n\t\taead, err := chacha20poly1305.New(GenerateChacha20Poly1305Key(c.requestBodyKey[:]))\n\t\tcommon.Must(err)\n\n\t\tauth := &crypto.AEADAuthenticator{\n\t\t\tAEAD:                    aead,\n\t\t\tNonceGenerator:          GenerateChunkNonce(c.requestBodyIV[:], uint32(aead.NonceSize())),\n\t\t\tAdditionalDataGenerator: crypto.GenerateEmptyBytes(),\n\t\t}\n\t\treturn crypto.NewAuthenticationWriter(auth, sizeParser, writer, request.Command.TransferType(), padding)\n\tdefault:\n\t\tpanic(\"Unknown security type.\")\n\t}\n}\n\nfunc (c *ClientSession) DecodeResponseHeader(reader io.Reader) (*protocol.ResponseHeader, error) {\n\tif !c.isAEAD {\n\t\taesStream := crypto.NewAesDecryptionStream(c.responseBodyKey[:], c.responseBodyIV[:])\n\t\tc.responseReader = crypto.NewCryptionReader(aesStream, reader)\n\t} else {\n\t\taeadResponseHeaderLengthEncryptionKey := vmessaead.KDF16(c.responseBodyKey[:], vmessaead.KDFSaltConst_AEADRespHeaderLenKey)\n\t\taeadResponseHeaderLengthEncryptionIV := vmessaead.KDF(c.responseBodyIV[:], vmessaead.KDFSaltConst_AEADRespHeaderLenIV)[:12]\n\n\t\taeadResponseHeaderLengthEncryptionKeyAESBlock := common.Must2(aes.NewCipher(aeadResponseHeaderLengthEncryptionKey)).(cipher.Block)\n\t\taeadResponseHeaderLengthEncryptionAEAD := common.Must2(cipher.NewGCM(aeadResponseHeaderLengthEncryptionKeyAESBlock)).(cipher.AEAD)\n\n\t\tvar aeadEncryptedResponseHeaderLength [18]byte\n\t\tvar decryptedResponseHeaderLength int\n\t\tvar decryptedResponseHeaderLengthBinaryDeserializeBuffer uint16\n\n\t\tif _, err := io.ReadFull(reader, aeadEncryptedResponseHeaderLength[:]); err != nil {\n\t\t\treturn nil, newError(\"Unable to Read Header Len\").Base(err)\n\t\t}\n\t\tif decryptedResponseHeaderLengthBinaryBuffer, err := aeadResponseHeaderLengthEncryptionAEAD.Open(nil, aeadResponseHeaderLengthEncryptionIV, aeadEncryptedResponseHeaderLength[:], nil); err != nil {\n\t\t\treturn nil, newError(\"Failed To Decrypt Length\").Base(err)\n\t\t} else {\n\t\t\tcommon.Must(binary.Read(bytes.NewReader(decryptedResponseHeaderLengthBinaryBuffer), binary.BigEndian, &decryptedResponseHeaderLengthBinaryDeserializeBuffer))\n\t\t\tdecryptedResponseHeaderLength = int(decryptedResponseHeaderLengthBinaryDeserializeBuffer)\n\t\t}\n\n\t\taeadResponseHeaderPayloadEncryptionKey := vmessaead.KDF16(c.responseBodyKey[:], vmessaead.KDFSaltConst_AEADRespHeaderPayloadKey)\n\t\taeadResponseHeaderPayloadEncryptionIV := vmessaead.KDF(c.responseBodyIV[:], vmessaead.KDFSaltConst_AEADRespHeaderPayloadIV)[:12]\n\n\t\taeadResponseHeaderPayloadEncryptionKeyAESBlock := common.Must2(aes.NewCipher(aeadResponseHeaderPayloadEncryptionKey)).(cipher.Block)\n\t\taeadResponseHeaderPayloadEncryptionAEAD := common.Must2(cipher.NewGCM(aeadResponseHeaderPayloadEncryptionKeyAESBlock)).(cipher.AEAD)\n\n\t\tencryptedResponseHeaderBuffer := make([]byte, decryptedResponseHeaderLength+16)\n\n\t\tif _, err := io.ReadFull(reader, encryptedResponseHeaderBuffer); err != nil {\n\t\t\treturn nil, newError(\"Unable to Read Header Data\").Base(err)\n\t\t}\n\n\t\tif decryptedResponseHeaderBuffer, err := aeadResponseHeaderPayloadEncryptionAEAD.Open(nil, aeadResponseHeaderPayloadEncryptionIV, encryptedResponseHeaderBuffer, nil); err != nil {\n\t\t\treturn nil, newError(\"Failed To Decrypt Payload\").Base(err)\n\t\t} else {\n\t\t\tc.responseReader = bytes.NewReader(decryptedResponseHeaderBuffer)\n\t\t}\n\t}\n\n\tbuffer := buf.StackNew()\n\tdefer buffer.Release()\n\n\tif _, err := buffer.ReadFullFrom(c.responseReader, 4); err != nil {\n\t\treturn nil, newError(\"failed to read response header\").Base(err).AtWarning()\n\t}\n\n\tif buffer.Byte(0) != c.responseHeader {\n\t\treturn nil, newError(\"unexpected response header. Expecting \", int(c.responseHeader), \" but actually \", int(buffer.Byte(0)))\n\t}\n\n\theader := &protocol.ResponseHeader{\n\t\tOption: bitmask.Byte(buffer.Byte(1)),\n\t}\n\n\tif buffer.Byte(2) != 0 {\n\t\tcmdID := buffer.Byte(2)\n\t\tdataLen := int32(buffer.Byte(3))\n\n\t\tbuffer.Clear()\n\t\tif _, err := buffer.ReadFullFrom(c.responseReader, dataLen); err != nil {\n\t\t\treturn nil, newError(\"failed to read response command\").Base(err)\n\t\t}\n\t\tcommand, err := UnmarshalCommand(cmdID, buffer.Bytes())\n\t\tif err == nil {\n\t\t\theader.Command = command\n\t\t}\n\t}\n\tif c.isAEAD {\n\t\taesStream := crypto.NewAesDecryptionStream(c.responseBodyKey[:], c.responseBodyIV[:])\n\t\tc.responseReader = crypto.NewCryptionReader(aesStream, reader)\n\t}\n\treturn header, nil\n}\n\nfunc (c *ClientSession) DecodeResponseBody(request *protocol.RequestHeader, reader io.Reader) buf.Reader {\n\tvar sizeParser crypto.ChunkSizeDecoder = crypto.PlainChunkSizeParser{}\n\tif request.Option.Has(protocol.RequestOptionChunkMasking) {\n\t\tsizeParser = NewShakeSizeParser(c.responseBodyIV[:])\n\t}\n\tvar padding crypto.PaddingLengthGenerator\n\tif request.Option.Has(protocol.RequestOptionGlobalPadding) {\n\t\tpadding = sizeParser.(crypto.PaddingLengthGenerator)\n\t}\n\n\tswitch request.Security {\n\tcase protocol.SecurityType_NONE:\n\t\tif request.Option.Has(protocol.RequestOptionChunkStream) {\n\t\t\tif request.Command.TransferType() == protocol.TransferTypeStream {\n\t\t\t\treturn crypto.NewChunkStreamReader(sizeParser, reader)\n\t\t\t}\n\n\t\t\tauth := &crypto.AEADAuthenticator{\n\t\t\t\tAEAD:                    new(NoOpAuthenticator),\n\t\t\t\tNonceGenerator:          crypto.GenerateEmptyBytes(),\n\t\t\t\tAdditionalDataGenerator: crypto.GenerateEmptyBytes(),\n\t\t\t}\n\n\t\t\treturn crypto.NewAuthenticationReader(auth, sizeParser, reader, protocol.TransferTypePacket, padding)\n\t\t}\n\n\t\treturn buf.NewReader(reader)\n\tcase protocol.SecurityType_LEGACY:\n\t\tif request.Option.Has(protocol.RequestOptionChunkStream) {\n\t\t\tauth := &crypto.AEADAuthenticator{\n\t\t\t\tAEAD:                    new(FnvAuthenticator),\n\t\t\t\tNonceGenerator:          crypto.GenerateEmptyBytes(),\n\t\t\t\tAdditionalDataGenerator: crypto.GenerateEmptyBytes(),\n\t\t\t}\n\t\t\treturn crypto.NewAuthenticationReader(auth, sizeParser, c.responseReader, request.Command.TransferType(), padding)\n\t\t}\n\n\t\treturn buf.NewReader(c.responseReader)\n\tcase protocol.SecurityType_AES128_GCM:\n\t\taead := crypto.NewAesGcm(c.responseBodyKey[:])\n\n\t\tauth := &crypto.AEADAuthenticator{\n\t\t\tAEAD:                    aead,\n\t\t\tNonceGenerator:          GenerateChunkNonce(c.responseBodyIV[:], uint32(aead.NonceSize())),\n\t\t\tAdditionalDataGenerator: crypto.GenerateEmptyBytes(),\n\t\t}\n\t\treturn crypto.NewAuthenticationReader(auth, sizeParser, reader, request.Command.TransferType(), padding)\n\tcase protocol.SecurityType_CHACHA20_POLY1305:\n\t\taead, _ := chacha20poly1305.New(GenerateChacha20Poly1305Key(c.responseBodyKey[:]))\n\n\t\tauth := &crypto.AEADAuthenticator{\n\t\t\tAEAD:                    aead,\n\t\t\tNonceGenerator:          GenerateChunkNonce(c.responseBodyIV[:], uint32(aead.NonceSize())),\n\t\t\tAdditionalDataGenerator: crypto.GenerateEmptyBytes(),\n\t\t}\n\t\treturn crypto.NewAuthenticationReader(auth, sizeParser, reader, request.Command.TransferType(), padding)\n\tdefault:\n\t\tpanic(\"Unknown security type.\")\n\t}\n}\n\nfunc GenerateChunkNonce(nonce []byte, size uint32) crypto.BytesGenerator {\n\tc := append([]byte(nil), nonce...)\n\tcount := uint16(0)\n\treturn func() []byte {\n\t\tbinary.BigEndian.PutUint16(c, count)\n\t\tcount++\n\t\treturn c[:size]\n\t}\n}\n"
  },
  {
    "path": "proxy/vmess/encoding/commands.go",
    "content": "package encoding\n\nimport (\n\t\"encoding/binary\"\n\t\"io\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/serial\"\n\t\"v2ray.com/core/common/uuid\"\n)\n\nvar (\n\tErrCommandTypeMismatch = newError(\"Command type mismatch.\")\n\tErrUnknownCommand      = newError(\"Unknown command.\")\n\tErrCommandTooLarge     = newError(\"Command too large.\")\n)\n\nfunc MarshalCommand(command interface{}, writer io.Writer) error {\n\tif command == nil {\n\t\treturn ErrUnknownCommand\n\t}\n\n\tvar cmdID byte\n\tvar factory CommandFactory\n\tswitch command.(type) {\n\tcase *protocol.CommandSwitchAccount:\n\t\tfactory = new(CommandSwitchAccountFactory)\n\t\tcmdID = 1\n\tdefault:\n\t\treturn ErrUnknownCommand\n\t}\n\n\tbuffer := buf.New()\n\tdefer buffer.Release()\n\n\terr := factory.Marshal(command, buffer)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tauth := Authenticate(buffer.Bytes())\n\tlength := buffer.Len() + 4\n\tif length > 255 {\n\t\treturn ErrCommandTooLarge\n\t}\n\n\tcommon.Must2(writer.Write([]byte{cmdID, byte(length), byte(auth >> 24), byte(auth >> 16), byte(auth >> 8), byte(auth)}))\n\tcommon.Must2(writer.Write(buffer.Bytes()))\n\treturn nil\n}\n\nfunc UnmarshalCommand(cmdID byte, data []byte) (protocol.ResponseCommand, error) {\n\tif len(data) <= 4 {\n\t\treturn nil, newError(\"insufficient length\")\n\t}\n\texpectedAuth := Authenticate(data[4:])\n\tactualAuth := binary.BigEndian.Uint32(data[:4])\n\tif expectedAuth != actualAuth {\n\t\treturn nil, newError(\"invalid auth\")\n\t}\n\n\tvar factory CommandFactory\n\tswitch cmdID {\n\tcase 1:\n\t\tfactory = new(CommandSwitchAccountFactory)\n\tdefault:\n\t\treturn nil, ErrUnknownCommand\n\t}\n\treturn factory.Unmarshal(data[4:])\n}\n\ntype CommandFactory interface {\n\tMarshal(command interface{}, writer io.Writer) error\n\tUnmarshal(data []byte) (interface{}, error)\n}\n\ntype CommandSwitchAccountFactory struct {\n}\n\nfunc (f *CommandSwitchAccountFactory) Marshal(command interface{}, writer io.Writer) error {\n\tcmd, ok := command.(*protocol.CommandSwitchAccount)\n\tif !ok {\n\t\treturn ErrCommandTypeMismatch\n\t}\n\n\thostStr := \"\"\n\tif cmd.Host != nil {\n\t\thostStr = cmd.Host.String()\n\t}\n\tcommon.Must2(writer.Write([]byte{byte(len(hostStr))}))\n\n\tif len(hostStr) > 0 {\n\t\tcommon.Must2(writer.Write([]byte(hostStr)))\n\t}\n\n\tcommon.Must2(serial.WriteUint16(writer, cmd.Port.Value()))\n\n\tidBytes := cmd.ID.Bytes()\n\tcommon.Must2(writer.Write(idBytes))\n\tcommon.Must2(serial.WriteUint16(writer, cmd.AlterIds))\n\tcommon.Must2(writer.Write([]byte{byte(cmd.Level)}))\n\n\tcommon.Must2(writer.Write([]byte{cmd.ValidMin}))\n\treturn nil\n}\n\nfunc (f *CommandSwitchAccountFactory) Unmarshal(data []byte) (interface{}, error) {\n\tcmd := new(protocol.CommandSwitchAccount)\n\tif len(data) == 0 {\n\t\treturn nil, newError(\"insufficient length.\")\n\t}\n\tlenHost := int(data[0])\n\tif len(data) < lenHost+1 {\n\t\treturn nil, newError(\"insufficient length.\")\n\t}\n\tif lenHost > 0 {\n\t\tcmd.Host = net.ParseAddress(string(data[1 : 1+lenHost]))\n\t}\n\tportStart := 1 + lenHost\n\tif len(data) < portStart+2 {\n\t\treturn nil, newError(\"insufficient length.\")\n\t}\n\tcmd.Port = net.PortFromBytes(data[portStart : portStart+2])\n\tidStart := portStart + 2\n\tif len(data) < idStart+16 {\n\t\treturn nil, newError(\"insufficient length.\")\n\t}\n\tcmd.ID, _ = uuid.ParseBytes(data[idStart : idStart+16])\n\talterIDStart := idStart + 16\n\tif len(data) < alterIDStart+2 {\n\t\treturn nil, newError(\"insufficient length.\")\n\t}\n\tcmd.AlterIds = binary.BigEndian.Uint16(data[alterIDStart : alterIDStart+2])\n\tlevelStart := alterIDStart + 2\n\tif len(data) < levelStart+1 {\n\t\treturn nil, newError(\"insufficient length.\")\n\t}\n\tcmd.Level = uint32(data[levelStart])\n\ttimeStart := levelStart + 1\n\tif len(data) < timeStart {\n\t\treturn nil, newError(\"insufficient length.\")\n\t}\n\tcmd.ValidMin = data[timeStart]\n\treturn cmd, nil\n}\n"
  },
  {
    "path": "proxy/vmess/encoding/commands_test.go",
    "content": "package encoding_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/uuid\"\n\t. \"v2ray.com/core/proxy/vmess/encoding\"\n)\n\nfunc TestSwitchAccount(t *testing.T) {\n\tsa := &protocol.CommandSwitchAccount{\n\t\tPort:     1234,\n\t\tID:       uuid.New(),\n\t\tAlterIds: 1024,\n\t\tLevel:    128,\n\t\tValidMin: 16,\n\t}\n\n\tbuffer := buf.New()\n\tcommon.Must(MarshalCommand(sa, buffer))\n\n\tcmd, err := UnmarshalCommand(1, buffer.BytesFrom(2))\n\tcommon.Must(err)\n\n\tsa2, ok := cmd.(*protocol.CommandSwitchAccount)\n\tif !ok {\n\t\tt.Fatal(\"failed to convert command to CommandSwitchAccount\")\n\t}\n\tif r := cmp.Diff(sa2, sa); r != \"\" {\n\t\tt.Error(r)\n\t}\n}\n"
  },
  {
    "path": "proxy/vmess/encoding/encoding.go",
    "content": "package encoding\n\nimport (\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n)\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n\nconst (\n\tVersion = byte(1)\n)\n\nvar addrParser = protocol.NewAddressParser(\n\tprotocol.AddressFamilyByte(byte(protocol.AddressTypeIPv4), net.AddressFamilyIPv4),\n\tprotocol.AddressFamilyByte(byte(protocol.AddressTypeDomain), net.AddressFamilyDomain),\n\tprotocol.AddressFamilyByte(byte(protocol.AddressTypeIPv6), net.AddressFamilyIPv6),\n\tprotocol.PortThenAddress(),\n)\n"
  },
  {
    "path": "proxy/vmess/encoding/encoding_test.go",
    "content": "package encoding_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/uuid\"\n\t\"v2ray.com/core/proxy/vmess\"\n\t. \"v2ray.com/core/proxy/vmess/encoding\"\n)\n\nfunc toAccount(a *vmess.Account) protocol.Account {\n\taccount, err := a.AsAccount()\n\tcommon.Must(err)\n\treturn account\n}\n\nfunc TestRequestSerialization(t *testing.T) {\n\tuser := &protocol.MemoryUser{\n\t\tLevel: 0,\n\t\tEmail: \"test@v2ray.com\",\n\t}\n\tid := uuid.New()\n\taccount := &vmess.Account{\n\t\tId:      id.String(),\n\t\tAlterId: 0,\n\t}\n\tuser.Account = toAccount(account)\n\n\texpectedRequest := &protocol.RequestHeader{\n\t\tVersion:  1,\n\t\tUser:     user,\n\t\tCommand:  protocol.RequestCommandTCP,\n\t\tAddress:  net.DomainAddress(\"www.v2ray.com\"),\n\t\tPort:     net.Port(443),\n\t\tSecurity: protocol.SecurityType_AES128_GCM,\n\t}\n\n\tbuffer := buf.New()\n\tclient := NewClientSession(true, protocol.DefaultIDHash, context.TODO())\n\tcommon.Must(client.EncodeRequestHeader(expectedRequest, buffer))\n\n\tbuffer2 := buf.New()\n\tbuffer2.Write(buffer.Bytes())\n\n\tsessionHistory := NewSessionHistory()\n\tdefer common.Close(sessionHistory)\n\n\tuserValidator := vmess.NewTimedUserValidator(protocol.DefaultIDHash)\n\tuserValidator.Add(user)\n\tdefer common.Close(userValidator)\n\n\tserver := NewServerSession(userValidator, sessionHistory)\n\tactualRequest, err := server.DecodeRequestHeader(buffer)\n\tcommon.Must(err)\n\n\tif r := cmp.Diff(actualRequest, expectedRequest, cmp.AllowUnexported(protocol.ID{})); r != \"\" {\n\t\tt.Error(r)\n\t}\n\n\t_, err = server.DecodeRequestHeader(buffer2)\n\t// anti replay attack\n\tif err == nil {\n\t\tt.Error(\"nil error\")\n\t}\n}\n\nfunc TestInvalidRequest(t *testing.T) {\n\tuser := &protocol.MemoryUser{\n\t\tLevel: 0,\n\t\tEmail: \"test@v2ray.com\",\n\t}\n\tid := uuid.New()\n\taccount := &vmess.Account{\n\t\tId:      id.String(),\n\t\tAlterId: 0,\n\t}\n\tuser.Account = toAccount(account)\n\n\texpectedRequest := &protocol.RequestHeader{\n\t\tVersion:  1,\n\t\tUser:     user,\n\t\tCommand:  protocol.RequestCommand(100),\n\t\tAddress:  net.DomainAddress(\"www.v2ray.com\"),\n\t\tPort:     net.Port(443),\n\t\tSecurity: protocol.SecurityType_AES128_GCM,\n\t}\n\n\tbuffer := buf.New()\n\tclient := NewClientSession(true, protocol.DefaultIDHash, context.TODO())\n\tcommon.Must(client.EncodeRequestHeader(expectedRequest, buffer))\n\n\tbuffer2 := buf.New()\n\tbuffer2.Write(buffer.Bytes())\n\n\tsessionHistory := NewSessionHistory()\n\tdefer common.Close(sessionHistory)\n\n\tuserValidator := vmess.NewTimedUserValidator(protocol.DefaultIDHash)\n\tuserValidator.Add(user)\n\tdefer common.Close(userValidator)\n\n\tserver := NewServerSession(userValidator, sessionHistory)\n\t_, err := server.DecodeRequestHeader(buffer)\n\tif err == nil {\n\t\tt.Error(\"nil error\")\n\t}\n}\n\nfunc TestMuxRequest(t *testing.T) {\n\tuser := &protocol.MemoryUser{\n\t\tLevel: 0,\n\t\tEmail: \"test@v2ray.com\",\n\t}\n\tid := uuid.New()\n\taccount := &vmess.Account{\n\t\tId:      id.String(),\n\t\tAlterId: 0,\n\t}\n\tuser.Account = toAccount(account)\n\n\texpectedRequest := &protocol.RequestHeader{\n\t\tVersion:  1,\n\t\tUser:     user,\n\t\tCommand:  protocol.RequestCommandMux,\n\t\tSecurity: protocol.SecurityType_AES128_GCM,\n\t\tAddress:  net.DomainAddress(\"v1.mux.cool\"),\n\t}\n\n\tbuffer := buf.New()\n\tclient := NewClientSession(true, protocol.DefaultIDHash, context.TODO())\n\tcommon.Must(client.EncodeRequestHeader(expectedRequest, buffer))\n\n\tbuffer2 := buf.New()\n\tbuffer2.Write(buffer.Bytes())\n\n\tsessionHistory := NewSessionHistory()\n\tdefer common.Close(sessionHistory)\n\n\tuserValidator := vmess.NewTimedUserValidator(protocol.DefaultIDHash)\n\tuserValidator.Add(user)\n\tdefer common.Close(userValidator)\n\n\tserver := NewServerSession(userValidator, sessionHistory)\n\tactualRequest, err := server.DecodeRequestHeader(buffer)\n\tcommon.Must(err)\n\n\tif r := cmp.Diff(actualRequest, expectedRequest, cmp.AllowUnexported(protocol.ID{})); r != \"\" {\n\t\tt.Error(r)\n\t}\n}\n"
  },
  {
    "path": "proxy/vmess/encoding/errors.generated.go",
    "content": "package encoding\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "proxy/vmess/encoding/server.go",
    "content": "package encoding\n\nimport (\n\t\"bytes\"\n\t\"crypto/aes\"\n\t\"crypto/cipher\"\n\t\"crypto/md5\"\n\t\"crypto/sha256\"\n\t\"encoding/binary\"\n\t\"hash/fnv\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"sync\"\n\t\"time\"\n\n\t\"golang.org/x/crypto/chacha20poly1305\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/bitmask\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/crypto\"\n\t\"v2ray.com/core/common/dice\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/task\"\n\t\"v2ray.com/core/proxy/vmess\"\n\tvmessaead \"v2ray.com/core/proxy/vmess/aead\"\n)\n\ntype sessionId struct {\n\tuser  [16]byte\n\tkey   [16]byte\n\tnonce [16]byte\n}\n\n// SessionHistory keeps track of historical session ids, to prevent replay attacks.\ntype SessionHistory struct {\n\tsync.RWMutex\n\tcache map[sessionId]time.Time\n\ttask  *task.Periodic\n}\n\n// NewSessionHistory creates a new SessionHistory object.\nfunc NewSessionHistory() *SessionHistory {\n\th := &SessionHistory{\n\t\tcache: make(map[sessionId]time.Time, 128),\n\t}\n\th.task = &task.Periodic{\n\t\tInterval: time.Second * 30,\n\t\tExecute:  h.removeExpiredEntries,\n\t}\n\treturn h\n}\n\n// Close implements common.Closable.\nfunc (h *SessionHistory) Close() error {\n\treturn h.task.Close()\n}\n\nfunc (h *SessionHistory) addIfNotExits(session sessionId) bool {\n\th.Lock()\n\n\tif expire, found := h.cache[session]; found && expire.After(time.Now()) {\n\t\th.Unlock()\n\t\treturn false\n\t}\n\n\th.cache[session] = time.Now().Add(time.Minute * 3)\n\th.Unlock()\n\tcommon.Must(h.task.Start())\n\treturn true\n}\n\nfunc (h *SessionHistory) removeExpiredEntries() error {\n\tnow := time.Now()\n\n\th.Lock()\n\tdefer h.Unlock()\n\n\tif len(h.cache) == 0 {\n\t\treturn newError(\"nothing to do\")\n\t}\n\n\tfor session, expire := range h.cache {\n\t\tif expire.Before(now) {\n\t\t\tdelete(h.cache, session)\n\t\t}\n\t}\n\n\tif len(h.cache) == 0 {\n\t\th.cache = make(map[sessionId]time.Time, 128)\n\t}\n\n\treturn nil\n}\n\n// ServerSession keeps information for a session in VMess server.\ntype ServerSession struct {\n\tuserValidator   *vmess.TimedUserValidator\n\tsessionHistory  *SessionHistory\n\trequestBodyKey  [16]byte\n\trequestBodyIV   [16]byte\n\tresponseBodyKey [16]byte\n\tresponseBodyIV  [16]byte\n\tresponseWriter  io.Writer\n\tresponseHeader  byte\n\n\tisAEADRequest bool\n\n\tisAEADForced bool\n}\n\n// NewServerSession creates a new ServerSession, using the given UserValidator.\n// The ServerSession instance doesn't take ownership of the validator.\nfunc NewServerSession(validator *vmess.TimedUserValidator, sessionHistory *SessionHistory) *ServerSession {\n\treturn &ServerSession{\n\t\tuserValidator:  validator,\n\t\tsessionHistory: sessionHistory,\n\t}\n}\n\nfunc parseSecurityType(b byte) protocol.SecurityType {\n\tif _, f := protocol.SecurityType_name[int32(b)]; f {\n\t\tst := protocol.SecurityType(b)\n\t\t// For backward compatibility.\n\t\tif st == protocol.SecurityType_UNKNOWN {\n\t\t\tst = protocol.SecurityType_LEGACY\n\t\t}\n\t\treturn st\n\t}\n\treturn protocol.SecurityType_UNKNOWN\n}\n\n// DecodeRequestHeader decodes and returns (if successful) a RequestHeader from an input stream.\nfunc (s *ServerSession) DecodeRequestHeader(reader io.Reader) (*protocol.RequestHeader, error) {\n\tbuffer := buf.New()\n\tbehaviorRand := dice.NewDeterministicDice(int64(s.userValidator.GetBehaviorSeed()))\n\tBaseDrainSize := behaviorRand.Roll(3266)\n\tRandDrainMax := behaviorRand.Roll(64) + 1\n\tRandDrainRolled := dice.Roll(RandDrainMax)\n\tDrainSize := BaseDrainSize + 16 + 38 + RandDrainRolled\n\treadSizeRemain := DrainSize\n\n\tdrainConnection := func(e error) error {\n\t\t//We read a deterministic generated length of data before closing the connection to offset padding read pattern\n\t\treadSizeRemain -= int(buffer.Len())\n\t\tif readSizeRemain > 0 {\n\t\t\terr := s.DrainConnN(reader, readSizeRemain)\n\t\t\tif err != nil {\n\t\t\t\treturn newError(\"failed to drain connection DrainSize = \", BaseDrainSize, \" \", RandDrainMax, \" \", RandDrainRolled).Base(err).Base(e)\n\t\t\t}\n\t\t\treturn newError(\"connection drained DrainSize = \", BaseDrainSize, \" \", RandDrainMax, \" \", RandDrainRolled).Base(e)\n\t\t}\n\t\treturn e\n\t}\n\n\tdefer func() {\n\t\tbuffer.Release()\n\t}()\n\n\tif _, err := buffer.ReadFullFrom(reader, protocol.IDBytesLen); err != nil {\n\t\treturn nil, newError(\"failed to read request header\").Base(err)\n\t}\n\n\tvar decryptor io.Reader\n\tvar vmessAccount *vmess.MemoryAccount\n\n\tuser, foundAEAD, errorAEAD := s.userValidator.GetAEAD(buffer.Bytes())\n\n\tvar fixedSizeAuthID [16]byte\n\tcopy(fixedSizeAuthID[:], buffer.Bytes())\n\n\tif foundAEAD {\n\t\tvmessAccount = user.Account.(*vmess.MemoryAccount)\n\t\tvar fixedSizeCmdKey [16]byte\n\t\tcopy(fixedSizeCmdKey[:], vmessAccount.ID.CmdKey())\n\t\taeadData, shouldDrain, errorReason, bytesRead := vmessaead.OpenVMessAEADHeader(fixedSizeCmdKey, fixedSizeAuthID, reader)\n\t\tif errorReason != nil {\n\t\t\tif shouldDrain {\n\t\t\t\treadSizeRemain -= bytesRead\n\t\t\t\treturn nil, drainConnection(newError(\"AEAD read failed\").Base(errorReason))\n\t\t\t} else {\n\t\t\t\treturn nil, drainConnection(newError(\"AEAD read failed, drain skiped\").Base(errorReason))\n\t\t\t}\n\t\t}\n\t\tdecryptor = bytes.NewReader(aeadData)\n\t\ts.isAEADRequest = true\n\t} else if !s.isAEADForced && errorAEAD == vmessaead.ErrNotFound {\n\t\tuserLegacy, timestamp, valid, userValidationError := s.userValidator.Get(buffer.Bytes())\n\t\tif !valid || userValidationError != nil {\n\t\t\treturn nil, drainConnection(newError(\"invalid user\").Base(userValidationError))\n\t\t}\n\t\tuser = userLegacy\n\t\tiv := hashTimestamp(md5.New(), timestamp)\n\t\tvmessAccount = userLegacy.Account.(*vmess.MemoryAccount)\n\n\t\taesStream := crypto.NewAesDecryptionStream(vmessAccount.ID.CmdKey(), iv[:])\n\t\tdecryptor = crypto.NewCryptionReader(aesStream, reader)\n\t} else {\n\t\treturn nil, drainConnection(newError(\"invalid user\").Base(errorAEAD))\n\t}\n\n\treadSizeRemain -= int(buffer.Len())\n\tbuffer.Clear()\n\tif _, err := buffer.ReadFullFrom(decryptor, 38); err != nil {\n\t\treturn nil, newError(\"failed to read request header\").Base(err)\n\t}\n\n\trequest := &protocol.RequestHeader{\n\t\tUser:    user,\n\t\tVersion: buffer.Byte(0),\n\t}\n\n\tcopy(s.requestBodyIV[:], buffer.BytesRange(1, 17))   // 16 bytes\n\tcopy(s.requestBodyKey[:], buffer.BytesRange(17, 33)) // 16 bytes\n\tvar sid sessionId\n\tcopy(sid.user[:], vmessAccount.ID.Bytes())\n\tsid.key = s.requestBodyKey\n\tsid.nonce = s.requestBodyIV\n\tif !s.sessionHistory.addIfNotExits(sid) {\n\t\tif !s.isAEADRequest {\n\t\t\tdrainErr := s.userValidator.BurnTaintFuse(fixedSizeAuthID[:])\n\t\t\tif drainErr != nil {\n\t\t\t\treturn nil, drainConnection(newError(\"duplicated session id, possibly under replay attack, and failed to taint userHash\").Base(drainErr))\n\t\t\t}\n\t\t\treturn nil, drainConnection(newError(\"duplicated session id, possibly under replay attack, userHash tainted\"))\n\t\t} else {\n\t\t\treturn nil, newError(\"duplicated session id, possibly under replay attack, but this is a AEAD request\")\n\t\t}\n\n\t}\n\n\ts.responseHeader = buffer.Byte(33)             // 1 byte\n\trequest.Option = bitmask.Byte(buffer.Byte(34)) // 1 byte\n\tpadingLen := int(buffer.Byte(35) >> 4)\n\trequest.Security = parseSecurityType(buffer.Byte(35) & 0x0F)\n\t// 1 bytes reserved\n\trequest.Command = protocol.RequestCommand(buffer.Byte(37))\n\n\tswitch request.Command {\n\tcase protocol.RequestCommandMux:\n\t\trequest.Address = net.DomainAddress(\"v1.mux.cool\")\n\t\trequest.Port = 0\n\tcase protocol.RequestCommandTCP, protocol.RequestCommandUDP:\n\t\tif addr, port, err := addrParser.ReadAddressPort(buffer, decryptor); err == nil {\n\t\t\trequest.Address = addr\n\t\t\trequest.Port = port\n\t\t}\n\t}\n\n\tif padingLen > 0 {\n\t\tif _, err := buffer.ReadFullFrom(decryptor, int32(padingLen)); err != nil {\n\t\t\tif !s.isAEADRequest {\n\t\t\t\tburnErr := s.userValidator.BurnTaintFuse(fixedSizeAuthID[:])\n\t\t\t\tif burnErr != nil {\n\t\t\t\t\treturn nil, newError(\"failed to read padding, failed to taint userHash\").Base(burnErr).Base(err)\n\t\t\t\t}\n\t\t\t\treturn nil, newError(\"failed to read padding, userHash tainted\").Base(err)\n\t\t\t}\n\t\t\treturn nil, newError(\"failed to read padding\").Base(err)\n\t\t}\n\t}\n\n\tif _, err := buffer.ReadFullFrom(decryptor, 4); err != nil {\n\t\tif !s.isAEADRequest {\n\t\t\tburnErr := s.userValidator.BurnTaintFuse(fixedSizeAuthID[:])\n\t\t\tif burnErr != nil {\n\t\t\t\treturn nil, newError(\"failed to read checksum, failed to taint userHash\").Base(burnErr).Base(err)\n\t\t\t}\n\t\t\treturn nil, newError(\"failed to read checksum, userHash tainted\").Base(err)\n\t\t}\n\t\treturn nil, newError(\"failed to read checksum\").Base(err)\n\t}\n\n\tfnv1a := fnv.New32a()\n\tcommon.Must2(fnv1a.Write(buffer.BytesTo(-4)))\n\tactualHash := fnv1a.Sum32()\n\texpectedHash := binary.BigEndian.Uint32(buffer.BytesFrom(-4))\n\n\tif actualHash != expectedHash {\n\t\tif !s.isAEADRequest {\n\t\t\tAutherr := newError(\"invalid auth, legacy userHash tainted\")\n\t\t\tburnErr := s.userValidator.BurnTaintFuse(fixedSizeAuthID[:])\n\t\t\tif burnErr != nil {\n\t\t\t\tAutherr = newError(\"invalid auth, can't taint legacy userHash\").Base(burnErr)\n\t\t\t}\n\t\t\t//It is possible that we are under attack described in https://github.com/v2ray/v2ray-core/issues/2523\n\t\t\treturn nil, drainConnection(Autherr)\n\t\t} else {\n\t\t\treturn nil, newError(\"invalid auth, but this is a AEAD request\")\n\t\t}\n\n\t}\n\n\tif request.Address == nil {\n\t\treturn nil, newError(\"invalid remote address\")\n\t}\n\n\tif request.Security == protocol.SecurityType_UNKNOWN || request.Security == protocol.SecurityType_AUTO {\n\t\treturn nil, newError(\"unknown security type: \", request.Security)\n\t}\n\n\treturn request, nil\n}\n\n// DecodeRequestBody returns Reader from which caller can fetch decrypted body.\nfunc (s *ServerSession) DecodeRequestBody(request *protocol.RequestHeader, reader io.Reader) buf.Reader {\n\tvar sizeParser crypto.ChunkSizeDecoder = crypto.PlainChunkSizeParser{}\n\tif request.Option.Has(protocol.RequestOptionChunkMasking) {\n\t\tsizeParser = NewShakeSizeParser(s.requestBodyIV[:])\n\t}\n\tvar padding crypto.PaddingLengthGenerator\n\tif request.Option.Has(protocol.RequestOptionGlobalPadding) {\n\t\tpadding = sizeParser.(crypto.PaddingLengthGenerator)\n\t}\n\n\tswitch request.Security {\n\tcase protocol.SecurityType_NONE:\n\t\tif request.Option.Has(protocol.RequestOptionChunkStream) {\n\t\t\tif request.Command.TransferType() == protocol.TransferTypeStream {\n\t\t\t\treturn crypto.NewChunkStreamReader(sizeParser, reader)\n\t\t\t}\n\n\t\t\tauth := &crypto.AEADAuthenticator{\n\t\t\t\tAEAD:                    new(NoOpAuthenticator),\n\t\t\t\tNonceGenerator:          crypto.GenerateEmptyBytes(),\n\t\t\t\tAdditionalDataGenerator: crypto.GenerateEmptyBytes(),\n\t\t\t}\n\t\t\treturn crypto.NewAuthenticationReader(auth, sizeParser, reader, protocol.TransferTypePacket, padding)\n\t\t}\n\n\t\treturn buf.NewReader(reader)\n\tcase protocol.SecurityType_LEGACY:\n\t\taesStream := crypto.NewAesDecryptionStream(s.requestBodyKey[:], s.requestBodyIV[:])\n\t\tcryptionReader := crypto.NewCryptionReader(aesStream, reader)\n\t\tif request.Option.Has(protocol.RequestOptionChunkStream) {\n\t\t\tauth := &crypto.AEADAuthenticator{\n\t\t\t\tAEAD:                    new(FnvAuthenticator),\n\t\t\t\tNonceGenerator:          crypto.GenerateEmptyBytes(),\n\t\t\t\tAdditionalDataGenerator: crypto.GenerateEmptyBytes(),\n\t\t\t}\n\t\t\treturn crypto.NewAuthenticationReader(auth, sizeParser, cryptionReader, request.Command.TransferType(), padding)\n\t\t}\n\n\t\treturn buf.NewReader(cryptionReader)\n\tcase protocol.SecurityType_AES128_GCM:\n\t\taead := crypto.NewAesGcm(s.requestBodyKey[:])\n\n\t\tauth := &crypto.AEADAuthenticator{\n\t\t\tAEAD:                    aead,\n\t\t\tNonceGenerator:          GenerateChunkNonce(s.requestBodyIV[:], uint32(aead.NonceSize())),\n\t\t\tAdditionalDataGenerator: crypto.GenerateEmptyBytes(),\n\t\t}\n\t\treturn crypto.NewAuthenticationReader(auth, sizeParser, reader, request.Command.TransferType(), padding)\n\tcase protocol.SecurityType_CHACHA20_POLY1305:\n\t\taead, _ := chacha20poly1305.New(GenerateChacha20Poly1305Key(s.requestBodyKey[:]))\n\n\t\tauth := &crypto.AEADAuthenticator{\n\t\t\tAEAD:                    aead,\n\t\t\tNonceGenerator:          GenerateChunkNonce(s.requestBodyIV[:], uint32(aead.NonceSize())),\n\t\t\tAdditionalDataGenerator: crypto.GenerateEmptyBytes(),\n\t\t}\n\t\treturn crypto.NewAuthenticationReader(auth, sizeParser, reader, request.Command.TransferType(), padding)\n\tdefault:\n\t\tpanic(\"Unknown security type.\")\n\t}\n}\n\n// EncodeResponseHeader writes encoded response header into the given writer.\nfunc (s *ServerSession) EncodeResponseHeader(header *protocol.ResponseHeader, writer io.Writer) {\n\tvar encryptionWriter io.Writer\n\tif !s.isAEADRequest {\n\t\ts.responseBodyKey = md5.Sum(s.requestBodyKey[:])\n\t\ts.responseBodyIV = md5.Sum(s.requestBodyIV[:])\n\t} else {\n\t\tBodyKey := sha256.Sum256(s.requestBodyKey[:])\n\t\tcopy(s.responseBodyKey[:], BodyKey[:16])\n\t\tBodyIV := sha256.Sum256(s.requestBodyIV[:])\n\t\tcopy(s.responseBodyIV[:], BodyIV[:16])\n\t}\n\n\taesStream := crypto.NewAesEncryptionStream(s.responseBodyKey[:], s.responseBodyIV[:])\n\tencryptionWriter = crypto.NewCryptionWriter(aesStream, writer)\n\ts.responseWriter = encryptionWriter\n\n\taeadEncryptedHeaderBuffer := bytes.NewBuffer(nil)\n\n\tif s.isAEADRequest {\n\t\tencryptionWriter = aeadEncryptedHeaderBuffer\n\t}\n\n\tcommon.Must2(encryptionWriter.Write([]byte{s.responseHeader, byte(header.Option)}))\n\terr := MarshalCommand(header.Command, encryptionWriter)\n\tif err != nil {\n\t\tcommon.Must2(encryptionWriter.Write([]byte{0x00, 0x00}))\n\t}\n\n\tif s.isAEADRequest {\n\n\t\taeadResponseHeaderLengthEncryptionKey := vmessaead.KDF16(s.responseBodyKey[:], vmessaead.KDFSaltConst_AEADRespHeaderLenKey)\n\t\taeadResponseHeaderLengthEncryptionIV := vmessaead.KDF(s.responseBodyIV[:], vmessaead.KDFSaltConst_AEADRespHeaderLenIV)[:12]\n\n\t\taeadResponseHeaderLengthEncryptionKeyAESBlock := common.Must2(aes.NewCipher(aeadResponseHeaderLengthEncryptionKey)).(cipher.Block)\n\t\taeadResponseHeaderLengthEncryptionAEAD := common.Must2(cipher.NewGCM(aeadResponseHeaderLengthEncryptionKeyAESBlock)).(cipher.AEAD)\n\n\t\taeadResponseHeaderLengthEncryptionBuffer := bytes.NewBuffer(nil)\n\n\t\tdecryptedResponseHeaderLengthBinaryDeserializeBuffer := uint16(aeadEncryptedHeaderBuffer.Len())\n\n\t\tcommon.Must(binary.Write(aeadResponseHeaderLengthEncryptionBuffer, binary.BigEndian, decryptedResponseHeaderLengthBinaryDeserializeBuffer))\n\n\t\tAEADEncryptedLength := aeadResponseHeaderLengthEncryptionAEAD.Seal(nil, aeadResponseHeaderLengthEncryptionIV, aeadResponseHeaderLengthEncryptionBuffer.Bytes(), nil)\n\t\tcommon.Must2(io.Copy(writer, bytes.NewReader(AEADEncryptedLength)))\n\n\t\taeadResponseHeaderPayloadEncryptionKey := vmessaead.KDF16(s.responseBodyKey[:], vmessaead.KDFSaltConst_AEADRespHeaderPayloadKey)\n\t\taeadResponseHeaderPayloadEncryptionIV := vmessaead.KDF(s.responseBodyIV[:], vmessaead.KDFSaltConst_AEADRespHeaderPayloadIV)[:12]\n\n\t\taeadResponseHeaderPayloadEncryptionKeyAESBlock := common.Must2(aes.NewCipher(aeadResponseHeaderPayloadEncryptionKey)).(cipher.Block)\n\t\taeadResponseHeaderPayloadEncryptionAEAD := common.Must2(cipher.NewGCM(aeadResponseHeaderPayloadEncryptionKeyAESBlock)).(cipher.AEAD)\n\n\t\taeadEncryptedHeaderPayload := aeadResponseHeaderPayloadEncryptionAEAD.Seal(nil, aeadResponseHeaderPayloadEncryptionIV, aeadEncryptedHeaderBuffer.Bytes(), nil)\n\t\tcommon.Must2(io.Copy(writer, bytes.NewReader(aeadEncryptedHeaderPayload)))\n\t}\n}\n\n// EncodeResponseBody returns a Writer that auto-encrypt content written by caller.\nfunc (s *ServerSession) EncodeResponseBody(request *protocol.RequestHeader, writer io.Writer) buf.Writer {\n\tvar sizeParser crypto.ChunkSizeEncoder = crypto.PlainChunkSizeParser{}\n\tif request.Option.Has(protocol.RequestOptionChunkMasking) {\n\t\tsizeParser = NewShakeSizeParser(s.responseBodyIV[:])\n\t}\n\tvar padding crypto.PaddingLengthGenerator\n\tif request.Option.Has(protocol.RequestOptionGlobalPadding) {\n\t\tpadding = sizeParser.(crypto.PaddingLengthGenerator)\n\t}\n\n\tswitch request.Security {\n\tcase protocol.SecurityType_NONE:\n\t\tif request.Option.Has(protocol.RequestOptionChunkStream) {\n\t\t\tif request.Command.TransferType() == protocol.TransferTypeStream {\n\t\t\t\treturn crypto.NewChunkStreamWriter(sizeParser, writer)\n\t\t\t}\n\n\t\t\tauth := &crypto.AEADAuthenticator{\n\t\t\t\tAEAD:                    new(NoOpAuthenticator),\n\t\t\t\tNonceGenerator:          crypto.GenerateEmptyBytes(),\n\t\t\t\tAdditionalDataGenerator: crypto.GenerateEmptyBytes(),\n\t\t\t}\n\t\t\treturn crypto.NewAuthenticationWriter(auth, sizeParser, writer, protocol.TransferTypePacket, padding)\n\t\t}\n\n\t\treturn buf.NewWriter(writer)\n\tcase protocol.SecurityType_LEGACY:\n\t\tif request.Option.Has(protocol.RequestOptionChunkStream) {\n\t\t\tauth := &crypto.AEADAuthenticator{\n\t\t\t\tAEAD:                    new(FnvAuthenticator),\n\t\t\t\tNonceGenerator:          crypto.GenerateEmptyBytes(),\n\t\t\t\tAdditionalDataGenerator: crypto.GenerateEmptyBytes(),\n\t\t\t}\n\t\t\treturn crypto.NewAuthenticationWriter(auth, sizeParser, s.responseWriter, request.Command.TransferType(), padding)\n\t\t}\n\n\t\treturn &buf.SequentialWriter{Writer: s.responseWriter}\n\tcase protocol.SecurityType_AES128_GCM:\n\t\taead := crypto.NewAesGcm(s.responseBodyKey[:])\n\n\t\tauth := &crypto.AEADAuthenticator{\n\t\t\tAEAD:                    aead,\n\t\t\tNonceGenerator:          GenerateChunkNonce(s.responseBodyIV[:], uint32(aead.NonceSize())),\n\t\t\tAdditionalDataGenerator: crypto.GenerateEmptyBytes(),\n\t\t}\n\t\treturn crypto.NewAuthenticationWriter(auth, sizeParser, writer, request.Command.TransferType(), padding)\n\tcase protocol.SecurityType_CHACHA20_POLY1305:\n\t\taead, _ := chacha20poly1305.New(GenerateChacha20Poly1305Key(s.responseBodyKey[:]))\n\n\t\tauth := &crypto.AEADAuthenticator{\n\t\t\tAEAD:                    aead,\n\t\t\tNonceGenerator:          GenerateChunkNonce(s.responseBodyIV[:], uint32(aead.NonceSize())),\n\t\t\tAdditionalDataGenerator: crypto.GenerateEmptyBytes(),\n\t\t}\n\t\treturn crypto.NewAuthenticationWriter(auth, sizeParser, writer, request.Command.TransferType(), padding)\n\tdefault:\n\t\tpanic(\"Unknown security type.\")\n\t}\n}\n\nfunc (s *ServerSession) DrainConnN(reader io.Reader, n int) error {\n\t_, err := io.CopyN(ioutil.Discard, reader, int64(n))\n\treturn err\n}\n"
  },
  {
    "path": "proxy/vmess/errors.generated.go",
    "content": "package vmess\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "proxy/vmess/inbound/config.go",
    "content": "// +build !confonly\n\npackage inbound\n\n// GetDefaultValue returns default settings of DefaultConfig.\nfunc (c *Config) GetDefaultValue() *DefaultConfig {\n\tif c.GetDefault() == nil {\n\t\treturn &DefaultConfig{\n\t\t\tAlterId: 32,\n\t\t\tLevel:   0,\n\t\t}\n\t}\n\treturn c.Default\n}\n"
  },
  {
    "path": "proxy/vmess/inbound/config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: proxy/vmess/inbound/config.proto\n\npackage inbound\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n\tprotocol \"v2ray.com/core/common/protocol\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype DetourConfig struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tTo string `protobuf:\"bytes,1,opt,name=to,proto3\" json:\"to,omitempty\"`\n}\n\nfunc (x *DetourConfig) Reset() {\n\t*x = DetourConfig{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_proxy_vmess_inbound_config_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *DetourConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*DetourConfig) ProtoMessage() {}\n\nfunc (x *DetourConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_proxy_vmess_inbound_config_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use DetourConfig.ProtoReflect.Descriptor instead.\nfunc (*DetourConfig) Descriptor() ([]byte, []int) {\n\treturn file_proxy_vmess_inbound_config_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *DetourConfig) GetTo() string {\n\tif x != nil {\n\t\treturn x.To\n\t}\n\treturn \"\"\n}\n\ntype DefaultConfig struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tAlterId uint32 `protobuf:\"varint,1,opt,name=alter_id,json=alterId,proto3\" json:\"alter_id,omitempty\"`\n\tLevel   uint32 `protobuf:\"varint,2,opt,name=level,proto3\" json:\"level,omitempty\"`\n}\n\nfunc (x *DefaultConfig) Reset() {\n\t*x = DefaultConfig{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_proxy_vmess_inbound_config_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *DefaultConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*DefaultConfig) ProtoMessage() {}\n\nfunc (x *DefaultConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_proxy_vmess_inbound_config_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use DefaultConfig.ProtoReflect.Descriptor instead.\nfunc (*DefaultConfig) Descriptor() ([]byte, []int) {\n\treturn file_proxy_vmess_inbound_config_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *DefaultConfig) GetAlterId() uint32 {\n\tif x != nil {\n\t\treturn x.AlterId\n\t}\n\treturn 0\n}\n\nfunc (x *DefaultConfig) GetLevel() uint32 {\n\tif x != nil {\n\t\treturn x.Level\n\t}\n\treturn 0\n}\n\ntype Config struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tUser                 []*protocol.User `protobuf:\"bytes,1,rep,name=user,proto3\" json:\"user,omitempty\"`\n\tDefault              *DefaultConfig   `protobuf:\"bytes,2,opt,name=default,proto3\" json:\"default,omitempty\"`\n\tDetour               *DetourConfig    `protobuf:\"bytes,3,opt,name=detour,proto3\" json:\"detour,omitempty\"`\n\tSecureEncryptionOnly bool             `protobuf:\"varint,4,opt,name=secure_encryption_only,json=secureEncryptionOnly,proto3\" json:\"secure_encryption_only,omitempty\"`\n}\n\nfunc (x *Config) Reset() {\n\t*x = Config{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_proxy_vmess_inbound_config_proto_msgTypes[2]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Config) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Config) ProtoMessage() {}\n\nfunc (x *Config) ProtoReflect() protoreflect.Message {\n\tmi := &file_proxy_vmess_inbound_config_proto_msgTypes[2]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Config.ProtoReflect.Descriptor instead.\nfunc (*Config) Descriptor() ([]byte, []int) {\n\treturn file_proxy_vmess_inbound_config_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *Config) GetUser() []*protocol.User {\n\tif x != nil {\n\t\treturn x.User\n\t}\n\treturn nil\n}\n\nfunc (x *Config) GetDefault() *DefaultConfig {\n\tif x != nil {\n\t\treturn x.Default\n\t}\n\treturn nil\n}\n\nfunc (x *Config) GetDetour() *DetourConfig {\n\tif x != nil {\n\t\treturn x.Detour\n\t}\n\treturn nil\n}\n\nfunc (x *Config) GetSecureEncryptionOnly() bool {\n\tif x != nil {\n\t\treturn x.SecureEncryptionOnly\n\t}\n\treturn false\n}\n\nvar File_proxy_vmess_inbound_config_proto protoreflect.FileDescriptor\n\nvar file_proxy_vmess_inbound_config_proto_rawDesc = []byte{\n\t0x0a, 0x20, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6d, 0x65, 0x73, 0x73, 0x2f, 0x69, 0x6e,\n\t0x62, 0x6f, 0x75, 0x6e, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f,\n\t0x74, 0x6f, 0x12, 0x1e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70,\n\t0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6d, 0x65, 0x73, 0x73, 0x2e, 0x69, 0x6e, 0x62, 0x6f, 0x75,\n\t0x6e, 0x64, 0x1a, 0x1a, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,\n\t0x63, 0x6f, 0x6c, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x1e,\n\t0x0a, 0x0c, 0x44, 0x65, 0x74, 0x6f, 0x75, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x0e,\n\t0x0a, 0x02, 0x74, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x74, 0x6f, 0x22, 0x40,\n\t0x0a, 0x0d, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,\n\t0x19, 0x0a, 0x08, 0x61, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,\n\t0x0d, 0x52, 0x07, 0x61, 0x6c, 0x74, 0x65, 0x72, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65,\n\t0x76, 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c,\n\t0x22, 0x83, 0x02, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x34, 0x0a, 0x04, 0x75,\n\t0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x76, 0x32, 0x72, 0x61,\n\t0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72,\n\t0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65,\n\t0x72, 0x12, 0x47, 0x0a, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x18, 0x02, 0x20, 0x01,\n\t0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,\n\t0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6d, 0x65, 0x73, 0x73, 0x2e, 0x69, 0x6e, 0x62, 0x6f,\n\t0x75, 0x6e, 0x64, 0x2e, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69,\n\t0x67, 0x52, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x12, 0x44, 0x0a, 0x06, 0x64, 0x65,\n\t0x74, 0x6f, 0x75, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x76, 0x32, 0x72,\n\t0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6d,\n\t0x65, 0x73, 0x73, 0x2e, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x2e, 0x44, 0x65, 0x74, 0x6f,\n\t0x75, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x64, 0x65, 0x74, 0x6f, 0x75, 0x72,\n\t0x12, 0x34, 0x0a, 0x16, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x5f, 0x65, 0x6e, 0x63, 0x72, 0x79,\n\t0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08,\n\t0x52, 0x14, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69,\n\t0x6f, 0x6e, 0x4f, 0x6e, 0x6c, 0x79, 0x42, 0x6b, 0x0a, 0x22, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32,\n\t0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76,\n\t0x6d, 0x65, 0x73, 0x73, 0x2e, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x50, 0x01, 0x5a, 0x22,\n\t0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70,\n\t0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6d, 0x65, 0x73, 0x73, 0x2f, 0x69, 0x6e, 0x62, 0x6f, 0x75,\n\t0x6e, 0x64, 0xaa, 0x02, 0x1e, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e,\n\t0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x56, 0x6d, 0x65, 0x73, 0x73, 0x2e, 0x49, 0x6e, 0x62, 0x6f,\n\t0x75, 0x6e, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_proxy_vmess_inbound_config_proto_rawDescOnce sync.Once\n\tfile_proxy_vmess_inbound_config_proto_rawDescData = file_proxy_vmess_inbound_config_proto_rawDesc\n)\n\nfunc file_proxy_vmess_inbound_config_proto_rawDescGZIP() []byte {\n\tfile_proxy_vmess_inbound_config_proto_rawDescOnce.Do(func() {\n\t\tfile_proxy_vmess_inbound_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_proxy_vmess_inbound_config_proto_rawDescData)\n\t})\n\treturn file_proxy_vmess_inbound_config_proto_rawDescData\n}\n\nvar file_proxy_vmess_inbound_config_proto_msgTypes = make([]protoimpl.MessageInfo, 3)\nvar file_proxy_vmess_inbound_config_proto_goTypes = []interface{}{\n\t(*DetourConfig)(nil),  // 0: v2ray.core.proxy.vmess.inbound.DetourConfig\n\t(*DefaultConfig)(nil), // 1: v2ray.core.proxy.vmess.inbound.DefaultConfig\n\t(*Config)(nil),        // 2: v2ray.core.proxy.vmess.inbound.Config\n\t(*protocol.User)(nil), // 3: v2ray.core.common.protocol.User\n}\nvar file_proxy_vmess_inbound_config_proto_depIdxs = []int32{\n\t3, // 0: v2ray.core.proxy.vmess.inbound.Config.user:type_name -> v2ray.core.common.protocol.User\n\t1, // 1: v2ray.core.proxy.vmess.inbound.Config.default:type_name -> v2ray.core.proxy.vmess.inbound.DefaultConfig\n\t0, // 2: v2ray.core.proxy.vmess.inbound.Config.detour:type_name -> v2ray.core.proxy.vmess.inbound.DetourConfig\n\t3, // [3:3] is the sub-list for method output_type\n\t3, // [3:3] is the sub-list for method input_type\n\t3, // [3:3] is the sub-list for extension type_name\n\t3, // [3:3] is the sub-list for extension extendee\n\t0, // [0:3] is the sub-list for field type_name\n}\n\nfunc init() { file_proxy_vmess_inbound_config_proto_init() }\nfunc file_proxy_vmess_inbound_config_proto_init() {\n\tif File_proxy_vmess_inbound_config_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_proxy_vmess_inbound_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*DetourConfig); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_proxy_vmess_inbound_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*DefaultConfig); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_proxy_vmess_inbound_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Config); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_proxy_vmess_inbound_config_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   3,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_proxy_vmess_inbound_config_proto_goTypes,\n\t\tDependencyIndexes: file_proxy_vmess_inbound_config_proto_depIdxs,\n\t\tMessageInfos:      file_proxy_vmess_inbound_config_proto_msgTypes,\n\t}.Build()\n\tFile_proxy_vmess_inbound_config_proto = out.File\n\tfile_proxy_vmess_inbound_config_proto_rawDesc = nil\n\tfile_proxy_vmess_inbound_config_proto_goTypes = nil\n\tfile_proxy_vmess_inbound_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "proxy/vmess/inbound/config.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.proxy.vmess.inbound;\noption csharp_namespace = \"V2Ray.Core.Proxy.Vmess.Inbound\";\noption go_package = \"v2ray.com/core/proxy/vmess/inbound\";\noption java_package = \"com.v2ray.core.proxy.vmess.inbound\";\noption java_multiple_files = true;\n\nimport \"common/protocol/user.proto\";\n\nmessage DetourConfig {\n  string to = 1;\n}\n\nmessage DefaultConfig {\n  uint32 alter_id = 1;\n  uint32 level = 2;\n}\n\nmessage Config {\n  repeated v2ray.core.common.protocol.User user = 1;\n  DefaultConfig default = 2;\n  DetourConfig detour = 3;\n  bool secure_encryption_only = 4;\n}\n"
  },
  {
    "path": "proxy/vmess/inbound/errors.generated.go",
    "content": "package inbound\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "proxy/vmess/inbound/inbound.go",
    "content": "// +build !confonly\n\npackage inbound\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/errors\"\n\t\"v2ray.com/core/common/log\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/session\"\n\t\"v2ray.com/core/common/signal\"\n\t\"v2ray.com/core/common/task\"\n\t\"v2ray.com/core/common/uuid\"\n\tfeature_inbound \"v2ray.com/core/features/inbound\"\n\t\"v2ray.com/core/features/policy\"\n\t\"v2ray.com/core/features/routing\"\n\t\"v2ray.com/core/proxy/vmess\"\n\t\"v2ray.com/core/proxy/vmess/encoding\"\n\t\"v2ray.com/core/transport/internet\"\n)\n\ntype userByEmail struct {\n\tsync.Mutex\n\tcache           map[string]*protocol.MemoryUser\n\tdefaultLevel    uint32\n\tdefaultAlterIDs uint16\n}\n\nfunc newUserByEmail(config *DefaultConfig) *userByEmail {\n\treturn &userByEmail{\n\t\tcache:           make(map[string]*protocol.MemoryUser),\n\t\tdefaultLevel:    config.Level,\n\t\tdefaultAlterIDs: uint16(config.AlterId),\n\t}\n}\n\nfunc (v *userByEmail) addNoLock(u *protocol.MemoryUser) bool {\n\temail := strings.ToLower(u.Email)\n\t_, found := v.cache[email]\n\tif found {\n\t\treturn false\n\t}\n\tv.cache[email] = u\n\treturn true\n}\n\nfunc (v *userByEmail) Add(u *protocol.MemoryUser) bool {\n\tv.Lock()\n\tdefer v.Unlock()\n\n\treturn v.addNoLock(u)\n}\n\nfunc (v *userByEmail) Get(email string) (*protocol.MemoryUser, bool) {\n\temail = strings.ToLower(email)\n\n\tv.Lock()\n\tdefer v.Unlock()\n\n\tuser, found := v.cache[email]\n\tif !found {\n\t\tid := uuid.New()\n\t\trawAccount := &vmess.Account{\n\t\t\tId:      id.String(),\n\t\t\tAlterId: uint32(v.defaultAlterIDs),\n\t\t}\n\t\taccount, err := rawAccount.AsAccount()\n\t\tcommon.Must(err)\n\t\tuser = &protocol.MemoryUser{\n\t\t\tLevel:   v.defaultLevel,\n\t\t\tEmail:   email,\n\t\t\tAccount: account,\n\t\t}\n\t\tv.cache[email] = user\n\t}\n\treturn user, found\n}\n\nfunc (v *userByEmail) Remove(email string) bool {\n\temail = strings.ToLower(email)\n\n\tv.Lock()\n\tdefer v.Unlock()\n\n\tif _, found := v.cache[email]; !found {\n\t\treturn false\n\t}\n\tdelete(v.cache, email)\n\treturn true\n}\n\n// Handler is an inbound connection handler that handles messages in VMess protocol.\ntype Handler struct {\n\tpolicyManager         policy.Manager\n\tinboundHandlerManager feature_inbound.Manager\n\tclients               *vmess.TimedUserValidator\n\tusersByEmail          *userByEmail\n\tdetours               *DetourConfig\n\tsessionHistory        *encoding.SessionHistory\n\tsecure                bool\n}\n\n// New creates a new VMess inbound handler.\nfunc New(ctx context.Context, config *Config) (*Handler, error) {\n\tv := core.MustFromContext(ctx)\n\thandler := &Handler{\n\t\tpolicyManager:         v.GetFeature(policy.ManagerType()).(policy.Manager),\n\t\tinboundHandlerManager: v.GetFeature(feature_inbound.ManagerType()).(feature_inbound.Manager),\n\t\tclients:               vmess.NewTimedUserValidator(protocol.DefaultIDHash),\n\t\tdetours:               config.Detour,\n\t\tusersByEmail:          newUserByEmail(config.GetDefaultValue()),\n\t\tsessionHistory:        encoding.NewSessionHistory(),\n\t\tsecure:                config.SecureEncryptionOnly,\n\t}\n\n\tfor _, user := range config.User {\n\t\tmUser, err := user.ToMemoryUser()\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"failed to get VMess user\").Base(err)\n\t\t}\n\n\t\tif err := handler.AddUser(ctx, mUser); err != nil {\n\t\t\treturn nil, newError(\"failed to initiate user\").Base(err)\n\t\t}\n\t}\n\n\treturn handler, nil\n}\n\n// Close implements common.Closable.\nfunc (h *Handler) Close() error {\n\treturn errors.Combine(\n\t\th.clients.Close(),\n\t\th.sessionHistory.Close(),\n\t\tcommon.Close(h.usersByEmail))\n}\n\n// Network implements proxy.Inbound.Network().\nfunc (*Handler) Network() []net.Network {\n\treturn []net.Network{net.Network_TCP}\n}\n\nfunc (h *Handler) GetUser(email string) *protocol.MemoryUser {\n\tuser, existing := h.usersByEmail.Get(email)\n\tif !existing {\n\t\th.clients.Add(user)\n\t}\n\treturn user\n}\n\nfunc (h *Handler) AddUser(ctx context.Context, user *protocol.MemoryUser) error {\n\tif len(user.Email) > 0 && !h.usersByEmail.Add(user) {\n\t\treturn newError(\"User \", user.Email, \" already exists.\")\n\t}\n\treturn h.clients.Add(user)\n}\n\nfunc (h *Handler) RemoveUser(ctx context.Context, email string) error {\n\tif email == \"\" {\n\t\treturn newError(\"Email must not be empty.\")\n\t}\n\tif !h.usersByEmail.Remove(email) {\n\t\treturn newError(\"User \", email, \" not found.\")\n\t}\n\th.clients.Remove(email)\n\treturn nil\n}\n\nfunc transferResponse(timer signal.ActivityUpdater, session *encoding.ServerSession, request *protocol.RequestHeader, response *protocol.ResponseHeader, input buf.Reader, output *buf.BufferedWriter) error {\n\tsession.EncodeResponseHeader(response, output)\n\n\tbodyWriter := session.EncodeResponseBody(request, output)\n\n\t{\n\t\t// Optimize for small response packet\n\t\tdata, err := input.ReadMultiBuffer()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err := bodyWriter.WriteMultiBuffer(data); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif err := output.SetBuffered(false); err != nil {\n\t\treturn err\n\t}\n\n\tif err := buf.Copy(input, bodyWriter, buf.UpdateActivity(timer)); err != nil {\n\t\treturn err\n\t}\n\n\tif request.Option.Has(protocol.RequestOptionChunkStream) {\n\t\tif err := bodyWriter.WriteMultiBuffer(buf.MultiBuffer{}); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc isInsecureEncryption(s protocol.SecurityType) bool {\n\treturn s == protocol.SecurityType_NONE || s == protocol.SecurityType_LEGACY || s == protocol.SecurityType_UNKNOWN\n}\n\n// Process implements proxy.Inbound.Process().\nfunc (h *Handler) Process(ctx context.Context, network net.Network, connection internet.Connection, dispatcher routing.Dispatcher) error {\n\tsessionPolicy := h.policyManager.ForLevel(0)\n\tif err := connection.SetReadDeadline(time.Now().Add(sessionPolicy.Timeouts.Handshake)); err != nil {\n\t\treturn newError(\"unable to set read deadline\").Base(err).AtWarning()\n\t}\n\n\treader := &buf.BufferedReader{Reader: buf.NewReader(connection)}\n\tsvrSession := encoding.NewServerSession(h.clients, h.sessionHistory)\n\trequest, err := svrSession.DecodeRequestHeader(reader)\n\tif err != nil {\n\t\tif errors.Cause(err) != io.EOF {\n\t\t\tlog.Record(&log.AccessMessage{\n\t\t\t\tFrom:   connection.RemoteAddr(),\n\t\t\t\tTo:     \"\",\n\t\t\t\tStatus: log.AccessRejected,\n\t\t\t\tReason: err,\n\t\t\t})\n\t\t\terr = newError(\"invalid request from \", connection.RemoteAddr()).Base(err).AtInfo()\n\t\t}\n\t\treturn err\n\t}\n\n\tif h.secure && isInsecureEncryption(request.Security) {\n\t\tlog.Record(&log.AccessMessage{\n\t\t\tFrom:   connection.RemoteAddr(),\n\t\t\tTo:     \"\",\n\t\t\tStatus: log.AccessRejected,\n\t\t\tReason: \"Insecure encryption\",\n\t\t\tEmail:  request.User.Email,\n\t\t})\n\t\treturn newError(\"client is using insecure encryption: \", request.Security)\n\t}\n\n\tif request.Command != protocol.RequestCommandMux {\n\t\tctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{\n\t\t\tFrom:   connection.RemoteAddr(),\n\t\t\tTo:     request.Destination(),\n\t\t\tStatus: log.AccessAccepted,\n\t\t\tReason: \"\",\n\t\t\tEmail:  request.User.Email,\n\t\t})\n\t}\n\n\tnewError(\"received request for \", request.Destination()).WriteToLog(session.ExportIDToError(ctx))\n\n\tif err := connection.SetReadDeadline(time.Time{}); err != nil {\n\t\tnewError(\"unable to set back read deadline\").Base(err).WriteToLog(session.ExportIDToError(ctx))\n\t}\n\n\tinbound := session.InboundFromContext(ctx)\n\tif inbound == nil {\n\t\tpanic(\"no inbound metadata\")\n\t}\n\tinbound.User = request.User\n\n\tsessionPolicy = h.policyManager.ForLevel(request.User.Level)\n\n\tctx, cancel := context.WithCancel(ctx)\n\ttimer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)\n\n\tctx = policy.ContextWithBufferPolicy(ctx, sessionPolicy.Buffer)\n\tlink, err := dispatcher.Dispatch(ctx, request.Destination())\n\tif err != nil {\n\t\treturn newError(\"failed to dispatch request to \", request.Destination()).Base(err)\n\t}\n\n\trequestDone := func() error {\n\t\tdefer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)\n\n\t\tbodyReader := svrSession.DecodeRequestBody(request, reader)\n\t\tif err := buf.Copy(bodyReader, link.Writer, buf.UpdateActivity(timer)); err != nil {\n\t\t\treturn newError(\"failed to transfer request\").Base(err)\n\t\t}\n\t\treturn nil\n\t}\n\n\tresponseDone := func() error {\n\t\tdefer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)\n\n\t\twriter := buf.NewBufferedWriter(buf.NewWriter(connection))\n\t\tdefer writer.Flush()\n\n\t\tresponse := &protocol.ResponseHeader{\n\t\t\tCommand: h.generateCommand(ctx, request),\n\t\t}\n\t\treturn transferResponse(timer, svrSession, request, response, link.Reader, writer)\n\t}\n\n\tvar requestDonePost = task.OnSuccess(requestDone, task.Close(link.Writer))\n\tif err := task.Run(ctx, requestDonePost, responseDone); err != nil {\n\t\tcommon.Interrupt(link.Reader)\n\t\tcommon.Interrupt(link.Writer)\n\t\treturn newError(\"connection ends\").Base(err)\n\t}\n\n\treturn nil\n}\n\nfunc (h *Handler) generateCommand(ctx context.Context, request *protocol.RequestHeader) protocol.ResponseCommand {\n\tif h.detours != nil {\n\t\ttag := h.detours.To\n\t\tif h.inboundHandlerManager != nil {\n\t\t\thandler, err := h.inboundHandlerManager.GetHandler(ctx, tag)\n\t\t\tif err != nil {\n\t\t\t\tnewError(\"failed to get detour handler: \", tag).Base(err).AtWarning().WriteToLog(session.ExportIDToError(ctx))\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tproxyHandler, port, availableMin := handler.GetRandomInboundProxy()\n\t\t\tinboundHandler, ok := proxyHandler.(*Handler)\n\t\t\tif ok && inboundHandler != nil {\n\t\t\t\tif availableMin > 255 {\n\t\t\t\t\tavailableMin = 255\n\t\t\t\t}\n\n\t\t\t\tnewError(\"pick detour handler for port \", port, \" for \", availableMin, \" minutes.\").AtDebug().WriteToLog(session.ExportIDToError(ctx))\n\t\t\t\tuser := inboundHandler.GetUser(request.User.Email)\n\t\t\t\tif user == nil {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t\taccount := user.Account.(*vmess.MemoryAccount)\n\t\t\t\treturn &protocol.CommandSwitchAccount{\n\t\t\t\t\tPort:     port,\n\t\t\t\t\tID:       account.ID.UUID(),\n\t\t\t\t\tAlterIds: uint16(len(account.AlterIDs)),\n\t\t\t\t\tLevel:    user.Level,\n\t\t\t\t\tValidMin: byte(availableMin),\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc init() {\n\tcommon.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {\n\t\treturn New(ctx, config.(*Config))\n\t}))\n}\n"
  },
  {
    "path": "proxy/vmess/outbound/command.go",
    "content": "// +build !confonly\n\npackage outbound\n\nimport (\n\t\"time\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/proxy/vmess\"\n)\n\nfunc (h *Handler) handleSwitchAccount(cmd *protocol.CommandSwitchAccount) {\n\trawAccount := &vmess.Account{\n\t\tId:      cmd.ID.String(),\n\t\tAlterId: uint32(cmd.AlterIds),\n\t\tSecuritySettings: &protocol.SecurityConfig{\n\t\t\tType: protocol.SecurityType_LEGACY,\n\t\t},\n\t}\n\n\taccount, err := rawAccount.AsAccount()\n\tcommon.Must(err)\n\tuser := &protocol.MemoryUser{\n\t\tEmail:   \"\",\n\t\tLevel:   cmd.Level,\n\t\tAccount: account,\n\t}\n\tdest := net.TCPDestination(cmd.Host, cmd.Port)\n\tuntil := time.Now().Add(time.Duration(cmd.ValidMin) * time.Minute)\n\th.serverList.AddServer(protocol.NewServerSpec(dest, protocol.BeforeTime(until), user))\n}\n\nfunc (h *Handler) handleCommand(dest net.Destination, cmd protocol.ResponseCommand) {\n\tswitch typedCommand := cmd.(type) {\n\tcase *protocol.CommandSwitchAccount:\n\t\tif typedCommand.Host == nil {\n\t\t\ttypedCommand.Host = dest.Address\n\t\t}\n\t\th.handleSwitchAccount(typedCommand)\n\tdefault:\n\t}\n}\n"
  },
  {
    "path": "proxy/vmess/outbound/config.go",
    "content": "package outbound\n"
  },
  {
    "path": "proxy/vmess/outbound/config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: proxy/vmess/outbound/config.proto\n\npackage outbound\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n\tprotocol \"v2ray.com/core/common/protocol\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype Config struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tReceiver []*protocol.ServerEndpoint `protobuf:\"bytes,1,rep,name=Receiver,proto3\" json:\"Receiver,omitempty\"`\n}\n\nfunc (x *Config) Reset() {\n\t*x = Config{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_proxy_vmess_outbound_config_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Config) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Config) ProtoMessage() {}\n\nfunc (x *Config) ProtoReflect() protoreflect.Message {\n\tmi := &file_proxy_vmess_outbound_config_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Config.ProtoReflect.Descriptor instead.\nfunc (*Config) Descriptor() ([]byte, []int) {\n\treturn file_proxy_vmess_outbound_config_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *Config) GetReceiver() []*protocol.ServerEndpoint {\n\tif x != nil {\n\t\treturn x.Receiver\n\t}\n\treturn nil\n}\n\nvar File_proxy_vmess_outbound_config_proto protoreflect.FileDescriptor\n\nvar file_proxy_vmess_outbound_config_proto_rawDesc = []byte{\n\t0x0a, 0x21, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6d, 0x65, 0x73, 0x73, 0x2f, 0x6f, 0x75,\n\t0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72,\n\t0x6f, 0x74, 0x6f, 0x12, 0x1f, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,\n\t0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6d, 0x65, 0x73, 0x73, 0x2e, 0x6f, 0x75, 0x74, 0x62,\n\t0x6f, 0x75, 0x6e, 0x64, 0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f,\n\t0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x70, 0x65,\n\t0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x50, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69,\n\t0x67, 0x12, 0x46, 0x0a, 0x08, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20,\n\t0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,\n\t0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c,\n\t0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52,\n\t0x08, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x42, 0x6e, 0x0a, 0x23, 0x63, 0x6f, 0x6d,\n\t0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78,\n\t0x79, 0x2e, 0x76, 0x6d, 0x65, 0x73, 0x73, 0x2e, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64,\n\t0x50, 0x01, 0x5a, 0x23, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f,\n\t0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6d, 0x65, 0x73, 0x73, 0x2f, 0x6f,\n\t0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0xaa, 0x02, 0x1f, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e,\n\t0x43, 0x6f, 0x72, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x56, 0x6d, 0x65, 0x73, 0x73,\n\t0x2e, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,\n\t0x33,\n}\n\nvar (\n\tfile_proxy_vmess_outbound_config_proto_rawDescOnce sync.Once\n\tfile_proxy_vmess_outbound_config_proto_rawDescData = file_proxy_vmess_outbound_config_proto_rawDesc\n)\n\nfunc file_proxy_vmess_outbound_config_proto_rawDescGZIP() []byte {\n\tfile_proxy_vmess_outbound_config_proto_rawDescOnce.Do(func() {\n\t\tfile_proxy_vmess_outbound_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_proxy_vmess_outbound_config_proto_rawDescData)\n\t})\n\treturn file_proxy_vmess_outbound_config_proto_rawDescData\n}\n\nvar file_proxy_vmess_outbound_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)\nvar file_proxy_vmess_outbound_config_proto_goTypes = []interface{}{\n\t(*Config)(nil),                  // 0: v2ray.core.proxy.vmess.outbound.Config\n\t(*protocol.ServerEndpoint)(nil), // 1: v2ray.core.common.protocol.ServerEndpoint\n}\nvar file_proxy_vmess_outbound_config_proto_depIdxs = []int32{\n\t1, // 0: v2ray.core.proxy.vmess.outbound.Config.Receiver:type_name -> v2ray.core.common.protocol.ServerEndpoint\n\t1, // [1:1] is the sub-list for method output_type\n\t1, // [1:1] is the sub-list for method input_type\n\t1, // [1:1] is the sub-list for extension type_name\n\t1, // [1:1] is the sub-list for extension extendee\n\t0, // [0:1] is the sub-list for field type_name\n}\n\nfunc init() { file_proxy_vmess_outbound_config_proto_init() }\nfunc file_proxy_vmess_outbound_config_proto_init() {\n\tif File_proxy_vmess_outbound_config_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_proxy_vmess_outbound_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Config); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_proxy_vmess_outbound_config_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   1,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_proxy_vmess_outbound_config_proto_goTypes,\n\t\tDependencyIndexes: file_proxy_vmess_outbound_config_proto_depIdxs,\n\t\tMessageInfos:      file_proxy_vmess_outbound_config_proto_msgTypes,\n\t}.Build()\n\tFile_proxy_vmess_outbound_config_proto = out.File\n\tfile_proxy_vmess_outbound_config_proto_rawDesc = nil\n\tfile_proxy_vmess_outbound_config_proto_goTypes = nil\n\tfile_proxy_vmess_outbound_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "proxy/vmess/outbound/config.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.proxy.vmess.outbound;\noption csharp_namespace = \"V2Ray.Core.Proxy.Vmess.Outbound\";\noption go_package = \"v2ray.com/core/proxy/vmess/outbound\";\noption java_package = \"com.v2ray.core.proxy.vmess.outbound\";\noption java_multiple_files = true;\n\nimport \"common/protocol/server_spec.proto\";\n\nmessage Config {\n  repeated v2ray.core.common.protocol.ServerEndpoint Receiver = 1;\n}\n"
  },
  {
    "path": "proxy/vmess/outbound/errors.generated.go",
    "content": "package outbound\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "proxy/vmess/outbound/outbound.go",
    "content": "// +build !confonly\n\npackage outbound\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/platform\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/retry\"\n\t\"v2ray.com/core/common/session\"\n\t\"v2ray.com/core/common/signal\"\n\t\"v2ray.com/core/common/task\"\n\t\"v2ray.com/core/features/policy\"\n\t\"v2ray.com/core/proxy/vmess\"\n\t\"v2ray.com/core/proxy/vmess/encoding\"\n\t\"v2ray.com/core/transport\"\n\t\"v2ray.com/core/transport/internet\"\n)\n\n// Handler is an outbound connection handler for VMess protocol.\ntype Handler struct {\n\tserverList    *protocol.ServerList\n\tserverPicker  protocol.ServerPicker\n\tpolicyManager policy.Manager\n}\n\n// New creates a new VMess outbound handler.\nfunc New(ctx context.Context, config *Config) (*Handler, error) {\n\tserverList := protocol.NewServerList()\n\tfor _, rec := range config.Receiver {\n\t\ts, err := protocol.NewServerSpecFromPB(rec)\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"failed to parse server spec\").Base(err)\n\t\t}\n\t\tserverList.AddServer(s)\n\t}\n\n\tv := core.MustFromContext(ctx)\n\thandler := &Handler{\n\t\tserverList:    serverList,\n\t\tserverPicker:  protocol.NewRoundRobinServerPicker(serverList),\n\t\tpolicyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),\n\t}\n\n\treturn handler, nil\n}\n\n// Process implements proxy.Outbound.Process().\nfunc (h *Handler) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {\n\tvar rec *protocol.ServerSpec\n\tvar conn internet.Connection\n\n\terr := retry.ExponentialBackoff(5, 200).On(func() error {\n\t\trec = h.serverPicker.PickServer()\n\t\trawConn, err := dialer.Dial(ctx, rec.Destination())\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tconn = rawConn\n\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\treturn newError(\"failed to find an available destination\").Base(err).AtWarning()\n\t}\n\tdefer conn.Close() //nolint: errcheck\n\n\toutbound := session.OutboundFromContext(ctx)\n\tif outbound == nil || !outbound.Target.IsValid() {\n\t\treturn newError(\"target not specified\").AtError()\n\t}\n\n\ttarget := outbound.Target\n\tnewError(\"tunneling request to \", target, \" via \", rec.Destination()).WriteToLog(session.ExportIDToError(ctx))\n\n\tcommand := protocol.RequestCommandTCP\n\tif target.Network == net.Network_UDP {\n\t\tcommand = protocol.RequestCommandUDP\n\t}\n\tif target.Address.Family().IsDomain() && target.Address.Domain() == \"v1.mux.cool\" {\n\t\tcommand = protocol.RequestCommandMux\n\t}\n\n\tuser := rec.PickUser()\n\trequest := &protocol.RequestHeader{\n\t\tVersion: encoding.Version,\n\t\tUser:    user,\n\t\tCommand: command,\n\t\tAddress: target.Address,\n\t\tPort:    target.Port,\n\t\tOption:  protocol.RequestOptionChunkStream,\n\t}\n\n\taccount := request.User.Account.(*vmess.MemoryAccount)\n\trequest.Security = account.Security\n\n\tif request.Security == protocol.SecurityType_AES128_GCM || request.Security == protocol.SecurityType_NONE || request.Security == protocol.SecurityType_CHACHA20_POLY1305 {\n\t\trequest.Option.Set(protocol.RequestOptionChunkMasking)\n\t}\n\n\tif shouldEnablePadding(request.Security) && request.Option.Has(protocol.RequestOptionChunkMasking) {\n\t\trequest.Option.Set(protocol.RequestOptionGlobalPadding)\n\t}\n\n\tinput := link.Reader\n\toutput := link.Writer\n\n\tisAEAD := false\n\tif !aead_disabled && len(account.AlterIDs) == 0 {\n\t\tisAEAD = true\n\t}\n\n\tsession := encoding.NewClientSession(isAEAD, protocol.DefaultIDHash, ctx)\n\tsessionPolicy := h.policyManager.ForLevel(request.User.Level)\n\n\tctx, cancel := context.WithCancel(ctx)\n\ttimer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)\n\n\trequestDone := func() error {\n\t\tdefer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)\n\n\t\twriter := buf.NewBufferedWriter(buf.NewWriter(conn))\n\t\tif err := session.EncodeRequestHeader(request, writer); err != nil {\n\t\t\treturn newError(\"failed to encode request\").Base(err).AtWarning()\n\t\t}\n\n\t\tbodyWriter := session.EncodeRequestBody(request, writer)\n\t\tif err := buf.CopyOnceTimeout(input, bodyWriter, time.Millisecond*100); err != nil && err != buf.ErrNotTimeoutReader && err != buf.ErrReadTimeout {\n\t\t\treturn newError(\"failed to write first payload\").Base(err)\n\t\t}\n\n\t\tif err := writer.SetBuffered(false); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err := buf.Copy(input, bodyWriter, buf.UpdateActivity(timer)); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif request.Option.Has(protocol.RequestOptionChunkStream) {\n\t\t\tif err := bodyWriter.WriteMultiBuffer(buf.MultiBuffer{}); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tresponseDone := func() error {\n\t\tdefer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)\n\n\t\treader := &buf.BufferedReader{Reader: buf.NewReader(conn)}\n\t\theader, err := session.DecodeResponseHeader(reader)\n\t\tif err != nil {\n\t\t\treturn newError(\"failed to read header\").Base(err)\n\t\t}\n\t\th.handleCommand(rec.Destination(), header.Command)\n\n\t\tbodyReader := session.DecodeResponseBody(request, reader)\n\n\t\treturn buf.Copy(bodyReader, output, buf.UpdateActivity(timer))\n\t}\n\n\tvar responseDonePost = task.OnSuccess(responseDone, task.Close(output))\n\tif err := task.Run(ctx, requestDone, responseDonePost); err != nil {\n\t\treturn newError(\"connection ends\").Base(err)\n\t}\n\n\treturn nil\n}\n\nvar (\n\tenablePadding = false\n\taead_disabled = false\n)\n\nfunc shouldEnablePadding(s protocol.SecurityType) bool {\n\treturn enablePadding || s == protocol.SecurityType_AES128_GCM || s == protocol.SecurityType_CHACHA20_POLY1305 || s == protocol.SecurityType_AUTO\n}\n\nfunc init() {\n\tcommon.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {\n\t\treturn New(ctx, config.(*Config))\n\t}))\n\n\tconst defaultFlagValue = \"NOT_DEFINED_AT_ALL\"\n\n\tpaddingValue := platform.NewEnvFlag(\"v2ray.vmess.padding\").GetValue(func() string { return defaultFlagValue })\n\tif paddingValue != defaultFlagValue {\n\t\tenablePadding = true\n\t}\n\n\taeadDisabled := platform.NewEnvFlag(\"v2ray.vmess.aead.disabled\").GetValue(func() string { return defaultFlagValue })\n\tif aeadDisabled == \"true\" {\n\t\taead_disabled = true\n\t}\n}\n"
  },
  {
    "path": "proxy/vmess/validator.go",
    "content": "// +build !confonly\n\npackage vmess\n\nimport (\n\t\"crypto/hmac\"\n\t\"crypto/sha256\"\n\t\"hash\"\n\t\"hash/crc64\"\n\t\"strings\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/dice\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/serial\"\n\t\"v2ray.com/core/common/task\"\n\t\"v2ray.com/core/proxy/vmess/aead\"\n)\n\nconst (\n\tupdateInterval   = 10 * time.Second\n\tcacheDurationSec = 120\n)\n\ntype user struct {\n\tuser    protocol.MemoryUser\n\tlastSec protocol.Timestamp\n}\n\n// TimedUserValidator is a user Validator based on time.\ntype TimedUserValidator struct {\n\tsync.RWMutex\n\tusers    []*user\n\tuserHash map[[16]byte]indexTimePair\n\thasher   protocol.IDHash\n\tbaseTime protocol.Timestamp\n\ttask     *task.Periodic\n\n\tbehaviorSeed  uint64\n\tbehaviorFused bool\n\n\taeadDecoderHolder *aead.AuthIDDecoderHolder\n}\n\ntype indexTimePair struct {\n\tuser    *user\n\ttimeInc uint32\n\n\ttaintedFuse *uint32\n}\n\n// NewTimedUserValidator creates a new TimedUserValidator.\nfunc NewTimedUserValidator(hasher protocol.IDHash) *TimedUserValidator {\n\ttuv := &TimedUserValidator{\n\t\tusers:             make([]*user, 0, 16),\n\t\tuserHash:          make(map[[16]byte]indexTimePair, 1024),\n\t\thasher:            hasher,\n\t\tbaseTime:          protocol.Timestamp(time.Now().Unix() - cacheDurationSec*2),\n\t\taeadDecoderHolder: aead.NewAuthIDDecoderHolder(),\n\t}\n\ttuv.task = &task.Periodic{\n\t\tInterval: updateInterval,\n\t\tExecute: func() error {\n\t\t\ttuv.updateUserHash()\n\t\t\treturn nil\n\t\t},\n\t}\n\tcommon.Must(tuv.task.Start())\n\treturn tuv\n}\n\nfunc (v *TimedUserValidator) generateNewHashes(nowSec protocol.Timestamp, user *user) {\n\tvar hashValue [16]byte\n\tgenEndSec := nowSec + cacheDurationSec\n\tgenHashForID := func(id *protocol.ID) {\n\t\tidHash := v.hasher(id.Bytes())\n\t\tgenBeginSec := user.lastSec\n\t\tif genBeginSec < nowSec-cacheDurationSec {\n\t\t\tgenBeginSec = nowSec - cacheDurationSec\n\t\t}\n\t\tfor ts := genBeginSec; ts <= genEndSec; ts++ {\n\t\t\tcommon.Must2(serial.WriteUint64(idHash, uint64(ts)))\n\t\t\tidHash.Sum(hashValue[:0])\n\t\t\tidHash.Reset()\n\n\t\t\tv.userHash[hashValue] = indexTimePair{\n\t\t\t\tuser:        user,\n\t\t\t\ttimeInc:     uint32(ts - v.baseTime),\n\t\t\t\ttaintedFuse: new(uint32),\n\t\t\t}\n\t\t}\n\t}\n\n\taccount := user.user.Account.(*MemoryAccount)\n\n\tgenHashForID(account.ID)\n\tfor _, id := range account.AlterIDs {\n\t\tgenHashForID(id)\n\t}\n\tuser.lastSec = genEndSec\n}\n\nfunc (v *TimedUserValidator) removeExpiredHashes(expire uint32) {\n\tfor key, pair := range v.userHash {\n\t\tif pair.timeInc < expire {\n\t\t\tdelete(v.userHash, key)\n\t\t}\n\t}\n}\n\nfunc (v *TimedUserValidator) updateUserHash() {\n\tnow := time.Now()\n\tnowSec := protocol.Timestamp(now.Unix())\n\tv.Lock()\n\tdefer v.Unlock()\n\n\tfor _, user := range v.users {\n\t\tv.generateNewHashes(nowSec, user)\n\t}\n\n\texpire := protocol.Timestamp(now.Unix() - cacheDurationSec)\n\tif expire > v.baseTime {\n\t\tv.removeExpiredHashes(uint32(expire - v.baseTime))\n\t}\n}\n\nfunc (v *TimedUserValidator) Add(u *protocol.MemoryUser) error {\n\tv.Lock()\n\tdefer v.Unlock()\n\n\tnowSec := time.Now().Unix()\n\n\tuu := &user{\n\t\tuser:    *u,\n\t\tlastSec: protocol.Timestamp(nowSec - cacheDurationSec),\n\t}\n\tv.users = append(v.users, uu)\n\tv.generateNewHashes(protocol.Timestamp(nowSec), uu)\n\n\taccount := uu.user.Account.(*MemoryAccount)\n\tif !v.behaviorFused {\n\t\thashkdf := hmac.New(func() hash.Hash { return sha256.New() }, []byte(\"VMESSBSKDF\"))\n\t\thashkdf.Write(account.ID.Bytes())\n\t\tv.behaviorSeed = crc64.Update(v.behaviorSeed, crc64.MakeTable(crc64.ECMA), hashkdf.Sum(nil))\n\t}\n\n\tvar cmdkeyfl [16]byte\n\tcopy(cmdkeyfl[:], account.ID.CmdKey())\n\tv.aeadDecoderHolder.AddUser(cmdkeyfl, u)\n\n\treturn nil\n}\n\nfunc (v *TimedUserValidator) Get(userHash []byte) (*protocol.MemoryUser, protocol.Timestamp, bool, error) {\n\tdefer v.RUnlock()\n\tv.RLock()\n\n\tv.behaviorFused = true\n\n\tvar fixedSizeHash [16]byte\n\tcopy(fixedSizeHash[:], userHash)\n\tpair, found := v.userHash[fixedSizeHash]\n\tif found {\n\t\tuser := pair.user.user\n\t\tif atomic.LoadUint32(pair.taintedFuse) == 0 {\n\t\t\treturn &user, protocol.Timestamp(pair.timeInc) + v.baseTime, true, nil\n\t\t}\n\t\treturn nil, 0, false, ErrTainted\n\t}\n\treturn nil, 0, false, ErrNotFound\n}\n\nfunc (v *TimedUserValidator) GetAEAD(userHash []byte) (*protocol.MemoryUser, bool, error) {\n\tdefer v.RUnlock()\n\tv.RLock()\n\tvar userHashFL [16]byte\n\tcopy(userHashFL[:], userHash)\n\n\tuserd, err := v.aeadDecoderHolder.Match(userHashFL)\n\tif err != nil {\n\t\treturn nil, false, err\n\t}\n\treturn userd.(*protocol.MemoryUser), true, err\n}\n\nfunc (v *TimedUserValidator) Remove(email string) bool {\n\tv.Lock()\n\tdefer v.Unlock()\n\n\tidx := -1\n\tfor i := range v.users {\n\t\tif strings.EqualFold(v.users[i].user.Email, email) {\n\t\t\tidx = i\n\t\t\tvar cmdkeyfl [16]byte\n\t\t\tcopy(cmdkeyfl[:], v.users[i].user.Account.(*MemoryAccount).ID.CmdKey())\n\t\t\tv.aeadDecoderHolder.RemoveUser(cmdkeyfl)\n\t\t\tbreak\n\t\t}\n\t}\n\tif idx == -1 {\n\t\treturn false\n\t}\n\tulen := len(v.users)\n\n\tv.users[idx] = v.users[ulen-1]\n\tv.users[ulen-1] = nil\n\tv.users = v.users[:ulen-1]\n\n\treturn true\n}\n\n// Close implements common.Closable.\nfunc (v *TimedUserValidator) Close() error {\n\treturn v.task.Close()\n}\n\nfunc (v *TimedUserValidator) GetBehaviorSeed() uint64 {\n\tv.Lock()\n\tdefer v.Unlock()\n\tv.behaviorFused = true\n\tif v.behaviorSeed == 0 {\n\t\tv.behaviorSeed = dice.RollUint64()\n\t}\n\treturn v.behaviorSeed\n}\n\nfunc (v *TimedUserValidator) BurnTaintFuse(userHash []byte) error {\n\tv.RLock()\n\tdefer v.RUnlock()\n\tvar userHashFL [16]byte\n\tcopy(userHashFL[:], userHash)\n\n\tpair, found := v.userHash[userHashFL]\n\tif found {\n\t\tif atomic.CompareAndSwapUint32(pair.taintedFuse, 0, 1) {\n\t\t\treturn nil\n\t\t}\n\t\treturn ErrTainted\n\t}\n\treturn ErrNotFound\n}\n\nvar ErrNotFound = newError(\"Not Found\")\n\nvar ErrTainted = newError(\"ErrTainted\")\n"
  },
  {
    "path": "proxy/vmess/validator_test.go",
    "content": "package vmess_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/serial\"\n\t\"v2ray.com/core/common/uuid\"\n\t. \"v2ray.com/core/proxy/vmess\"\n)\n\nfunc toAccount(a *Account) protocol.Account {\n\taccount, err := a.AsAccount()\n\tcommon.Must(err)\n\treturn account\n}\n\nfunc TestUserValidator(t *testing.T) {\n\thasher := protocol.DefaultIDHash\n\tv := NewTimedUserValidator(hasher)\n\tdefer common.Close(v)\n\n\tid := uuid.New()\n\tuser := &protocol.MemoryUser{\n\t\tEmail: \"test\",\n\t\tAccount: toAccount(&Account{\n\t\t\tId:      id.String(),\n\t\t\tAlterId: 8,\n\t\t}),\n\t}\n\tcommon.Must(v.Add(user))\n\n\t{\n\t\ttestSmallLag := func(lag time.Duration) {\n\t\t\tts := protocol.Timestamp(time.Now().Add(time.Second * lag).Unix())\n\t\t\tidHash := hasher(id.Bytes())\n\t\t\tcommon.Must2(serial.WriteUint64(idHash, uint64(ts)))\n\t\t\tuserHash := idHash.Sum(nil)\n\n\t\t\teuser, ets, found, _ := v.Get(userHash)\n\t\t\tif !found {\n\t\t\t\tt.Fatal(\"user not found\")\n\t\t\t}\n\t\t\tif euser.Email != user.Email {\n\t\t\t\tt.Error(\"unexpected user email: \", euser.Email, \" want \", user.Email)\n\t\t\t}\n\t\t\tif ets != ts {\n\t\t\t\tt.Error(\"unexpected timestamp: \", ets, \" want \", ts)\n\t\t\t}\n\t\t}\n\n\t\ttestSmallLag(0)\n\t\ttestSmallLag(40)\n\t\ttestSmallLag(-40)\n\t\ttestSmallLag(80)\n\t\ttestSmallLag(-80)\n\t\ttestSmallLag(120)\n\t\ttestSmallLag(-120)\n\t}\n\n\t{\n\t\ttestBigLag := func(lag time.Duration) {\n\t\t\tts := protocol.Timestamp(time.Now().Add(time.Second * lag).Unix())\n\t\t\tidHash := hasher(id.Bytes())\n\t\t\tcommon.Must2(serial.WriteUint64(idHash, uint64(ts)))\n\t\t\tuserHash := idHash.Sum(nil)\n\n\t\t\teuser, _, found, _ := v.Get(userHash)\n\t\t\tif found || euser != nil {\n\t\t\t\tt.Error(\"unexpected user\")\n\t\t\t}\n\t\t}\n\n\t\ttestBigLag(121)\n\t\ttestBigLag(-121)\n\t\ttestBigLag(310)\n\t\ttestBigLag(-310)\n\t\ttestBigLag(500)\n\t\ttestBigLag(-500)\n\t}\n\n\tif v := v.Remove(user.Email); !v {\n\t\tt.Error(\"unable to remove user\")\n\t}\n\tif v := v.Remove(user.Email); v {\n\t\tt.Error(\"remove user twice\")\n\t}\n}\n\nfunc BenchmarkUserValidator(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\thasher := protocol.DefaultIDHash\n\t\tv := NewTimedUserValidator(hasher)\n\n\t\tfor j := 0; j < 1500; j++ {\n\t\t\tid := uuid.New()\n\t\t\tv.Add(&protocol.MemoryUser{\n\t\t\t\tEmail: \"test\",\n\t\t\t\tAccount: toAccount(&Account{\n\t\t\t\t\tId:      id.String(),\n\t\t\t\t\tAlterId: 16,\n\t\t\t\t}),\n\t\t\t})\n\t\t}\n\n\t\tcommon.Close(v)\n\t}\n}\n"
  },
  {
    "path": "proxy/vmess/vmess.go",
    "content": "// Package vmess contains the implementation of VMess protocol and transportation.\n//\n// VMess contains both inbound and outbound connections. VMess inbound is usually used on servers\n// together with 'freedom' to talk to final destination, while VMess outbound is usually used on\n// clients with 'socks' for proxying.\npackage vmess\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n"
  },
  {
    "path": "proxy/vmess/vmessCtxInterface.go",
    "content": "package vmess\n\n// example\nconst AlterID = \"VMessCtxInterface_AlterID\"\n"
  },
  {
    "path": "release/BUILD",
    "content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"//infra/bazel:zip.bzl\", \"pkg_zip\")\nload(\"//release:mapping.bzl\", \"gen_mappings\")\n\nfilegroup(\n    name = \"config_json\",\n    srcs = [\n        \"config/config.json\",\n        \"config/vpoint_socks_vmess.json\",\n        \"config/vpoint_vmess_freedom.json\",\n    ],\n)\n\nfilegroup(\n    name = \"systemd\",\n    srcs = [\n        \"config/systemd/system/v2ray.service\",\n        \"config/systemd/system/v2ray@.service\",\n    ],\n)\n\nfilegroup(\n    name = \"geodata\",\n    srcs = [\n        \"config/geoip.dat\",\n        \"config/geosite.dat\",\n    ],\n)\n\npkg_zip(\n    name = \"v2ray_darwin_amd64_package\",\n    srcs = [\n        \":config_json\",\n        \":geodata\",\n        \"//infra/control/main:v2ctl_darwin_amd64\",\n        \"//main:v2ray_darwin_amd64\",\n    ],\n    out = \"v2ray-macos-64.zip\",\n    mappings = gen_mappings(\"darwin\", \"amd64\", \"0\"),\n)\n\npkg_zip(\n    name = \"v2ray_windows_amd64_package\",\n    srcs = [\n        \":config_json\",\n        \":geodata\",\n        \"//infra/control/main:v2ctl_windows_amd64\",\n        \"//main:v2ray_windows_amd64\",\n        \"//main:v2ray_windows_amd64_nowindow\",\n    ],\n    out = \"v2ray-windows-64.zip\",\n    mappings = gen_mappings(\"windows\", \"amd64\", \"0\"),\n)\n\npkg_zip(\n    name = \"v2ray_windows_x86_package\",\n    srcs = [\n        \":config_json\",\n        \":geodata\",\n        \"//infra/control/main:v2ctl_windows_386\",\n        \"//main:v2ray_windows_386\",\n        \"//main:v2ray_windows_386_nowindow\",\n    ],\n    out = \"v2ray-windows-32.zip\",\n    mappings = gen_mappings(\"windows\", \"386\", \"0\"),\n)\n\npkg_zip(\n    name = \"v2ray_windows_armv7_package\",\n    srcs = [\n        \":config_json\",\n        \":geodata\",\n        \"//infra/control/main:v2ctl_windows_arm_7\",\n        \"//main:v2ray_windows_arm_7\",\n        \"//main:v2ray_windows_arm_7_nowindow\",\n    ],\n    out = \"v2ray-windows-arm32-v7a.zip\",\n    mappings = gen_mappings(\"windows\", \"arm\", \"7\"),\n)\n\npkg_zip(\n    name = \"v2ray_freebsd_amd64_package\",\n    srcs = [\n        \":config_json\",\n        \":geodata\",\n        \"//infra/control/main:v2ctl_freebsd_amd64\",\n        \"//main:v2ray_freebsd_amd64\",\n    ],\n    out = \"v2ray-freebsd-64.zip\",\n    mappings = gen_mappings(\"freebsd\", \"amd64\", \"0\"),\n)\n\npkg_zip(\n    name = \"v2ray_freebsd_x86_package\",\n    srcs = [\n        \":config_json\",\n        \":geodata\",\n        \"//infra/control/main:v2ctl_freebsd_386\",\n        \"//main:v2ray_freebsd_386\",\n    ],\n    out = \"v2ray-freebsd-32.zip\",\n    mappings = gen_mappings(\"freebsd\", \"386\", \"0\"),\n)\n\npkg_zip(\n    name = \"v2ray_openbsd_amd64_package\",\n    srcs = [\n        \":config_json\",\n        \":geodata\",\n        \"//infra/control/main:v2ctl_openbsd_amd64\",\n        \"//main:v2ray_openbsd_amd64\",\n    ],\n    out = \"v2ray-openbsd-64.zip\",\n    mappings = gen_mappings(\"openbsd\", \"amd64\", \"0\"),\n)\n\npkg_zip(\n    name = \"v2ray_openbsd_x86_package\",\n    srcs = [\n        \":config_json\",\n        \":geodata\",\n        \"//infra/control/main:v2ctl_openbsd_386\",\n        \"//main:v2ray_openbsd_386\",\n    ],\n    out = \"v2ray-openbsd-32.zip\",\n    mappings = gen_mappings(\"openbsd\", \"386\", \"0\"),\n)\n\npkg_zip(\n    name = \"v2ray_dragonfly_amd64_package\",\n    srcs = [\n        \":config_json\",\n        \":geodata\",\n        \"//infra/control/main:v2ctl_dragonfly_amd64\",\n        \"//main:v2ray_dragonfly_amd64\",\n    ],\n    out = \"v2ray-dragonfly-64.zip\",\n    mappings = gen_mappings(\"dragonfly\", \"amd64\", \"0\"),\n)\n\npkg_zip(\n    name = \"v2ray_linux_amd64_package\",\n    srcs = [\n        \":config_json\",\n        \":geodata\",\n        \":systemd\",\n        \"//infra/control/main:v2ctl_linux_amd64\",\n        \"//main:v2ray_linux_amd64\",\n    ],\n    out = \"v2ray-linux-64.zip\",\n    mappings = gen_mappings(\"linux\", \"amd64\", \"0\"),\n)\n\npkg_zip(\n    name = \"v2ray_linux_x86_package\",\n    srcs = [\n        \":config_json\",\n        \":geodata\",\n        \":systemd\",\n        \"//infra/control/main:v2ctl_linux_386\",\n        \"//main:v2ray_linux_386\",\n    ],\n    out = \"v2ray-linux-32.zip\",\n    mappings = gen_mappings(\"linux\", \"386\", \"0\"),\n)\n\npkg_zip(\n    name = \"v2ray_linux_arm64_package\",\n    srcs = [\n        \":config_json\",\n        \":geodata\",\n        \":systemd\",\n        \"//infra/control/main:v2ctl_linux_arm64\",\n        \"//main:v2ray_linux_arm64\",\n    ],\n    out = \"v2ray-linux-arm64-v8a.zip\",\n    mappings = gen_mappings(\"linux\", \"arm64\", \"0\"),\n)\n\npkg_zip(\n    name = \"v2ray_linux_armv7_package\",\n    srcs = [\n        \":config_json\",\n        \":geodata\",\n        \":systemd\",\n        \"//infra/control/main:v2ctl_linux_arm_7\",\n        \"//main:v2ray_linux_arm_7\",\n    ],\n    out = \"v2ray-linux-arm32-v7a.zip\",\n    mappings = gen_mappings(\"linux\", \"arm\", \"7\"),\n)\n\npkg_zip(\n    name = \"v2ray_linux_armv6_package\",\n    srcs = [\n        \":config_json\",\n        \":geodata\",\n        \":systemd\",\n        \"//infra/control/main:v2ctl_linux_arm_6\",\n        \"//main:v2ray_linux_arm_6\",\n    ],\n    out = \"v2ray-linux-arm32-v6.zip\",\n    mappings = gen_mappings(\"linux\", \"arm\", \"6\"),\n)\n\npkg_zip(\n    name = \"v2ray_linux_armv5_package\",\n    srcs = [\n        \":config_json\",\n        \":geodata\",\n        \":systemd\",\n        \"//infra/control/main:v2ctl_linux_arm_5\",\n        \"//main:v2ray_linux_arm_5\",\n    ],\n    out = \"v2ray-linux-arm32-v5.zip\",\n    mappings = gen_mappings(\"linux\", \"arm\", \"5\"),\n)\n\npkg_zip(\n    name = \"v2ray_linux_mips32_package\",\n    srcs = [\n        \":config_json\",\n        \":geodata\",\n        \":systemd\",\n        \"//infra/control/main:v2ctl_linux_mips\",\n        \"//infra/control/main:v2ctl_linux_mips_softfloat\",\n        \"//main:v2ray_linux_mips\",\n        \"//main:v2ray_linux_mips_softfloat\",\n    ],\n    out = \"v2ray-linux-mips32.zip\",\n    mappings = gen_mappings(\"linux\", \"mips\", \"0\"),\n)\n\npkg_zip(\n    name = \"v2ray_linux_mips32le_package\",\n    srcs = [\n        \":config_json\",\n        \":geodata\",\n        \":systemd\",\n        \"//infra/control/main:v2ctl_linux_mipsle\",\n        \"//infra/control/main:v2ctl_linux_mipsle_softfloat\",\n        \"//main:v2ray_linux_mipsle\",\n        \"//main:v2ray_linux_mipsle_softfloat\",\n    ],\n    out = \"v2ray-linux-mips32le.zip\",\n    mappings = gen_mappings(\"linux\", \"mipsle\", \"0\"),\n)\n\npkg_zip(\n    name = \"v2ray_linux_mips64_package\",\n    srcs = [\n        \":config_json\",\n        \":geodata\",\n        \":systemd\",\n        \"//infra/control/main:v2ctl_linux_mips64\",\n        \"//main:v2ray_linux_mips64\",\n    ],\n    out = \"v2ray-linux-mips64.zip\",\n    mappings = gen_mappings(\"linux\", \"mips64\", \"0\"),\n)\n\npkg_zip(\n    name = \"v2ray_linux_mips64le_package\",\n    srcs = [\n        \":config_json\",\n        \":geodata\",\n        \":systemd\",\n        \"//infra/control/main:v2ctl_linux_mips64le\",\n        \"//main:v2ray_linux_mips64le\",\n    ],\n    out = \"v2ray-linux-mips64le.zip\",\n    mappings = gen_mappings(\"linux\", \"mips64le\", \"0\"),\n)\n\npkg_zip(\n    name = \"v2ray_linux_riscv64_package\",\n    srcs = [\n        \":config_json\",\n        \":geodata\",\n        \":systemd\",\n        \"//infra/control/main:v2ctl_linux_riscv64\",\n        \"//main:v2ray_linux_riscv64\",\n    ],\n    out = \"v2ray-linux-riscv64.zip\",\n    mappings = gen_mappings(\"linux\", \"riscv64\", \"0\"),\n)\n\npkg_zip(\n    name = \"v2ray_linux_s390x_package\",\n    srcs = [\n        \":config_json\",\n        \":geodata\",\n        \":systemd\",\n        \"//infra/control/main:v2ctl_linux_s390x\",\n        \"//main:v2ray_linux_s390x\",\n    ],\n    out = \"v2ray-linux-s390x.zip\",\n    mappings = gen_mappings(\"linux\", \"s390x\", \"0\"),\n)\n\npkg_zip(\n    name = \"v2ray_linux_ppc64_package\",\n    srcs = [\n        \":config_json\",\n        \":geodata\",\n        \":systemd\",\n        \"//infra/control/main:v2ctl_linux_ppc64\",\n        \"//main:v2ray_linux_ppc64\",\n    ],\n    out = \"v2ray-linux-ppc64.zip\",\n    mappings = gen_mappings(\"linux\", \"ppc64\", \"0\"),\n)\n\npkg_zip(\n    name = \"v2ray_linux_ppc64le_package\",\n    srcs = [\n        \":config_json\",\n        \":geodata\",\n        \":systemd\",\n        \"//infra/control/main:v2ctl_linux_ppc64le\",\n        \"//main:v2ray_linux_ppc64le\",\n    ],\n    out = \"v2ray-linux-ppc64le.zip\",\n    mappings = gen_mappings(\"linux\", \"ppc64le\", \"0\"),\n)\n"
  },
  {
    "path": "release/bleedingrelease.sh",
    "content": "#!/usr/bin/env bash\n\nRELBODY=\"https://github.com/v2fly/v2ray-core/commit/${RELEASE_SHA}\"\nJSON_DATA=$(echo \"{}\" | jq -c \".tag_name=\\\"${RELEASE_TAG}\\\"\")\nJSON_DATA=$(echo ${JSON_DATA} | jq -c \".prerelease=${PRERELEASE}\")\nJSON_DATA=$(echo ${JSON_DATA} | jq -c \".body=\\\"${RELBODY}\\\"\")\nRELEASE_DATA=$(curl --data \"${JSON_DATA}\" -H \"Authorization: token ${GITHUB_TOKEN}\" -X POST https://api.github.com/repos/v2fly/V2FlyBleedingEdgeBinary/releases)\necho $RELEASE_DATA\nRELEASE_ID=$(echo $RELEASE_DATA | jq \".id\")\n\nfunction uploadfile() {\n  FILE=$1\n  CTYPE=$(file -b --mime-type $FILE)\n\n  sleep 1\n  curl -H \"Authorization: token ${GITHUB_TOKEN}\" -H \"Content-Type: ${CTYPE}\" --data-binary @$FILE \"https://uploads.github.com/repos/v2fly/V2FlyBleedingEdgeBinary/releases/${RELEASE_ID}/assets?name=$(basename $FILE)\"\n  sleep 1\n}\n\nfunction upload() {\n  FILE=$1\n  DGST=$1.dgst\n  openssl dgst -md5 $FILE | sed 's/([^)]*)//g' >>$DGST\n  openssl dgst -sha1 $FILE | sed 's/([^)]*)//g' >>$DGST\n  openssl dgst -sha256 $FILE | sed 's/([^)]*)//g' >>$DGST\n  openssl dgst -sha512 $FILE | sed 's/([^)]*)//g' >>$DGST\n  uploadfile $FILE\n  uploadfile $DGST\n}\n\nART_ROOT=${WORKDIR}/bazel-bin/release\n\npushd ${ART_ROOT}\n{\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen version ${RELEASE_TAG}\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen project \"v2flyunstable\"\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-macos-64.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-windows-64.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-windows-32.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-windows-arm32-v7a.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-64.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-32.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-arm64-v8a.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-arm32-v7a.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-arm32-v6.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-arm32-v5.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-mips64.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-mips64le.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-mips32.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-mips32le.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-ppc64.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-ppc64le.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-riscv64.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-s390x.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-freebsd-64.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-freebsd-32.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-openbsd-64.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-openbsd-32.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-dragonfly-64.zip\n} >Release.unsigned.unsorted\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen sort < Release.unsigned.unsorted > Release.unsigned\n\n  {\n    echo \"Build Finished\"\n    echo \"https://github.com/v2fly/V2FlyBleedingEdgeBinary/releases/tag/${RELEASE_TAG}\"\n  } > buildcomment\n\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil post commit \"${RELEASE_SHA}\" < buildcomment\npopd\n\nupload ${ART_ROOT}/v2ray-macos-64.zip\nupload ${ART_ROOT}/v2ray-windows-64.zip\nupload ${ART_ROOT}/v2ray-windows-32.zip\nupload ${ART_ROOT}/v2ray-windows-arm32-v7a.zip\nupload ${ART_ROOT}/v2ray-linux-64.zip\nupload ${ART_ROOT}/v2ray-linux-32.zip\nupload ${ART_ROOT}/v2ray-linux-arm64-v8a.zip\nupload ${ART_ROOT}/v2ray-linux-arm32-v7a.zip\nupload ${ART_ROOT}/v2ray-linux-arm32-v6.zip\nupload ${ART_ROOT}/v2ray-linux-arm32-v5.zip\nupload ${ART_ROOT}/v2ray-linux-mips64.zip\nupload ${ART_ROOT}/v2ray-linux-mips64le.zip\nupload ${ART_ROOT}/v2ray-linux-mips32.zip\nupload ${ART_ROOT}/v2ray-linux-mips32le.zip\nupload ${ART_ROOT}/v2ray-linux-ppc64.zip\nupload ${ART_ROOT}/v2ray-linux-ppc64le.zip\nupload ${ART_ROOT}/v2ray-linux-riscv64.zip\nupload ${ART_ROOT}/v2ray-linux-s390x.zip\nupload ${ART_ROOT}/v2ray-freebsd-64.zip\nupload ${ART_ROOT}/v2ray-freebsd-32.zip\nupload ${ART_ROOT}/v2ray-openbsd-64.zip\nupload ${ART_ROOT}/v2ray-openbsd-32.zip\nupload ${ART_ROOT}/v2ray-dragonfly-64.zip\nupload ${ART_ROOT}/Release.unsigned\n"
  },
  {
    "path": "release/config/config.json",
    "content": "// Config file of V2Ray. This file follows standard JSON format, with comments support.\n// Uncomment entries below to satisfy your needs. Also read our manual for more detail at\n// https://www.v2ray.com/\n{\n  \"log\": {\n    // By default, V2Ray writes access log to stdout.\n    // \"access\": \"/path/to/access/log/file\",\n\n    // By default, V2Ray write error log to stdout.\n    // \"error\": \"/path/to/error/log/file\",\n\n    // Log level, one of \"debug\", \"info\", \"warning\", \"error\", \"none\"\n    \"loglevel\": \"warning\"\n  },\n  // List of inbound proxy configurations.\n  \"inbounds\": [{\n    // Port to listen on. You may need root access if the value is less than 1024.\n    \"port\": 1080,\n\n    // IP address to listen on. Change to \"0.0.0.0\" to listen on all network interfaces.\n    \"listen\": \"127.0.0.1\",\n\n    // Tag of the inbound proxy. May be used for routing.\n    \"tag\": \"socks-inbound\",\n\n    // Protocol name of inbound proxy.\n    \"protocol\": \"socks\",\n\n    // Settings of the protocol. Varies based on protocol.\n    \"settings\": {\n      \"auth\": \"noauth\",\n      \"udp\": false,\n      \"ip\": \"127.0.0.1\"\n    },\n\n    // Enable sniffing on TCP connection.\n    \"sniffing\": {\n      \"enabled\": true,\n      // Target domain will be overriden to the one carried by the connection, if the connection is HTTP or HTTPS.\n      \"destOverride\": [\"http\", \"tls\"]\n    }\n  }],\n  // List of outbound proxy configurations.\n  \"outbounds\": [{\n    // Protocol name of the outbound proxy.\n    \"protocol\": \"freedom\",\n\n    // Settings of the protocol. Varies based on protocol.\n    \"settings\": {},\n\n    // Tag of the outbound. May be used for routing.\n    \"tag\": \"direct\"\n  },{\n    \"protocol\": \"blackhole\",\n    \"settings\": {},\n    \"tag\": \"blocked\"\n  }],\n\n  // Transport is for global transport settings. If you have multiple transports with same settings\n  // (say mKCP), you may put it here, instead of in each individual inbound/outbounds.\n  //\"transport\": {},\n\n  // Routing controls how traffic from inbounds are sent to outbounds.\n  \"routing\": {\n    \"domainStrategy\": \"IPOnDemand\",\n    \"rules\":[\n      {\n        // Blocks access to private IPs. Remove this if you want to access your router.\n        \"type\": \"field\",\n        \"ip\": [\"geoip:private\"],\n        \"outboundTag\": \"blocked\"\n      },\n      {\n        // Blocks major ads.\n        \"type\": \"field\",\n        \"domain\": [\"geosite:category-ads\"],\n        \"outboundTag\": \"blocked\"\n      }\n    ]\n  },\n\n  // Dns settings for domain resolution.\n  \"dns\": {\n    // Static hosts, similar to hosts file.\n    \"hosts\": {\n      // Match v2ray.com to another domain on CloudFlare. This domain will be used when querying IPs for v2ray.com.\n      \"domain:v2ray.com\": \"www.vicemc.net\",\n\n      // The following settings help to eliminate DNS poisoning in mainland China.\n      // It is safe to comment these out if this is not the case for you.\n      \"domain:github.io\": \"pages.github.com\",\n      \"domain:wikipedia.org\": \"www.wikimedia.org\",\n      \"domain:shadowsocks.org\": \"electronicsrealm.com\"\n    },\n    \"servers\": [\n      \"1.1.1.1\",\n      {\n        \"address\": \"114.114.114.114\",\n        \"port\": 53,\n        // List of domains that use this DNS first.\n        \"domains\": [\n          \"geosite:cn\"\n        ]\n      },\n      \"8.8.8.8\",\n      \"localhost\"\n    ]\n  },\n\n  // Policy controls some internal behavior of how V2Ray handles connections.\n  // It may be on connection level by user levels in 'levels', or global settings in 'system.'\n  \"policy\": {\n    // Connection policys by user levels\n    \"levels\": {\n      \"0\": {\n        \"uplinkOnly\": 0,\n        \"downlinkOnly\": 0\n      }\n    },\n    \"system\": {\n      \"statsInboundUplink\": false,\n      \"statsInboundDownlink\": false,\n      \"statsOutboundUplink\": false,\n      \"statsOutboundDownlink\": false\n    }\n  },\n\n  // Stats enables internal stats counter.\n  // This setting can be used together with Policy and Api. \n  //\"stats\":{},\n\n  // Api enables gRPC APIs for external programs to communicate with V2Ray instance.\n  //\"api\": {\n    //\"tag\": \"api\",\n    //\"services\": [\n    //  \"HandlerService\",\n    //  \"LoggerService\",\n    //  \"StatsService\"\n    //]\n  //},\n\n  // You may add other entries to the configuration, but they will not be recognized by V2Ray.\n  \"other\": {}\n}\n"
  },
  {
    "path": "release/config/systemd/system/v2ray.service",
    "content": "[Unit]\nDescription=V2Ray Service\nDocumentation=https://www.v2fly.org/\nAfter=network.target nss-lookup.target\n\n[Service]\nUser=nobody\nCapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE\nAmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE\nNoNewPrivileges=true\nExecStart=/usr/local/bin/v2ray -config /usr/local/etc/v2ray/config.json\nRestart=on-failure\nRestartPreventExitStatus=23\n\n[Install]\nWantedBy=multi-user.target\n"
  },
  {
    "path": "release/config/systemd/system/v2ray@.service",
    "content": "[Unit]\nDescription=V2Ray Service\nDocumentation=https://www.v2fly.org/\nAfter=network.target nss-lookup.target\n\n[Service]\nUser=nobody\nCapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE\nAmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE\nNoNewPrivileges=true\nExecStart=/usr/local/bin/v2ray -config /usr/local/etc/v2ray/%i.json\nRestart=on-failure\nRestartPreventExitStatus=23\n\n[Install]\nWantedBy=multi-user.target\n"
  },
  {
    "path": "release/config/vpoint_socks_vmess.json",
    "content": "{\n  \"log\": {\n    \"loglevel\": \"warning\"\n  },\n  \"inbounds\": [{\n    \"port\": 1080,\n    \"listen\": \"127.0.0.1\",\n    \"protocol\": \"socks\",\n    \"settings\": {\n      \"auth\": \"noauth\",\n      \"udp\": false,\n      \"ip\": \"127.0.0.1\"\n    }\n  }],\n  \"outbounds\": [{\n    \"protocol\": \"freedom\",\n    \"settings\": {},\n    \"tag\": \"direct\"\n  }],\n  \"policy\": {\n    \"levels\": {\n      \"0\": {\"uplinkOnly\": 0}\n    }\n  }\n}\n"
  },
  {
    "path": "release/config/vpoint_vmess_freedom.json",
    "content": "{\n  \"inbounds\": [{\n    \"port\": 10086,\n    \"protocol\": \"vmess\",\n    \"settings\": {\n      \"clients\": [\n        {\n          \"id\": \"23ad6b10-8d1a-40f7-8ad0-e3e35cd38297\",\n          \"level\": 1,\n          \"alterId\": 64\n        }\n      ]\n    }\n  }],\n  \"outbounds\": [{\n    \"protocol\": \"freedom\",\n    \"settings\": {}\n  },{\n    \"protocol\": \"blackhole\",\n    \"settings\": {},\n    \"tag\": \"blocked\"\n  }],\n  \"routing\": {\n    \"rules\": [\n      {\n        \"type\": \"field\",\n        \"ip\": [\"geoip:private\"],\n        \"outboundTag\": \"blocked\"\n      }\n    ]\n  }\n}\n"
  },
  {
    "path": "release/install-release.sh",
    "content": "#!/usr/bin/env bash\n\n# This file is accessible as https://install.direct/go.sh\n# Original source is located at github.com/v2fly/v2ray-core/release/install-release.sh\n\n# If not specify, default meaning of return value:\n# 0: Success\n# 1: System error\n# 2: Application error\n# 3: Network error\n\n#######color code########\nRED=\"31m\"      # Error message\nYELLOW=\"33m\"   # Warning message\ncolorEcho(){\n    echo -e \"\\033[${1}${@:2}\\033[0m\" 1>& 2\n}\n\ncolorEcho ${RED} \"ERROR: This script has been DISCARDED, please switch to fhs-install-v2ray project.\"\ncolorEcho ${YELLOW} \"HOW TO USE: https://github.com/v2fly/fhs-install-v2ray\"\ncolorEcho ${YELLOW} \"TO MIGRATE: https://github.com/v2fly/fhs-install-v2ray/wiki/Migrate-from-the-old-script-to-this\"\nexit 255\n"
  },
  {
    "path": "release/mapping.bzl",
    "content": "def gen_mappings(os, arch, ver):\n  return {\n    \"v2ray_core/release/config\": \"\",\n    \"v2ray_core/main/\" + os + \"/\" + arch + \"/\" + ver: \"\",\n    \"v2ray_core/infra/control/main/\" + os + \"/\" + arch + \"/\" + ver : \"\",\n  }\n"
  },
  {
    "path": "release/mutilate/removeVSign.sh",
    "content": "#!/usr/bin/env bash\n\nexport VROOT=$(dirname \"${BASH_SOURCE[0]}\")/../../\n\nrm $VROOT/infra/control/verify.go\n\nsed -i '/VSign/d' $VROOT/go.mod\n"
  },
  {
    "path": "release/requestsign.sh",
    "content": "#!/usr/bin/env bash\n\nRELEASE_DATA=$(curl --data \"version=${SIGN_VERSION}\" --data \"password=${SIGN_SERVICE_PASSWORD}\" -X POST \"${SIGN_SERIVCE_URL}\" )\necho $RELEASE_DATA\nRELEASE_ID=$(echo $RELEASE_DATA| jq -r \".id\")\n\nfunction uploadfile() {\n  FILE=$1\n  CTYPE=$(file -b --mime-type $FILE)\n\n  sleep 1\n  curl -H \"Authorization: token ${GITHUB_TOKEN}\" -H \"Content-Type: ${CTYPE}\" --data-binary @$FILE \"https://uploads.github.com/repos/v2fly/v2ray-core/releases/${RELEASE_ID}/assets?name=$(basename $FILE)\"\n  sleep 1\n}\n\nfunction upload() {\n  FILE=$1\n  DGST=$1.dgst\n  openssl dgst -md5 $FILE | sed 's/([^)]*)//g' >> $DGST\n  openssl dgst -sha1 $FILE | sed 's/([^)]*)//g' >> $DGST\n  openssl dgst -sha256 $FILE | sed 's/([^)]*)//g' >> $DGST\n  openssl dgst -sha512 $FILE | sed 's/([^)]*)//g' >> $DGST\n  uploadfile $FILE\n  uploadfile $DGST\n}\n\ncurl \"https://raw.githubusercontent.com/v2fly/Release/master/v2fly/${SIGN_VERSION}.Release\" > Release\nupload Release\n"
  },
  {
    "path": "release/requestsign_github.sh",
    "content": "#!/usr/bin/env bash\n\nexport SIGN_VERSION=$(cat $GITHUB_EVENT_PATH| jq -r \".release.tag_name\")\n\necho $SIGN_VERSION\n\n$GITHUB_WORKSPACE/release/requestsign.sh\n"
  },
  {
    "path": "release/tagrelease.sh",
    "content": "#!/usr/bin/env bash\n\nCONST_refs=\"refs\"\n\nTRIGGER_REASON_A=${TRIGGER_REASON:0:${#CONST_refs}}\n\nif [ $TRIGGER_REASON_A != $CONST_refs ]; then\n  echo \"not a tag: $TRIGGER_REASON_A\"\n  exit\nfi\n\nCONST_refsB=\"refs/tags/\"\n\nTRIGGER_REASON_B=${TRIGGER_REASON:0:${#CONST_refsB}}\n\nif [ $TRIGGER_REASON_B != $CONST_refsB ]; then\n  echo \"not a tag (B)\"\n  exit\nfi\n\nGITHUB_RELEASE_TAG=${TRIGGER_REASON:${#CONST_refsB}:25}\n\necho ${GITHUB_RELEASE_TAG}\n\nRELEASE_DATA=$(curl -H \"Authorization: token ${GITHUB_TOKEN}\" -X GET https://api.github.com/repos/v2fly/v2ray-core/releases/tags/${GITHUB_RELEASE_TAG})\necho $RELEASE_DATA\nRELEASE_ID=$(echo $RELEASE_DATA | jq \".id\")\n\necho $RELEASE_ID\n\nfunction uploadfile() {\n  FILE=$1\n  CTYPE=$(file -b --mime-type $FILE)\n\n  sleep 1\n  curl -H \"Authorization: token ${GITHUB_TOKEN}\" -H \"Content-Type: ${CTYPE}\" --data-binary @$FILE \"https://uploads.github.com/repos/v2fly/v2ray-core/releases/${RELEASE_ID}/assets?name=$(basename $FILE)\"\n  sleep 1\n}\n\nfunction upload() {\n  FILE=$1\n  DGST=$1.dgst\n  openssl dgst -md5 $FILE | sed 's/([^)]*)//g' >>$DGST\n  openssl dgst -sha1 $FILE | sed 's/([^)]*)//g' >>$DGST\n  openssl dgst -sha256 $FILE | sed 's/([^)]*)//g' >>$DGST\n  openssl dgst -sha512 $FILE | sed 's/([^)]*)//g' >>$DGST\n  uploadfile $FILE\n  uploadfile $DGST\n}\n\nART_ROOT=${WORKDIR}/bazel-bin/release\n\npushd ${ART_ROOT}\n{\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen version \"${GITHUB_RELEASE_TAG}\"\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen project \"v2fly\"\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-macos-64.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-windows-64.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-windows-32.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-windows-arm32-v7a.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-64.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-32.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-arm64-v8a.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-arm32-v7a.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-arm32-v6.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-arm32-v5.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-mips64.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-mips64le.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-mips32.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-mips32le.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-ppc64.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-ppc64le.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-riscv64.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-s390x.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-freebsd-64.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-freebsd-32.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-openbsd-64.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-openbsd-32.zip\n  go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-dragonfly-64.zip\n} >Release.unsigned.unsorted\ngo run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen sort <Release.unsigned.unsorted >Release.unsigned\n\npopd\n\nupload ${ART_ROOT}/v2ray-macos-64.zip\nupload ${ART_ROOT}/v2ray-windows-64.zip\nupload ${ART_ROOT}/v2ray-windows-32.zip\nupload ${ART_ROOT}/v2ray-windows-arm32-v7a.zip\nupload ${ART_ROOT}/v2ray-linux-64.zip\nupload ${ART_ROOT}/v2ray-linux-32.zip\nupload ${ART_ROOT}/v2ray-linux-arm64-v8a.zip\nupload ${ART_ROOT}/v2ray-linux-arm32-v7a.zip\nupload ${ART_ROOT}/v2ray-linux-arm32-v6.zip\nupload ${ART_ROOT}/v2ray-linux-arm32-v5.zip\nupload ${ART_ROOT}/v2ray-linux-mips64.zip\nupload ${ART_ROOT}/v2ray-linux-mips64le.zip\nupload ${ART_ROOT}/v2ray-linux-mips32.zip\nupload ${ART_ROOT}/v2ray-linux-mips32le.zip\nupload ${ART_ROOT}/v2ray-linux-ppc64.zip\nupload ${ART_ROOT}/v2ray-linux-ppc64le.zip\nupload ${ART_ROOT}/v2ray-linux-riscv64.zip\nupload ${ART_ROOT}/v2ray-linux-s390x.zip\nupload ${ART_ROOT}/v2ray-freebsd-64.zip\nupload ${ART_ROOT}/v2ray-freebsd-32.zip\nupload ${ART_ROOT}/v2ray-openbsd-64.zip\nupload ${ART_ROOT}/v2ray-openbsd-32.zip\nupload ${ART_ROOT}/v2ray-dragonfly-64.zip\nupload ${ART_ROOT}/Release.unsigned\n"
  },
  {
    "path": "release/user-package.sh",
    "content": "#!/usr/bin/env bash\n\nset -o errexit\nset -o pipefail\nset -o nounset\n# set -o xtrace\n\ntrap 'echo -e \"Aborted, error $? in command: $BASH_COMMAND\"; trap ERR; exit 1' ERR\n\nNOW=$(date '+%Y%m%d-%H%M%S')\nTMP=$(mktemp -d)\nSRCDIR=$(pwd)\n\nCODENAME=\"user\"\nBUILDNAME=$NOW\n\ncleanup() { rm -rf \"$TMP\"; }\ntrap cleanup INT TERM ERR\n\nget_source() {\n\techo \">>> Clone v2fly/v2ray-core repo...\"\n\tgit clone https://github.com/v2fly/v2ray-core.git\n\tcd v2ray-core\n\tgo mod download\n}\n\nbuild_v2() {\n\tif [[ $nosource != 1 ]]; then\n\t\tcd ${SRCDIR}/v2ray-core\n\t\tlocal VERSIONTAG=$(git describe --abbrev=0 --tags)\n\telse\n\t\techo \">>> Use current directory as WORKDIR\"\n\t\tlocal VERSIONTAG=$(git describe --abbrev=0 --tags)\n\tfi\n\n\tLDFLAGS=\"-s -w -buildid= -X v2ray.codename=${CODENAME} -X v2ray.build=${BUILDNAME} -X v2ray.version=${VERSIONTAG}\"\n\n\techo \">>> Compile v2ray ...\"\n\tenv CGO_ENABLED=0 go build -o \"$TMP\"/v2ray\"${EXESUFFIX}\" -ldflags \"$LDFLAGS\" ./main\n\tif [[ $GOOS == \"windows\" ]]; then\n\t\tenv CGO_ENABLED=0 go build -o \"$TMP\"/wv2ray\"${EXESUFFIX}\" -ldflags \"-H windowsgui $LDFLAGS\" ./main\n\tfi\n\n\techo \">>> Compile v2ctl ...\"\n\tenv CGO_ENABLED=0 go build -o \"$TMP\"/v2ctl\"${EXESUFFIX}\" -tags confonly -ldflags \"$LDFLAGS\" ./infra/control/main\n}\n\nbuild_dat() {\n\techo \">>> Download latest geoip...\"\n\tcurl -s -L -o \"$TMP\"/geoip.dat \"https://github.com/v2fly/geoip/raw/release/geoip.dat\"\n\n\techo \">>> Download latest geosite...\"\n\tcurl -s -L -o \"$TMP\"/geosite.dat \"https://github.com/v2fly/domain-list-community/raw/release/dlc.dat\"\n}\n\ncopyconf() {\n\techo \">>> Copying config...\"\n\tcd ./release/config\n\tif [[ $GOOS == \"linux\" ]]; then\n\t\ttar c --exclude \"*.dat\" . | tar x -C \"$TMP\"\n\telse\n\t\ttar c --exclude \"*.dat\" --exclude \"systemd/**\" . | tar x -C \"$TMP\"\n\tfi\n}\n\npackzip() {\n\techo \">>> Generating zip package\"\n\tcd \"$TMP\"\n\tlocal PKG=${SRCDIR}/v2ray-custom-${GOARCH}-${GOOS}-${PKGSUFFIX}${NOW}.zip\n\tzip -r \"$PKG\" .\n\techo \">>> Generated: $(basename \"$PKG\") at $(dirname \"$PKG\")\"\n}\n\npacktgz() {\n\techo \">>> Generating tgz package\"\n\tcd \"$TMP\"\n\tlocal PKG=${SRCDIR}/v2ray-custom-${GOARCH}-${GOOS}-${PKGSUFFIX}${NOW}.tar.gz\n\ttar cvfz \"$PKG\" .\n\techo \">>> Generated: $(basename \"$PKG\") at $(dirname \"$PKG\")\"\n}\n\npacktgzAbPath() {\n\tlocal ABPATH=\"$1\"\n\techo \">>> Generating tgz package at $ABPATH\"\n\tcd \"$TMP\"\n\ttar cvfz \"$ABPATH\" .\n\techo \">>> Generated: $ABPATH\"\n}\n\npkg=zip\nnosource=0\nnodat=0\nnoconf=0\nGOOS=linux\nGOARCH=amd64\nEXESUFFIX=\nPKGSUFFIX=\n\nfor arg in \"$@\"; do\n\tcase $arg in\n\t386 | arm* | mips* | ppc64* | riscv64 | s390x)\n\t\tGOARCH=$arg\n\t\t;;\n\twindows)\n\t\tGOOS=$arg\n\t\tEXESUFFIX=.exe\n\t\t;;\n\tdarwin | dragonfly | freebsd | openbsd)\n\t\tGOOS=$arg\n\t\t;;\n\tnodat)\n\t\tnodat=1\n\t\tPKGSUFFIX=${PKGSUFFIX}nodat-\n\t\t;;\n\tnoconf)\n\t\tnoconf=1\n\t\t;;\n\tnosource)\n\t\tnosource=1\n\t\t;;\n\ttgz)\n\t\tpkg=tgz\n\t\t;;\n\tabpathtgz=*)\n\t\tpkg=${arg##abpathtgz=}\n\t\t;;\n\tcodename=*)\n\t\tCODENAME=${arg##codename=}\n\t\t;;\n\tbuildname=*)\n\t\tBUILDNAME=${arg##buildname=}\n\t\t;;\n\tesac\ndone\n\nif [[ $nosource != 1 ]]; then\n\tget_source\nfi\n\nexport GOOS GOARCH\necho \"Build ARGS: GOOS=${GOOS} GOARCH=${GOARCH} CODENAME=${CODENAME} BUILDNAME=${BUILDNAME}\"\necho \"PKG ARGS: pkg=${pkg}\"\nbuild_v2\n\nif [[ $nodat != 1 ]]; then\n\tbuild_dat\nfi\n\nif [[ $noconf != 1 ]]; then\n\tcopyconf\nfi\n\nif [[ $pkg == \"zip\" ]]; then\n\tpackzip\nelif [[ $pkg == \"tgz\" ]]; then\n\tpacktgz\nelse\n\tpacktgzAbPath \"$pkg\"\nfi\n\ncleanup\n"
  },
  {
    "path": "testing/coverage/coverall",
    "content": "#!/bin/bash\n\nFAIL=0\n\nV2RAY_OUT=${PWD}/out/v2ray\nexport V2RAY_COV=${V2RAY_OUT}/cov\nCOVERAGE_FILE=${V2RAY_COV}/coverage.txt\n\nfunction test_package {\n  DIR=\".$1\"\n  DEP=$(go list -f '{{ join .Deps \"\\n\" }}' $DIR | grep v2ray | tr '\\n' ',')\n  DEP=${DEP}$DIR\n  RND_NAME=$(openssl rand -hex 16)\n  COV_PROFILE=${V2RAY_COV}/${RND_NAME}.out\n  go test -tags \"json coverage\" -coverprofile=${COV_PROFILE} -coverpkg=$DEP $DIR || FAIL=1\n}\n\nrm -rf ${V2RAY_OUT}\nmkdir -p ${V2RAY_COV}\ntouch ${COVERAGE_FILE}\n\nTEST_FILES=(./*_test.go)\nif [ -f ${TEST_FILES[0]} ]; then\n  test_package \"\"\nfi\n\nfor DIR in $(find * -type d ! -path \"*.git*\" ! -path \"*vendor*\" ! -path \"*external*\"); do\n  TEST_FILES=($DIR/*_test.go)\n  if [ -f ${TEST_FILES[0]} ]; then\n    test_package \"/$DIR\"\n  fi\ndone\n\nfor OUT_FILE in $(find ${V2RAY_COV} -name \"*.out\"); do\n  echo \"Merging file ${OUT_FILE}\"\n  cat ${OUT_FILE} | grep -v \"mode: set\" >> ${COVERAGE_FILE}\ndone\n\nCOV_SORTED=${V2RAY_COV}/coverallsorted.out\ncat ${COVERAGE_FILE} | sort -t: -k1 | grep -vw \"testing\" | grep -v \".pb.go\" | grep -vw \"vendor\" | grep -vw \"external\" > ${COV_SORTED}\necho \"mode: set\" | cat - ${COV_SORTED} > ${COVERAGE_FILE}\n\nif [ \"$FAIL\" -eq 0 ]; then\n  echo \"Uploading coverage datea to codecov.\"\n  #bash <(curl -s https://codecov.io/bash) -f ${COVERAGE_FILE} -v || echo \"Codecov did not collect coverage reports.\"\nfi\n\nexit $FAIL\n"
  },
  {
    "path": "testing/coverage/coverall2",
    "content": "#!/bin/bash\n\nCOVERAGE_FILE=${PWD}/coverage.txt\nCOV_SORTED=${PWD}/coverallsorted.out\n\ntouch \"$COVERAGE_FILE\"\n\nfunction test_package {\n  DIR=\".$1\"\n  DEP=$(go list -f '{{ join .Deps \"\\n\" }}' \"$DIR\" | grep v2ray | tr '\\n' ',')\n  DEP=${DEP}$DIR\n  RND_NAME=$(openssl rand -hex 16)\n  COV_PROFILE=${RND_NAME}.out\n  go test -coverprofile=\"$COV_PROFILE\" -coverpkg=\"$DEP\" \"$DIR\" || return\n}\n\nTEST_FILES=(./*_test.go)\nif [ -f \"${TEST_FILES[0]}\" ]; then\n  test_package \"\"\nfi\n\n# shellcheck disable=SC2044\nfor DIR in $(find ./* -type d ! -path \"*.git*\" ! -path \"*vendor*\" ! -path \"*external*\"); do\n  TEST_FILES=(\"$DIR\"/*_test.go)\n  if [ -f \"${TEST_FILES[0]}\" ]; then\n    test_package \"/$DIR\"\n  fi\ndone\n\n# merge out\nwhile IFS= read -r -d '' OUT_FILE\ndo\n  echo \"Merging file ${OUT_FILE}\"\n  < \"${OUT_FILE}\" grep -v \"mode: set\" >> \"$COVERAGE_FILE\"\ndone <   <(find ./* -name \"*.out\" -print0)\n\n< \"$COVERAGE_FILE\" sort -t: -k1 | grep -vw \"testing\" | grep -v \".pb.go\" | grep -vw \"vendor\" | grep -vw \"external\" > \"$COV_SORTED\"\necho \"mode: set\" | cat - \"${COV_SORTED}\" > \"${COVERAGE_FILE}\"\n\nbash <(curl -s https://codecov.io/bash) || echo 'Codecov failed to upload'"
  },
  {
    "path": "testing/mocks/dns.go",
    "content": "// Code generated by MockGen. DO NOT EDIT.\n// Source: v2ray.com/core/features/dns (interfaces: Client)\n\n// Package mocks is a generated GoMock package.\npackage mocks\n\nimport (\n\tgomock \"github.com/golang/mock/gomock\"\n\tnet \"net\"\n\treflect \"reflect\"\n)\n\n// DNSClient is a mock of Client interface\ntype DNSClient struct {\n\tctrl     *gomock.Controller\n\trecorder *DNSClientMockRecorder\n}\n\n// DNSClientMockRecorder is the mock recorder for DNSClient\ntype DNSClientMockRecorder struct {\n\tmock *DNSClient\n}\n\n// NewDNSClient creates a new mock instance\nfunc NewDNSClient(ctrl *gomock.Controller) *DNSClient {\n\tmock := &DNSClient{ctrl: ctrl}\n\tmock.recorder = &DNSClientMockRecorder{mock}\n\treturn mock\n}\n\n// EXPECT returns an object that allows the caller to indicate expected use\nfunc (m *DNSClient) EXPECT() *DNSClientMockRecorder {\n\treturn m.recorder\n}\n\n// Close mocks base method\nfunc (m *DNSClient) Close() error {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Close\")\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// Close indicates an expected call of Close\nfunc (mr *DNSClientMockRecorder) Close() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Close\", reflect.TypeOf((*DNSClient)(nil).Close))\n}\n\n// LookupIP mocks base method\nfunc (m *DNSClient) LookupIP(arg0 string) ([]net.IP, error) {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"LookupIP\", arg0)\n\tret0, _ := ret[0].([]net.IP)\n\tret1, _ := ret[1].(error)\n\treturn ret0, ret1\n}\n\n// LookupIP indicates an expected call of LookupIP\nfunc (mr *DNSClientMockRecorder) LookupIP(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"LookupIP\", reflect.TypeOf((*DNSClient)(nil).LookupIP), arg0)\n}\n\n// Start mocks base method\nfunc (m *DNSClient) Start() error {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Start\")\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// Start indicates an expected call of Start\nfunc (mr *DNSClientMockRecorder) Start() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Start\", reflect.TypeOf((*DNSClient)(nil).Start))\n}\n\n// Type mocks base method\nfunc (m *DNSClient) Type() interface{} {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Type\")\n\tret0, _ := ret[0].(interface{})\n\treturn ret0\n}\n\n// Type indicates an expected call of Type\nfunc (mr *DNSClientMockRecorder) Type() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Type\", reflect.TypeOf((*DNSClient)(nil).Type))\n}\n"
  },
  {
    "path": "testing/mocks/io.go",
    "content": "// Code generated by MockGen. DO NOT EDIT.\n// Source: io (interfaces: Reader,Writer)\n\n// Package mocks is a generated GoMock package.\npackage mocks\n\nimport (\n\tgomock \"github.com/golang/mock/gomock\"\n\treflect \"reflect\"\n)\n\n// Reader is a mock of Reader interface\ntype Reader struct {\n\tctrl     *gomock.Controller\n\trecorder *ReaderMockRecorder\n}\n\n// ReaderMockRecorder is the mock recorder for Reader\ntype ReaderMockRecorder struct {\n\tmock *Reader\n}\n\n// NewReader creates a new mock instance\nfunc NewReader(ctrl *gomock.Controller) *Reader {\n\tmock := &Reader{ctrl: ctrl}\n\tmock.recorder = &ReaderMockRecorder{mock}\n\treturn mock\n}\n\n// EXPECT returns an object that allows the caller to indicate expected use\nfunc (m *Reader) EXPECT() *ReaderMockRecorder {\n\treturn m.recorder\n}\n\n// Read mocks base method\nfunc (m *Reader) Read(arg0 []byte) (int, error) {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Read\", arg0)\n\tret0, _ := ret[0].(int)\n\tret1, _ := ret[1].(error)\n\treturn ret0, ret1\n}\n\n// Read indicates an expected call of Read\nfunc (mr *ReaderMockRecorder) Read(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Read\", reflect.TypeOf((*Reader)(nil).Read), arg0)\n}\n\n// Writer is a mock of Writer interface\ntype Writer struct {\n\tctrl     *gomock.Controller\n\trecorder *WriterMockRecorder\n}\n\n// WriterMockRecorder is the mock recorder for Writer\ntype WriterMockRecorder struct {\n\tmock *Writer\n}\n\n// NewWriter creates a new mock instance\nfunc NewWriter(ctrl *gomock.Controller) *Writer {\n\tmock := &Writer{ctrl: ctrl}\n\tmock.recorder = &WriterMockRecorder{mock}\n\treturn mock\n}\n\n// EXPECT returns an object that allows the caller to indicate expected use\nfunc (m *Writer) EXPECT() *WriterMockRecorder {\n\treturn m.recorder\n}\n\n// Write mocks base method\nfunc (m *Writer) Write(arg0 []byte) (int, error) {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Write\", arg0)\n\tret0, _ := ret[0].(int)\n\tret1, _ := ret[1].(error)\n\treturn ret0, ret1\n}\n\n// Write indicates an expected call of Write\nfunc (mr *WriterMockRecorder) Write(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Write\", reflect.TypeOf((*Writer)(nil).Write), arg0)\n}\n"
  },
  {
    "path": "testing/mocks/log.go",
    "content": "// Code generated by MockGen. DO NOT EDIT.\n// Source: v2ray.com/core/common/log (interfaces: Handler)\n\n// Package mocks is a generated GoMock package.\npackage mocks\n\nimport (\n\tgomock \"github.com/golang/mock/gomock\"\n\treflect \"reflect\"\n\tlog \"v2ray.com/core/common/log\"\n)\n\n// LogHandler is a mock of Handler interface\ntype LogHandler struct {\n\tctrl     *gomock.Controller\n\trecorder *LogHandlerMockRecorder\n}\n\n// LogHandlerMockRecorder is the mock recorder for LogHandler\ntype LogHandlerMockRecorder struct {\n\tmock *LogHandler\n}\n\n// NewLogHandler creates a new mock instance\nfunc NewLogHandler(ctrl *gomock.Controller) *LogHandler {\n\tmock := &LogHandler{ctrl: ctrl}\n\tmock.recorder = &LogHandlerMockRecorder{mock}\n\treturn mock\n}\n\n// EXPECT returns an object that allows the caller to indicate expected use\nfunc (m *LogHandler) EXPECT() *LogHandlerMockRecorder {\n\treturn m.recorder\n}\n\n// Handle mocks base method\nfunc (m *LogHandler) Handle(arg0 log.Message) {\n\tm.ctrl.T.Helper()\n\tm.ctrl.Call(m, \"Handle\", arg0)\n}\n\n// Handle indicates an expected call of Handle\nfunc (mr *LogHandlerMockRecorder) Handle(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Handle\", reflect.TypeOf((*LogHandler)(nil).Handle), arg0)\n}\n"
  },
  {
    "path": "testing/mocks/mux.go",
    "content": "// Code generated by MockGen. DO NOT EDIT.\n// Source: v2ray.com/core/common/mux (interfaces: ClientWorkerFactory)\n\n// Package mocks is a generated GoMock package.\npackage mocks\n\nimport (\n\tgomock \"github.com/golang/mock/gomock\"\n\treflect \"reflect\"\n\tmux \"v2ray.com/core/common/mux\"\n)\n\n// MuxClientWorkerFactory is a mock of ClientWorkerFactory interface\ntype MuxClientWorkerFactory struct {\n\tctrl     *gomock.Controller\n\trecorder *MuxClientWorkerFactoryMockRecorder\n}\n\n// MuxClientWorkerFactoryMockRecorder is the mock recorder for MuxClientWorkerFactory\ntype MuxClientWorkerFactoryMockRecorder struct {\n\tmock *MuxClientWorkerFactory\n}\n\n// NewMuxClientWorkerFactory creates a new mock instance\nfunc NewMuxClientWorkerFactory(ctrl *gomock.Controller) *MuxClientWorkerFactory {\n\tmock := &MuxClientWorkerFactory{ctrl: ctrl}\n\tmock.recorder = &MuxClientWorkerFactoryMockRecorder{mock}\n\treturn mock\n}\n\n// EXPECT returns an object that allows the caller to indicate expected use\nfunc (m *MuxClientWorkerFactory) EXPECT() *MuxClientWorkerFactoryMockRecorder {\n\treturn m.recorder\n}\n\n// Create mocks base method\nfunc (m *MuxClientWorkerFactory) Create() (*mux.ClientWorker, error) {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Create\")\n\tret0, _ := ret[0].(*mux.ClientWorker)\n\tret1, _ := ret[1].(error)\n\treturn ret0, ret1\n}\n\n// Create indicates an expected call of Create\nfunc (mr *MuxClientWorkerFactoryMockRecorder) Create() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Create\", reflect.TypeOf((*MuxClientWorkerFactory)(nil).Create))\n}\n"
  },
  {
    "path": "testing/mocks/outbound.go",
    "content": "// Code generated by MockGen. DO NOT EDIT.\n// Source: v2ray.com/core/features/outbound (interfaces: Manager,HandlerSelector)\n\n// Package mocks is a generated GoMock package.\npackage mocks\n\nimport (\n\tcontext \"context\"\n\tgomock \"github.com/golang/mock/gomock\"\n\treflect \"reflect\"\n\toutbound \"v2ray.com/core/features/outbound\"\n)\n\n// OutboundManager is a mock of Manager interface\ntype OutboundManager struct {\n\tctrl     *gomock.Controller\n\trecorder *OutboundManagerMockRecorder\n}\n\n// OutboundManagerMockRecorder is the mock recorder for OutboundManager\ntype OutboundManagerMockRecorder struct {\n\tmock *OutboundManager\n}\n\n// NewOutboundManager creates a new mock instance\nfunc NewOutboundManager(ctrl *gomock.Controller) *OutboundManager {\n\tmock := &OutboundManager{ctrl: ctrl}\n\tmock.recorder = &OutboundManagerMockRecorder{mock}\n\treturn mock\n}\n\n// EXPECT returns an object that allows the caller to indicate expected use\nfunc (m *OutboundManager) EXPECT() *OutboundManagerMockRecorder {\n\treturn m.recorder\n}\n\n// AddHandler mocks base method\nfunc (m *OutboundManager) AddHandler(arg0 context.Context, arg1 outbound.Handler) error {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"AddHandler\", arg0, arg1)\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// AddHandler indicates an expected call of AddHandler\nfunc (mr *OutboundManagerMockRecorder) AddHandler(arg0, arg1 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"AddHandler\", reflect.TypeOf((*OutboundManager)(nil).AddHandler), arg0, arg1)\n}\n\n// Close mocks base method\nfunc (m *OutboundManager) Close() error {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Close\")\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// Close indicates an expected call of Close\nfunc (mr *OutboundManagerMockRecorder) Close() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Close\", reflect.TypeOf((*OutboundManager)(nil).Close))\n}\n\n// GetDefaultHandler mocks base method\nfunc (m *OutboundManager) GetDefaultHandler() outbound.Handler {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"GetDefaultHandler\")\n\tret0, _ := ret[0].(outbound.Handler)\n\treturn ret0\n}\n\n// GetDefaultHandler indicates an expected call of GetDefaultHandler\nfunc (mr *OutboundManagerMockRecorder) GetDefaultHandler() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"GetDefaultHandler\", reflect.TypeOf((*OutboundManager)(nil).GetDefaultHandler))\n}\n\n// GetHandler mocks base method\nfunc (m *OutboundManager) GetHandler(arg0 string) outbound.Handler {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"GetHandler\", arg0)\n\tret0, _ := ret[0].(outbound.Handler)\n\treturn ret0\n}\n\n// GetHandler indicates an expected call of GetHandler\nfunc (mr *OutboundManagerMockRecorder) GetHandler(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"GetHandler\", reflect.TypeOf((*OutboundManager)(nil).GetHandler), arg0)\n}\n\n// RemoveHandler mocks base method\nfunc (m *OutboundManager) RemoveHandler(arg0 context.Context, arg1 string) error {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"RemoveHandler\", arg0, arg1)\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// RemoveHandler indicates an expected call of RemoveHandler\nfunc (mr *OutboundManagerMockRecorder) RemoveHandler(arg0, arg1 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"RemoveHandler\", reflect.TypeOf((*OutboundManager)(nil).RemoveHandler), arg0, arg1)\n}\n\n// Start mocks base method\nfunc (m *OutboundManager) Start() error {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Start\")\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// Start indicates an expected call of Start\nfunc (mr *OutboundManagerMockRecorder) Start() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Start\", reflect.TypeOf((*OutboundManager)(nil).Start))\n}\n\n// Type mocks base method\nfunc (m *OutboundManager) Type() interface{} {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Type\")\n\tret0, _ := ret[0].(interface{})\n\treturn ret0\n}\n\n// Type indicates an expected call of Type\nfunc (mr *OutboundManagerMockRecorder) Type() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Type\", reflect.TypeOf((*OutboundManager)(nil).Type))\n}\n\n// OutboundHandlerSelector is a mock of HandlerSelector interface\ntype OutboundHandlerSelector struct {\n\tctrl     *gomock.Controller\n\trecorder *OutboundHandlerSelectorMockRecorder\n}\n\n// OutboundHandlerSelectorMockRecorder is the mock recorder for OutboundHandlerSelector\ntype OutboundHandlerSelectorMockRecorder struct {\n\tmock *OutboundHandlerSelector\n}\n\n// NewOutboundHandlerSelector creates a new mock instance\nfunc NewOutboundHandlerSelector(ctrl *gomock.Controller) *OutboundHandlerSelector {\n\tmock := &OutboundHandlerSelector{ctrl: ctrl}\n\tmock.recorder = &OutboundHandlerSelectorMockRecorder{mock}\n\treturn mock\n}\n\n// EXPECT returns an object that allows the caller to indicate expected use\nfunc (m *OutboundHandlerSelector) EXPECT() *OutboundHandlerSelectorMockRecorder {\n\treturn m.recorder\n}\n\n// Select mocks base method\nfunc (m *OutboundHandlerSelector) Select(arg0 []string) []string {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Select\", arg0)\n\tret0, _ := ret[0].([]string)\n\treturn ret0\n}\n\n// Select indicates an expected call of Select\nfunc (mr *OutboundHandlerSelectorMockRecorder) Select(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Select\", reflect.TypeOf((*OutboundHandlerSelector)(nil).Select), arg0)\n}\n"
  },
  {
    "path": "testing/mocks/proxy.go",
    "content": "// Code generated by MockGen. DO NOT EDIT.\n// Source: v2ray.com/core/proxy (interfaces: Inbound,Outbound)\n\n// Package mocks is a generated GoMock package.\npackage mocks\n\nimport (\n\tcontext \"context\"\n\tgomock \"github.com/golang/mock/gomock\"\n\treflect \"reflect\"\n\tnet \"v2ray.com/core/common/net\"\n\trouting \"v2ray.com/core/features/routing\"\n\ttransport \"v2ray.com/core/transport\"\n\tinternet \"v2ray.com/core/transport/internet\"\n)\n\n// ProxyInbound is a mock of Inbound interface\ntype ProxyInbound struct {\n\tctrl     *gomock.Controller\n\trecorder *ProxyInboundMockRecorder\n}\n\n// ProxyInboundMockRecorder is the mock recorder for ProxyInbound\ntype ProxyInboundMockRecorder struct {\n\tmock *ProxyInbound\n}\n\n// NewProxyInbound creates a new mock instance\nfunc NewProxyInbound(ctrl *gomock.Controller) *ProxyInbound {\n\tmock := &ProxyInbound{ctrl: ctrl}\n\tmock.recorder = &ProxyInboundMockRecorder{mock}\n\treturn mock\n}\n\n// EXPECT returns an object that allows the caller to indicate expected use\nfunc (m *ProxyInbound) EXPECT() *ProxyInboundMockRecorder {\n\treturn m.recorder\n}\n\n// Network mocks base method\nfunc (m *ProxyInbound) Network() []net.Network {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Network\")\n\tret0, _ := ret[0].([]net.Network)\n\treturn ret0\n}\n\n// Network indicates an expected call of Network\nfunc (mr *ProxyInboundMockRecorder) Network() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Network\", reflect.TypeOf((*ProxyInbound)(nil).Network))\n}\n\n// Process mocks base method\nfunc (m *ProxyInbound) Process(arg0 context.Context, arg1 net.Network, arg2 internet.Connection, arg3 routing.Dispatcher) error {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Process\", arg0, arg1, arg2, arg3)\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// Process indicates an expected call of Process\nfunc (mr *ProxyInboundMockRecorder) Process(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Process\", reflect.TypeOf((*ProxyInbound)(nil).Process), arg0, arg1, arg2, arg3)\n}\n\n// ProxyOutbound is a mock of Outbound interface\ntype ProxyOutbound struct {\n\tctrl     *gomock.Controller\n\trecorder *ProxyOutboundMockRecorder\n}\n\n// ProxyOutboundMockRecorder is the mock recorder for ProxyOutbound\ntype ProxyOutboundMockRecorder struct {\n\tmock *ProxyOutbound\n}\n\n// NewProxyOutbound creates a new mock instance\nfunc NewProxyOutbound(ctrl *gomock.Controller) *ProxyOutbound {\n\tmock := &ProxyOutbound{ctrl: ctrl}\n\tmock.recorder = &ProxyOutboundMockRecorder{mock}\n\treturn mock\n}\n\n// EXPECT returns an object that allows the caller to indicate expected use\nfunc (m *ProxyOutbound) EXPECT() *ProxyOutboundMockRecorder {\n\treturn m.recorder\n}\n\n// Process mocks base method\nfunc (m *ProxyOutbound) Process(arg0 context.Context, arg1 *transport.Link, arg2 internet.Dialer) error {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Process\", arg0, arg1, arg2)\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// Process indicates an expected call of Process\nfunc (mr *ProxyOutboundMockRecorder) Process(arg0, arg1, arg2 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Process\", reflect.TypeOf((*ProxyOutbound)(nil).Process), arg0, arg1, arg2)\n}\n"
  },
  {
    "path": "testing/scenarios/command_test.go",
    "content": "package scenarios\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"github.com/google/go-cmp/cmp/cmpopts\"\n\t\"io\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"google.golang.org/grpc\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/app/commander\"\n\t\"v2ray.com/core/app/policy\"\n\t\"v2ray.com/core/app/proxyman\"\n\t\"v2ray.com/core/app/proxyman/command\"\n\t\"v2ray.com/core/app/router\"\n\t\"v2ray.com/core/app/stats\"\n\tstatscmd \"v2ray.com/core/app/stats/command\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/serial\"\n\t\"v2ray.com/core/common/uuid\"\n\t\"v2ray.com/core/proxy/dokodemo\"\n\t\"v2ray.com/core/proxy/freedom\"\n\t\"v2ray.com/core/proxy/vmess\"\n\t\"v2ray.com/core/proxy/vmess/inbound\"\n\t\"v2ray.com/core/proxy/vmess/outbound\"\n\t\"v2ray.com/core/testing/servers/tcp\"\n)\n\nfunc TestCommanderRemoveHandler(t *testing.T) {\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\tdefer tcpServer.Close()\n\n\tclientPort := tcp.PickPort()\n\tcmdPort := tcp.PickPort()\n\tclientConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&commander.Config{\n\t\t\t\tTag: \"api\",\n\t\t\t\tService: []*serial.TypedMessage{\n\t\t\t\t\tserial.ToTypedMessage(&command.Config{}),\n\t\t\t\t},\n\t\t\t}),\n\t\t\tserial.ToTypedMessage(&router.Config{\n\t\t\t\tRule: []*router.RoutingRule{\n\t\t\t\t\t{\n\t\t\t\t\t\tInboundTag: []string{\"api\"},\n\t\t\t\t\t\tTargetTag: &router.RoutingRule_Tag{\n\t\t\t\t\t\t\tTag: \"api\",\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\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tTag: \"d\",\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(clientPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress:  net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:     uint32(dest.Port),\n\t\t\t\t\tNetworks: []net.Network{net.Network_TCP},\n\t\t\t\t}),\n\t\t\t},\n\t\t\t{\n\t\t\t\tTag: \"api\",\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(cmdPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress:  net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:     uint32(dest.Port),\n\t\t\t\t\tNetworks: []net.Network{net.Network_TCP},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tTag:           \"default-outbound\",\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tservers, err := InitializeServerConfigs(clientConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\tif err := testTCPConn(clientPort, 1024, time.Second*5)(); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tcmdConn, err := grpc.Dial(fmt.Sprintf(\"127.0.0.1:%d\", cmdPort), grpc.WithInsecure(), grpc.WithBlock())\n\tcommon.Must(err)\n\tdefer cmdConn.Close()\n\n\thsClient := command.NewHandlerServiceClient(cmdConn)\n\tresp, err := hsClient.RemoveInbound(context.Background(), &command.RemoveInboundRequest{\n\t\tTag: \"d\",\n\t})\n\tcommon.Must(err)\n\tif resp == nil {\n\t\tt.Error(\"unexpected nil response\")\n\t}\n\n\t{\n\t\t_, err := net.DialTCP(\"tcp\", nil, &net.TCPAddr{\n\t\t\tIP:   []byte{127, 0, 0, 1},\n\t\t\tPort: int(clientPort),\n\t\t})\n\t\tif err == nil {\n\t\t\tt.Error(\"unexpected nil error\")\n\t\t}\n\t}\n}\n\nfunc TestCommanderAddRemoveUser(t *testing.T) {\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\tdefer tcpServer.Close()\n\n\tu1 := protocol.NewID(uuid.New())\n\tu2 := protocol.NewID(uuid.New())\n\n\tcmdPort := tcp.PickPort()\n\tserverPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&commander.Config{\n\t\t\t\tTag: \"api\",\n\t\t\t\tService: []*serial.TypedMessage{\n\t\t\t\t\tserial.ToTypedMessage(&command.Config{}),\n\t\t\t\t},\n\t\t\t}),\n\t\t\tserial.ToTypedMessage(&router.Config{\n\t\t\t\tRule: []*router.RoutingRule{\n\t\t\t\t\t{\n\t\t\t\t\t\tInboundTag: []string{\"api\"},\n\t\t\t\t\t\tTargetTag: &router.RoutingRule_Tag{\n\t\t\t\t\t\t\tTag: \"api\",\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\tserial.ToTypedMessage(&policy.Config{\n\t\t\t\tLevel: map[uint32]*policy.Policy{\n\t\t\t\t\t0: {\n\t\t\t\t\t\tTimeout: &policy.Policy_Timeout{\n\t\t\t\t\t\t\tUplinkOnly:   &policy.Second{Value: 0},\n\t\t\t\t\t\t\tDownlinkOnly: &policy.Second{Value: 0},\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\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tTag: \"v\",\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&inbound.Config{\n\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\tId:      u1.String(),\n\t\t\t\t\t\t\t\tAlterId: 64,\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\t{\n\t\t\t\tTag: \"api\",\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(cmdPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress:  net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:     uint32(dest.Port),\n\t\t\t\t\tNetworks: []net.Network{net.Network_TCP},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tclientPort := tcp.PickPort()\n\tclientConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&policy.Config{\n\t\t\t\tLevel: map[uint32]*policy.Policy{\n\t\t\t\t\t0: {\n\t\t\t\t\t\tTimeout: &policy.Policy_Timeout{\n\t\t\t\t\t\t\tUplinkOnly:   &policy.Second{Value: 0},\n\t\t\t\t\t\t\tDownlinkOnly: &policy.Second{Value: 0},\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\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tTag: \"d\",\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(clientPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&outbound.Config{\n\t\t\t\t\tReceiver: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(serverPort),\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\t\t\tId:      u2.String(),\n\t\t\t\t\t\t\t\t\t\tAlterId: 64,\n\t\t\t\t\t\t\t\t\t\tSecuritySettings: &protocol.SecurityConfig{\n\t\t\t\t\t\t\t\t\t\t\tType: protocol.SecurityType_AES128_GCM,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t},\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},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig, clientConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\tif err := testTCPConn(clientPort, 1024, time.Second*5)(); err != io.EOF &&\n\t\t/*We might wish to drain the connection*/\n\t\t(err != nil && !strings.HasSuffix(err.Error(), \"i/o timeout\")) {\n\t\tt.Fatal(\"expected error: \", err)\n\t}\n\n\tcmdConn, err := grpc.Dial(fmt.Sprintf(\"127.0.0.1:%d\", cmdPort), grpc.WithInsecure(), grpc.WithBlock())\n\tcommon.Must(err)\n\tdefer cmdConn.Close()\n\n\thsClient := command.NewHandlerServiceClient(cmdConn)\n\tresp, err := hsClient.AlterInbound(context.Background(), &command.AlterInboundRequest{\n\t\tTag: \"v\",\n\t\tOperation: serial.ToTypedMessage(\n\t\t\t&command.AddUserOperation{\n\t\t\t\tUser: &protocol.User{\n\t\t\t\t\tEmail: \"test@v2ray.com\",\n\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\tId:      u2.String(),\n\t\t\t\t\t\tAlterId: 64,\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t}),\n\t})\n\tcommon.Must(err)\n\tif resp == nil {\n\t\tt.Fatal(\"nil response\")\n\t}\n\n\tif err := testTCPConn(clientPort, 1024, time.Second*5)(); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tresp, err = hsClient.AlterInbound(context.Background(), &command.AlterInboundRequest{\n\t\tTag:       \"v\",\n\t\tOperation: serial.ToTypedMessage(&command.RemoveUserOperation{Email: \"test@v2ray.com\"}),\n\t})\n\tcommon.Must(err)\n\tif resp == nil {\n\t\tt.Fatal(\"nil response\")\n\t}\n}\n\nfunc TestCommanderStats(t *testing.T) {\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\tdefer tcpServer.Close()\n\n\tuserID := protocol.NewID(uuid.New())\n\tserverPort := tcp.PickPort()\n\tcmdPort := tcp.PickPort()\n\n\tserverConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&stats.Config{}),\n\t\t\tserial.ToTypedMessage(&commander.Config{\n\t\t\t\tTag: \"api\",\n\t\t\t\tService: []*serial.TypedMessage{\n\t\t\t\t\tserial.ToTypedMessage(&statscmd.Config{}),\n\t\t\t\t},\n\t\t\t}),\n\t\t\tserial.ToTypedMessage(&router.Config{\n\t\t\t\tRule: []*router.RoutingRule{\n\t\t\t\t\t{\n\t\t\t\t\t\tInboundTag: []string{\"api\"},\n\t\t\t\t\t\tTargetTag: &router.RoutingRule_Tag{\n\t\t\t\t\t\t\tTag: \"api\",\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\tserial.ToTypedMessage(&policy.Config{\n\t\t\t\tLevel: map[uint32]*policy.Policy{\n\t\t\t\t\t0: {\n\t\t\t\t\t\tTimeout: &policy.Policy_Timeout{\n\t\t\t\t\t\t\tUplinkOnly:   &policy.Second{Value: 0},\n\t\t\t\t\t\t\tDownlinkOnly: &policy.Second{Value: 0},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t1: {\n\t\t\t\t\t\tStats: &policy.Policy_Stats{\n\t\t\t\t\t\t\tUserUplink:   true,\n\t\t\t\t\t\t\tUserDownlink: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tSystem: &policy.SystemPolicy{\n\t\t\t\t\tStats: &policy.SystemPolicy_Stats{\n\t\t\t\t\t\tInboundUplink: true,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tTag: \"vmess\",\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&inbound.Config{\n\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tLevel: 1,\n\t\t\t\t\t\t\tEmail: \"test\",\n\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\tId:      userID.String(),\n\t\t\t\t\t\t\t\tAlterId: 64,\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\t{\n\t\t\t\tTag: \"api\",\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(cmdPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tclientPort := tcp.PickPort()\n\tclientConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(clientPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&outbound.Config{\n\t\t\t\t\tReceiver: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(serverPort),\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\t\t\tId:      userID.String(),\n\t\t\t\t\t\t\t\t\t\tAlterId: 64,\n\t\t\t\t\t\t\t\t\t\tSecuritySettings: &protocol.SecurityConfig{\n\t\t\t\t\t\t\t\t\t\t\tType: protocol.SecurityType_AES128_GCM,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t},\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},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig, clientConfig)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to create all servers\", err)\n\t}\n\tdefer CloseAllServers(servers)\n\n\tif err := testTCPConn(clientPort, 10240*1024, time.Second*20)(); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tcmdConn, err := grpc.Dial(fmt.Sprintf(\"127.0.0.1:%d\", cmdPort), grpc.WithInsecure(), grpc.WithBlock())\n\tcommon.Must(err)\n\tdefer cmdConn.Close()\n\n\tconst name = \"user>>>test>>>traffic>>>uplink\"\n\tsClient := statscmd.NewStatsServiceClient(cmdConn)\n\n\tsresp, err := sClient.GetStats(context.Background(), &statscmd.GetStatsRequest{\n\t\tName:   name,\n\t\tReset_: true,\n\t})\n\tcommon.Must(err)\n\tif r := cmp.Diff(sresp.Stat, &statscmd.Stat{\n\t\tName:  name,\n\t\tValue: 10240 * 1024,\n\t}, cmpopts.IgnoreUnexported(statscmd.Stat{})); r != \"\" {\n\t\tt.Error(r)\n\t}\n\n\tsresp, err = sClient.GetStats(context.Background(), &statscmd.GetStatsRequest{\n\t\tName: name,\n\t})\n\tcommon.Must(err)\n\tif r := cmp.Diff(sresp.Stat, &statscmd.Stat{\n\t\tName:  name,\n\t\tValue: 0,\n\t}, cmpopts.IgnoreUnexported(statscmd.Stat{})); r != \"\" {\n\t\tt.Error(r)\n\t}\n\n\tsresp, err = sClient.GetStats(context.Background(), &statscmd.GetStatsRequest{\n\t\tName:   \"inbound>>>vmess>>>traffic>>>uplink\",\n\t\tReset_: true,\n\t})\n\tcommon.Must(err)\n\tif sresp.Stat.Value <= 10240*1024 {\n\t\tt.Error(\"value < 10240*1024: \", sresp.Stat.Value)\n\t}\n}\n"
  },
  {
    "path": "testing/scenarios/common.go",
    "content": "package scenarios\n\nimport (\n\t\"bytes\"\n\t\"crypto/rand\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"sync\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/golang/protobuf/proto\"\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/app/dispatcher\"\n\t\"v2ray.com/core/app/proxyman\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/errors\"\n\t\"v2ray.com/core/common/log\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/retry\"\n\t\"v2ray.com/core/common/serial\"\n)\n\nfunc xor(b []byte) []byte {\n\tr := make([]byte, len(b))\n\tfor i, v := range b {\n\t\tr[i] = v ^ 'c'\n\t}\n\treturn r\n}\n\nfunc readFrom(conn net.Conn, timeout time.Duration, length int) []byte {\n\tb := make([]byte, length)\n\tdeadline := time.Now().Add(timeout)\n\tconn.SetReadDeadline(deadline)\n\tn, err := io.ReadFull(conn, b[:length])\n\tif err != nil {\n\t\tfmt.Println(\"Unexpected error from readFrom:\", err)\n\t}\n\treturn b[:n]\n}\n\nfunc readFrom2(conn net.Conn, timeout time.Duration, length int) ([]byte, error) {\n\tb := make([]byte, length)\n\tdeadline := time.Now().Add(timeout)\n\tconn.SetReadDeadline(deadline)\n\tn, err := io.ReadFull(conn, b[:length])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn b[:n], nil\n}\n\nfunc InitializeServerConfigs(configs ...*core.Config) ([]*exec.Cmd, error) {\n\tservers := make([]*exec.Cmd, 0, 10)\n\n\tfor _, config := range configs {\n\t\tserver, err := InitializeServerConfig(config)\n\t\tif err != nil {\n\t\t\tCloseAllServers(servers)\n\t\t\treturn nil, err\n\t\t}\n\t\tservers = append(servers, server)\n\t}\n\n\ttime.Sleep(time.Second * 2)\n\n\treturn servers, nil\n}\n\nfunc InitializeServerConfig(config *core.Config) (*exec.Cmd, error) {\n\terr := BuildV2Ray()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tconfig = withDefaultApps(config)\n\tconfigBytes, err := proto.Marshal(config)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tproc := RunV2RayProtobuf(configBytes)\n\n\tif err := proc.Start(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn proc, nil\n}\n\nvar (\n\ttestBinaryPath    string\n\ttestBinaryPathGen sync.Once\n)\n\nfunc genTestBinaryPath() {\n\ttestBinaryPathGen.Do(func() {\n\t\tvar tempDir string\n\t\tcommon.Must(retry.Timed(5, 100).On(func() error {\n\t\t\tdir, err := ioutil.TempDir(\"\", \"v2ray\")\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\ttempDir = dir\n\t\t\treturn nil\n\t\t}))\n\t\tfile := filepath.Join(tempDir, \"v2ray.test\")\n\t\tif runtime.GOOS == \"windows\" {\n\t\t\tfile += \".exe\"\n\t\t}\n\t\ttestBinaryPath = file\n\t\tfmt.Printf(\"Generated binary path: %s\\n\", file)\n\t})\n}\n\nfunc GetSourcePath() string {\n\treturn filepath.Join(\"v2ray.com\", \"core\", \"main\")\n}\n\nfunc CloseAllServers(servers []*exec.Cmd) {\n\tlog.Record(&log.GeneralMessage{\n\t\tSeverity: log.Severity_Info,\n\t\tContent:  \"Closing all servers.\",\n\t})\n\tfor _, server := range servers {\n\t\tif runtime.GOOS == \"windows\" {\n\t\t\tserver.Process.Kill()\n\t\t} else {\n\t\t\tserver.Process.Signal(syscall.SIGTERM)\n\t\t}\n\t}\n\tfor _, server := range servers {\n\t\tserver.Process.Wait()\n\t}\n\tlog.Record(&log.GeneralMessage{\n\t\tSeverity: log.Severity_Info,\n\t\tContent:  \"All server closed.\",\n\t})\n}\n\nfunc withDefaultApps(config *core.Config) *core.Config {\n\tconfig.App = append(config.App, serial.ToTypedMessage(&dispatcher.Config{}))\n\tconfig.App = append(config.App, serial.ToTypedMessage(&proxyman.InboundConfig{}))\n\tconfig.App = append(config.App, serial.ToTypedMessage(&proxyman.OutboundConfig{}))\n\treturn config\n}\n\nfunc testTCPConn(port net.Port, payloadSize int, timeout time.Duration) func() error {\n\treturn func() error {\n\t\tconn, err := net.DialTCP(\"tcp\", nil, &net.TCPAddr{\n\t\t\tIP:   []byte{127, 0, 0, 1},\n\t\t\tPort: int(port),\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tdefer conn.Close()\n\n\t\treturn testTCPConn2(conn, payloadSize, timeout)()\n\t}\n}\n\nfunc testUDPConn(port net.Port, payloadSize int, timeout time.Duration) func() error {\n\treturn func() error {\n\t\tconn, err := net.DialUDP(\"udp\", nil, &net.UDPAddr{\n\t\t\tIP:   []byte{127, 0, 0, 1},\n\t\t\tPort: int(port),\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tdefer conn.Close()\n\n\t\treturn testTCPConn2(conn, payloadSize, timeout)()\n\t}\n}\n\nfunc testTCPConn2(conn net.Conn, payloadSize int, timeout time.Duration) func() error {\n\treturn func() error {\n\t\tpayload := make([]byte, payloadSize)\n\t\tcommon.Must2(rand.Read(payload))\n\n\t\tnBytes, err := conn.Write(payload)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif nBytes != len(payload) {\n\t\t\treturn errors.New(\"expect \", len(payload), \" written, but actually \", nBytes)\n\t\t}\n\n\t\tresponse, err := readFrom2(conn, timeout, payloadSize)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\t_ = response\n\n\t\tif r := bytes.Compare(response, xor(payload)); r != 0 {\n\t\t\treturn errors.New(r)\n\t\t}\n\n\t\treturn nil\n\n\t}\n}\n"
  },
  {
    "path": "testing/scenarios/common_coverage.go",
    "content": "// +build coverage\n\npackage scenarios\n\nimport (\n\t\"bytes\"\n\t\"os\"\n\t\"os/exec\"\n\n\t\"v2ray.com/core/common/uuid\"\n)\n\nfunc BuildV2Ray() error {\n\tgenTestBinaryPath()\n\tif _, err := os.Stat(testBinaryPath); err == nil {\n\t\treturn nil\n\t}\n\n\tcmd := exec.Command(\"go\", \"test\", \"-tags\", \"coverage coveragemain\", \"-coverpkg\", \"v2ray.com/core/...\", \"-c\", \"-o\", testBinaryPath, GetSourcePath())\n\treturn cmd.Run()\n}\n\nfunc RunV2RayProtobuf(config []byte) *exec.Cmd {\n\tgenTestBinaryPath()\n\n\tcovDir := os.Getenv(\"V2RAY_COV\")\n\tos.MkdirAll(covDir, os.ModeDir)\n\trandomID := uuid.New()\n\tprofile := randomID.String() + \".out\"\n\tproc := exec.Command(testBinaryPath, \"-config=stdin:\", \"-format=pb\", \"-test.run\", \"TestRunMainForCoverage\", \"-test.coverprofile\", profile, \"-test.outputdir\", covDir)\n\tproc.Stdin = bytes.NewBuffer(config)\n\tproc.Stderr = os.Stderr\n\tproc.Stdout = os.Stdout\n\n\treturn proc\n}\n"
  },
  {
    "path": "testing/scenarios/common_regular.go",
    "content": "// +build !coverage\n\npackage scenarios\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n)\n\nfunc BuildV2Ray() error {\n\tgenTestBinaryPath()\n\tif _, err := os.Stat(testBinaryPath); err == nil {\n\t\treturn nil\n\t}\n\n\tfmt.Printf(\"Building V2Ray into path (%s)\\n\", testBinaryPath)\n\tcmd := exec.Command(\"go\", \"build\", \"-o=\"+testBinaryPath, GetSourcePath())\n\treturn cmd.Run()\n}\n\nfunc RunV2RayProtobuf(config []byte) *exec.Cmd {\n\tgenTestBinaryPath()\n\tproc := exec.Command(testBinaryPath, \"-config=stdin:\", \"-format=pb\")\n\tproc.Stdin = bytes.NewBuffer(config)\n\tproc.Stderr = os.Stderr\n\tproc.Stdout = os.Stdout\n\n\treturn proc\n}\n"
  },
  {
    "path": "testing/scenarios/dns_test.go",
    "content": "package scenarios\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\txproxy \"golang.org/x/net/proxy\"\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/app/dns\"\n\t\"v2ray.com/core/app/proxyman\"\n\t\"v2ray.com/core/app/router\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/serial\"\n\t\"v2ray.com/core/proxy/blackhole\"\n\t\"v2ray.com/core/proxy/freedom\"\n\t\"v2ray.com/core/proxy/socks\"\n\t\"v2ray.com/core/testing/servers/tcp\"\n)\n\nfunc TestResolveIP(t *testing.T) {\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\tdefer tcpServer.Close()\n\n\tserverPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&dns.Config{\n\t\t\t\tHosts: map[string]*net.IPOrDomain{\n\t\t\t\t\t\"google.com\": net.NewIPOrDomain(dest.Address),\n\t\t\t\t},\n\t\t\t}),\n\t\t\tserial.ToTypedMessage(&router.Config{\n\t\t\t\tDomainStrategy: router.Config_IpIfNonMatch,\n\t\t\t\tRule: []*router.RoutingRule{\n\t\t\t\t\t{\n\t\t\t\t\t\tCidr: []*router.CIDR{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tIp:     []byte{127, 0, 0, 0},\n\t\t\t\t\t\t\t\tPrefix: 8,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tTargetTag: &router.RoutingRule_Tag{\n\t\t\t\t\t\t\tTag: \"direct\",\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\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&socks.ServerConfig{\n\t\t\t\t\tAuthType: socks.AuthType_NO_AUTH,\n\t\t\t\t\tAccounts: map[string]string{\n\t\t\t\t\t\t\"Test Account\": \"Test Password\",\n\t\t\t\t\t},\n\t\t\t\t\tAddress:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\tUdpEnabled: false,\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&blackhole.Config{}),\n\t\t\t},\n\t\t\t{\n\t\t\t\tTag: \"direct\",\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{\n\t\t\t\t\tDomainStrategy: freedom.Config_USE_IP,\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\t{\n\t\tnoAuthDialer, err := xproxy.SOCKS5(\"tcp\", net.TCPDestination(net.LocalHostIP, serverPort).NetAddr(), nil, xproxy.Direct)\n\t\tcommon.Must(err)\n\t\tconn, err := noAuthDialer.Dial(\"tcp\", fmt.Sprintf(\"google.com:%d\", dest.Port))\n\t\tcommon.Must(err)\n\t\tdefer conn.Close()\n\n\t\tif err := testTCPConn2(conn, 1024, time.Second*5)(); err != nil {\n\t\t\tt.Error(err)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "testing/scenarios/dokodemo_test.go",
    "content": "package scenarios\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"golang.org/x/sync/errgroup\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/app/log\"\n\t\"v2ray.com/core/app/proxyman\"\n\t\"v2ray.com/core/common\"\n\tclog \"v2ray.com/core/common/log\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/serial\"\n\t\"v2ray.com/core/common/uuid\"\n\t\"v2ray.com/core/proxy/dokodemo\"\n\t\"v2ray.com/core/proxy/freedom\"\n\t\"v2ray.com/core/proxy/vmess\"\n\t\"v2ray.com/core/proxy/vmess/inbound\"\n\t\"v2ray.com/core/proxy/vmess/outbound\"\n\t\"v2ray.com/core/testing/servers/tcp\"\n\t\"v2ray.com/core/testing/servers/udp\"\n)\n\nfunc TestDokodemoTCP(t *testing.T) {\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\tdefer tcpServer.Close()\n\n\tuserID := protocol.NewID(uuid.New())\n\tserverPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&log.Config{\n\t\t\t\tErrorLogLevel: clog.Severity_Debug,\n\t\t\t\tErrorLogType:  log.LogType_Console,\n\t\t\t}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&inbound.Config{\n\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\tId: userID.String(),\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},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tclientPort := uint32(tcp.PickPort())\n\tclientPortRange := uint32(5)\n\tclientConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&log.Config{\n\t\t\t\tErrorLogLevel: clog.Severity_Debug,\n\t\t\t\tErrorLogType:  log.LogType_Console,\n\t\t\t}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: &net.PortRange{From: clientPort, To: clientPort + clientPortRange},\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&outbound.Config{\n\t\t\t\t\tReceiver: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(serverPort),\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\t\t\tId: userID.String(),\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t},\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},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig, clientConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\tfor port := clientPort; port <= clientPort+clientPortRange; port++ {\n\t\tif err := testTCPConn(net.Port(port), 1024, time.Second*2)(); err != nil {\n\t\t\tt.Error(err)\n\t\t}\n\t}\n}\n\nfunc TestDokodemoUDP(t *testing.T) {\n\tudpServer := udp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := udpServer.Start()\n\tcommon.Must(err)\n\tdefer udpServer.Close()\n\n\tuserID := protocol.NewID(uuid.New())\n\tserverPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&inbound.Config{\n\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\tId: userID.String(),\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},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tclientPort := uint32(tcp.PickPort())\n\tclientPortRange := uint32(5)\n\tclientConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: &net.PortRange{From: clientPort, To: clientPort + clientPortRange},\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_UDP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&outbound.Config{\n\t\t\t\t\tReceiver: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(serverPort),\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\t\t\tId: userID.String(),\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t},\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},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig, clientConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\tvar errg errgroup.Group\n\tfor port := clientPort; port <= clientPort+clientPortRange; port++ {\n\t\terrg.Go(testUDPConn(net.Port(port), 1024, time.Second*5))\n\t}\n\tif err := errg.Wait(); err != nil {\n\t\tt.Error(err)\n\t}\n}\n"
  },
  {
    "path": "testing/scenarios/feature_test.go",
    "content": "package scenarios\n\nimport (\n\t\"context\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n\n\txproxy \"golang.org/x/net/proxy\"\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/app/dispatcher\"\n\t\"v2ray.com/core/app/log\"\n\t\"v2ray.com/core/app/proxyman\"\n\t_ \"v2ray.com/core/app/proxyman/inbound\"\n\t_ \"v2ray.com/core/app/proxyman/outbound\"\n\t\"v2ray.com/core/app/router\"\n\t\"v2ray.com/core/common\"\n\tclog \"v2ray.com/core/common/log\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/serial\"\n\t\"v2ray.com/core/common/uuid\"\n\t\"v2ray.com/core/proxy/blackhole\"\n\t\"v2ray.com/core/proxy/dokodemo\"\n\t\"v2ray.com/core/proxy/freedom\"\n\tv2http \"v2ray.com/core/proxy/http\"\n\t\"v2ray.com/core/proxy/socks\"\n\t\"v2ray.com/core/proxy/vmess\"\n\t\"v2ray.com/core/proxy/vmess/inbound\"\n\t\"v2ray.com/core/proxy/vmess/outbound\"\n\t\"v2ray.com/core/testing/servers/tcp\"\n\t\"v2ray.com/core/testing/servers/udp\"\n\t\"v2ray.com/core/transport/internet\"\n)\n\nfunc TestPassiveConnection(t *testing.T) {\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: xor,\n\t\tSendFirst:    []byte(\"send first\"),\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\tdefer tcpServer.Close()\n\n\tserverPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\tconn, err := net.DialTCP(\"tcp\", nil, &net.TCPAddr{\n\t\tIP:   []byte{127, 0, 0, 1},\n\t\tPort: int(serverPort),\n\t})\n\tcommon.Must(err)\n\n\t{\n\t\tresponse := make([]byte, 1024)\n\t\tnBytes, err := conn.Read(response)\n\t\tcommon.Must(err)\n\t\tif string(response[:nBytes]) != \"send first\" {\n\t\t\tt.Error(\"unexpected first response: \", string(response[:nBytes]))\n\t\t}\n\t}\n\n\tif err := testTCPConn2(conn, 1024, time.Second*5)(); err != nil {\n\t\tt.Error(err)\n\t}\n}\n\nfunc TestProxy(t *testing.T) {\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\tdefer tcpServer.Close()\n\n\tserverUserID := protocol.NewID(uuid.New())\n\tserverPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&inbound.Config{\n\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\tId: serverUserID.String(),\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},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tproxyUserID := protocol.NewID(uuid.New())\n\tproxyPort := tcp.PickPort()\n\tproxyConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(proxyPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&inbound.Config{\n\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\tId: proxyUserID.String(),\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},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tclientPort := tcp.PickPort()\n\tclientConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(clientPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&outbound.Config{\n\t\t\t\t\tReceiver: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(serverPort),\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\t\t\tId: serverUserID.String(),\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t},\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\tSenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{\n\t\t\t\t\tProxySettings: &internet.ProxyConfig{\n\t\t\t\t\t\tTag: \"proxy\",\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t\t{\n\t\t\t\tTag: \"proxy\",\n\t\t\t\tProxySettings: serial.ToTypedMessage(&outbound.Config{\n\t\t\t\t\tReceiver: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(proxyPort),\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\t\t\tId: proxyUserID.String(),\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t},\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},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig, proxyConfig, clientConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\tif err := testTCPConn(clientPort, 1024, time.Second*5)(); err != nil {\n\t\tt.Error(err)\n\t}\n}\n\nfunc TestProxyOverKCP(t *testing.T) {\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\tdefer tcpServer.Close()\n\n\tserverUserID := protocol.NewID(uuid.New())\n\tserverPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\tStreamSettings: &internet.StreamConfig{\n\t\t\t\t\t\tProtocol: internet.TransportProtocol_MKCP,\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&inbound.Config{\n\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\tId: serverUserID.String(),\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},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tproxyUserID := protocol.NewID(uuid.New())\n\tproxyPort := tcp.PickPort()\n\tproxyConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(proxyPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&inbound.Config{\n\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\tId: proxyUserID.String(),\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},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t\tSenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{\n\t\t\t\t\tStreamSettings: &internet.StreamConfig{\n\t\t\t\t\t\tProtocol: internet.TransportProtocol_MKCP,\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t}\n\n\tclientPort := tcp.PickPort()\n\tclientConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(clientPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&outbound.Config{\n\t\t\t\t\tReceiver: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(serverPort),\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\t\t\tId: serverUserID.String(),\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t},\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\tSenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{\n\t\t\t\t\tProxySettings: &internet.ProxyConfig{\n\t\t\t\t\t\tTag: \"proxy\",\n\t\t\t\t\t},\n\t\t\t\t\tStreamSettings: &internet.StreamConfig{\n\t\t\t\t\t\tProtocol: internet.TransportProtocol_MKCP,\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t\t{\n\t\t\t\tTag: \"proxy\",\n\t\t\t\tProxySettings: serial.ToTypedMessage(&outbound.Config{\n\t\t\t\t\tReceiver: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(proxyPort),\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\t\t\tId: proxyUserID.String(),\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t},\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},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig, proxyConfig, clientConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\tif err := testTCPConn(clientPort, 1024, time.Second*5)(); err != nil {\n\t\tt.Error(err)\n\t}\n}\n\nfunc TestBlackhole(t *testing.T) {\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\tdefer tcpServer.Close()\n\n\ttcpServer2 := tcp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest2, err := tcpServer2.Start()\n\tcommon.Must(err)\n\tdefer tcpServer2.Close()\n\n\tserverPort := tcp.PickPort()\n\tserverPort2 := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort2),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest2.Address),\n\t\t\t\t\tPort:    uint32(dest2.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tTag:           \"direct\",\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t\t{\n\t\t\t\tTag:           \"blocked\",\n\t\t\t\tProxySettings: serial.ToTypedMessage(&blackhole.Config{}),\n\t\t\t},\n\t\t},\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&router.Config{\n\t\t\t\tRule: []*router.RoutingRule{\n\t\t\t\t\t{\n\t\t\t\t\t\tTargetTag: &router.RoutingRule_Tag{\n\t\t\t\t\t\t\tTag: \"blocked\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tPortRange: net.SinglePortRange(dest2.Port),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}),\n\t\t},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\tif err := testTCPConn(serverPort2, 1024, time.Second*5)(); err == nil {\n\t\tt.Error(\"nil error\")\n\t}\n}\n\nfunc TestForward(t *testing.T) {\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\tdefer tcpServer.Close()\n\n\tserverPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&socks.ServerConfig{\n\t\t\t\t\tAuthType: socks.AuthType_NO_AUTH,\n\t\t\t\t\tAccounts: map[string]string{\n\t\t\t\t\t\t\"Test Account\": \"Test Password\",\n\t\t\t\t\t},\n\t\t\t\t\tAddress:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\tUdpEnabled: false,\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{\n\t\t\t\t\tDestinationOverride: &freedom.DestinationOverride{\n\t\t\t\t\t\tServer: &protocol.ServerEndpoint{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(dest.Port),\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\tservers, err := InitializeServerConfigs(serverConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\t{\n\t\tnoAuthDialer, err := xproxy.SOCKS5(\"tcp\", net.TCPDestination(net.LocalHostIP, serverPort).NetAddr(), nil, xproxy.Direct)\n\t\tcommon.Must(err)\n\t\tconn, err := noAuthDialer.Dial(\"tcp\", \"google.com:80\")\n\t\tcommon.Must(err)\n\t\tdefer conn.Close()\n\n\t\tif err := testTCPConn2(conn, 1024, time.Second*5)(); err != nil {\n\t\t\tt.Error(err)\n\t\t}\n\t}\n}\n\nfunc TestUDPConnection(t *testing.T) {\n\tudpServer := udp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := udpServer.Start()\n\tcommon.Must(err)\n\tdefer udpServer.Close()\n\n\tclientPort := tcp.PickPort()\n\tclientConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(clientPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_UDP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tservers, err := InitializeServerConfigs(clientConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\tif err := testUDPConn(clientPort, 1024, time.Second*5)(); err != nil {\n\t\tt.Error(err)\n\t}\n\n\ttime.Sleep(20 * time.Second)\n\n\tif err := testUDPConn(clientPort, 1024, time.Second*5)(); err != nil {\n\t\tt.Error(err)\n\t}\n}\n\nfunc TestDomainSniffing(t *testing.T) {\n\tsniffingPort := tcp.PickPort()\n\thttpPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tTag: \"snif\",\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(sniffingPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\tDomainOverride: []proxyman.KnownProtocols{\n\t\t\t\t\t\tproxyman.KnownProtocols_TLS,\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\tPort:    443,\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t\t{\n\t\t\t\tTag: \"http\",\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(httpPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&v2http.ServerConfig{}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tTag: \"redir\",\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{\n\t\t\t\t\tDestinationOverride: &freedom.DestinationOverride{\n\t\t\t\t\t\tServer: &protocol.ServerEndpoint{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(sniffingPort),\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\t\tTag:           \"direct\",\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&router.Config{\n\t\t\t\tRule: []*router.RoutingRule{\n\t\t\t\t\t{\n\t\t\t\t\t\tTargetTag: &router.RoutingRule_Tag{\n\t\t\t\t\t\t\tTag: \"direct\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tInboundTag: []string{\"snif\"},\n\t\t\t\t\t}, {\n\t\t\t\t\t\tTargetTag: &router.RoutingRule_Tag{\n\t\t\t\t\t\t\tTag: \"redir\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tInboundTag: []string{\"http\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}),\n\t\t\tserial.ToTypedMessage(&log.Config{\n\t\t\t\tErrorLogLevel: clog.Severity_Debug,\n\t\t\t\tErrorLogType:  log.LogType_Console,\n\t\t\t}),\n\t\t},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\t{\n\t\ttransport := &http.Transport{\n\t\t\tProxy: func(req *http.Request) (*url.URL, error) {\n\t\t\t\treturn url.Parse(\"http://127.0.0.1:\" + httpPort.String())\n\t\t\t},\n\t\t}\n\n\t\tclient := &http.Client{\n\t\t\tTransport: transport,\n\t\t}\n\n\t\tresp, err := client.Get(\"https://www.github.com/\")\n\t\tcommon.Must(err)\n\t\tif resp.StatusCode != 200 {\n\t\t\tt.Error(\"unexpected status code: \", resp.StatusCode)\n\t\t}\n\t\tcommon.Must(resp.Write(ioutil.Discard))\n\t}\n}\n\nfunc TestDialV2Ray(t *testing.T) {\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\tdefer tcpServer.Close()\n\n\tuserID := protocol.NewID(uuid.New())\n\tserverPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&log.Config{\n\t\t\t\tErrorLogLevel: clog.Severity_Debug,\n\t\t\t\tErrorLogType:  log.LogType_Console,\n\t\t\t}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&inbound.Config{\n\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\tId:      userID.String(),\n\t\t\t\t\t\t\t\tAlterId: 64,\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},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tclientConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&dispatcher.Config{}),\n\t\t\tserial.ToTypedMessage(&proxyman.InboundConfig{}),\n\t\t\tserial.ToTypedMessage(&proxyman.OutboundConfig{}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&outbound.Config{\n\t\t\t\t\tReceiver: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(serverPort),\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\t\t\tId:      userID.String(),\n\t\t\t\t\t\t\t\t\t\tAlterId: 64,\n\t\t\t\t\t\t\t\t\t\tSecuritySettings: &protocol.SecurityConfig{\n\t\t\t\t\t\t\t\t\t\t\tType: protocol.SecurityType_AES128_GCM,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t},\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},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\tclient, err := core.New(clientConfig)\n\tcommon.Must(err)\n\n\tconn, err := core.Dial(context.Background(), client, dest)\n\tcommon.Must(err)\n\tdefer conn.Close()\n\n\tif err := testTCPConn2(conn, 1024, time.Second*5)(); err != nil {\n\t\tt.Error(err)\n\t}\n}\n"
  },
  {
    "path": "testing/scenarios/http_test.go",
    "content": "package scenarios\n\nimport (\n\t\"bytes\"\n\t\"crypto/rand\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/app/proxyman\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/serial\"\n\t\"v2ray.com/core/proxy/freedom\"\n\tv2http \"v2ray.com/core/proxy/http\"\n\tv2httptest \"v2ray.com/core/testing/servers/http\"\n\t\"v2ray.com/core/testing/servers/tcp\"\n)\n\nfunc TestHttpConformance(t *testing.T) {\n\thttpServerPort := tcp.PickPort()\n\thttpServer := &v2httptest.Server{\n\t\tPort:        httpServerPort,\n\t\tPathHandler: make(map[string]http.HandlerFunc),\n\t}\n\t_, err := httpServer.Start()\n\tcommon.Must(err)\n\tdefer httpServer.Close()\n\n\tserverPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&v2http.ServerConfig{}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\t{\n\t\ttransport := &http.Transport{\n\t\t\tProxy: func(req *http.Request) (*url.URL, error) {\n\t\t\t\treturn url.Parse(\"http://127.0.0.1:\" + serverPort.String())\n\t\t\t},\n\t\t}\n\n\t\tclient := &http.Client{\n\t\t\tTransport: transport,\n\t\t}\n\n\t\tresp, err := client.Get(\"http://127.0.0.1:\" + httpServerPort.String())\n\t\tcommon.Must(err)\n\t\tif resp.StatusCode != 200 {\n\t\t\tt.Fatal(\"status: \", resp.StatusCode)\n\t\t}\n\n\t\tcontent, err := ioutil.ReadAll(resp.Body)\n\t\tcommon.Must(err)\n\t\tif string(content) != \"Home\" {\n\t\t\tt.Fatal(\"body: \", string(content))\n\t\t}\n\t}\n}\n\nfunc TestHttpError(t *testing.T) {\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: func(msg []byte) []byte {\n\t\t\treturn []byte{}\n\t\t},\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\tdefer tcpServer.Close()\n\n\ttime.AfterFunc(time.Second*2, func() {\n\t\ttcpServer.ShouldClose = true\n\t})\n\n\tserverPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&v2http.ServerConfig{}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\t{\n\t\ttransport := &http.Transport{\n\t\t\tProxy: func(req *http.Request) (*url.URL, error) {\n\t\t\t\treturn url.Parse(\"http://127.0.0.1:\" + serverPort.String())\n\t\t\t},\n\t\t}\n\n\t\tclient := &http.Client{\n\t\t\tTransport: transport,\n\t\t}\n\n\t\tresp, err := client.Get(\"http://127.0.0.1:\" + dest.Port.String())\n\t\tcommon.Must(err)\n\t\tif resp.StatusCode != 503 {\n\t\t\tt.Error(\"status: \", resp.StatusCode)\n\t\t}\n\t}\n}\n\nfunc TestHttpConnectMethod(t *testing.T) {\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\tdefer tcpServer.Close()\n\n\tserverPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&v2http.ServerConfig{}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\t{\n\t\ttransport := &http.Transport{\n\t\t\tProxy: func(req *http.Request) (*url.URL, error) {\n\t\t\t\treturn url.Parse(\"http://127.0.0.1:\" + serverPort.String())\n\t\t\t},\n\t\t}\n\n\t\tclient := &http.Client{\n\t\t\tTransport: transport,\n\t\t}\n\n\t\tpayload := make([]byte, 1024*64)\n\t\tcommon.Must2(rand.Read(payload))\n\t\treq, err := http.NewRequest(\"Connect\", \"http://\"+dest.NetAddr()+\"/\", bytes.NewReader(payload))\n\t\treq.Header.Set(\"X-a\", \"b\")\n\t\treq.Header.Set(\"X-b\", \"d\")\n\t\tcommon.Must(err)\n\n\t\tresp, err := client.Do(req)\n\t\tcommon.Must(err)\n\t\tif resp.StatusCode != 200 {\n\t\t\tt.Fatal(\"status: \", resp.StatusCode)\n\t\t}\n\n\t\tcontent := make([]byte, len(payload))\n\t\tcommon.Must2(io.ReadFull(resp.Body, content))\n\t\tif r := cmp.Diff(content, xor(payload)); r != \"\" {\n\t\t\tt.Fatal(r)\n\t\t}\n\t}\n}\n\nfunc TestHttpPost(t *testing.T) {\n\thttpServerPort := tcp.PickPort()\n\thttpServer := &v2httptest.Server{\n\t\tPort: httpServerPort,\n\t\tPathHandler: map[string]http.HandlerFunc{\n\t\t\t\"/testpost\": func(w http.ResponseWriter, r *http.Request) {\n\t\t\t\tpayload, err := buf.ReadAllToBytes(r.Body)\n\t\t\t\tr.Body.Close()\n\n\t\t\t\tif err != nil {\n\t\t\t\t\tw.WriteHeader(500)\n\t\t\t\t\tw.Write([]byte(\"Unable to read all payload\"))\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tpayload = xor(payload)\n\t\t\t\tw.Write(payload)\n\t\t\t},\n\t\t},\n\t}\n\n\t_, err := httpServer.Start()\n\tcommon.Must(err)\n\tdefer httpServer.Close()\n\n\tserverPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&v2http.ServerConfig{}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\t{\n\t\ttransport := &http.Transport{\n\t\t\tProxy: func(req *http.Request) (*url.URL, error) {\n\t\t\t\treturn url.Parse(\"http://127.0.0.1:\" + serverPort.String())\n\t\t\t},\n\t\t}\n\n\t\tclient := &http.Client{\n\t\t\tTransport: transport,\n\t\t}\n\n\t\tpayload := make([]byte, 1024*64)\n\t\tcommon.Must2(rand.Read(payload))\n\n\t\tresp, err := client.Post(\"http://127.0.0.1:\"+httpServerPort.String()+\"/testpost\", \"application/x-www-form-urlencoded\", bytes.NewReader(payload))\n\t\tcommon.Must(err)\n\t\tif resp.StatusCode != 200 {\n\t\t\tt.Fatal(\"status: \", resp.StatusCode)\n\t\t}\n\n\t\tcontent, err := ioutil.ReadAll(resp.Body)\n\t\tcommon.Must(err)\n\t\tif r := cmp.Diff(content, xor(payload)); r != \"\" {\n\t\t\tt.Fatal(r)\n\t\t}\n\t}\n}\n\nfunc setProxyBasicAuth(req *http.Request, user, pass string) {\n\treq.SetBasicAuth(user, pass)\n\treq.Header.Set(\"Proxy-Authorization\", req.Header.Get(\"Authorization\"))\n\treq.Header.Del(\"Authorization\")\n}\n\nfunc TestHttpBasicAuth(t *testing.T) {\n\thttpServerPort := tcp.PickPort()\n\thttpServer := &v2httptest.Server{\n\t\tPort:        httpServerPort,\n\t\tPathHandler: make(map[string]http.HandlerFunc),\n\t}\n\t_, err := httpServer.Start()\n\tcommon.Must(err)\n\tdefer httpServer.Close()\n\n\tserverPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&v2http.ServerConfig{\n\t\t\t\t\tAccounts: map[string]string{\n\t\t\t\t\t\t\"a\": \"b\",\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\t{\n\t\ttransport := &http.Transport{\n\t\t\tProxy: func(req *http.Request) (*url.URL, error) {\n\t\t\t\treturn url.Parse(\"http://127.0.0.1:\" + serverPort.String())\n\t\t\t},\n\t\t}\n\n\t\tclient := &http.Client{\n\t\t\tTransport: transport,\n\t\t}\n\n\t\t{\n\t\t\tresp, err := client.Get(\"http://127.0.0.1:\" + httpServerPort.String())\n\t\t\tcommon.Must(err)\n\t\t\tif resp.StatusCode != 407 {\n\t\t\t\tt.Fatal(\"status: \", resp.StatusCode)\n\t\t\t}\n\t\t}\n\n\t\t{\n\t\t\treq, err := http.NewRequest(\"GET\", \"http://127.0.0.1:\"+httpServerPort.String(), nil)\n\t\t\tcommon.Must(err)\n\n\t\t\tsetProxyBasicAuth(req, \"a\", \"c\")\n\t\t\tresp, err := client.Do(req)\n\t\t\tcommon.Must(err)\n\t\t\tif resp.StatusCode != 407 {\n\t\t\t\tt.Fatal(\"status: \", resp.StatusCode)\n\t\t\t}\n\t\t}\n\n\t\t{\n\t\t\treq, err := http.NewRequest(\"GET\", \"http://127.0.0.1:\"+httpServerPort.String(), nil)\n\t\t\tcommon.Must(err)\n\n\t\t\tsetProxyBasicAuth(req, \"a\", \"b\")\n\t\t\tresp, err := client.Do(req)\n\t\t\tcommon.Must(err)\n\t\t\tif resp.StatusCode != 200 {\n\t\t\t\tt.Fatal(\"status: \", resp.StatusCode)\n\t\t\t}\n\n\t\t\tcontent, err := ioutil.ReadAll(resp.Body)\n\t\t\tcommon.Must(err)\n\t\t\tif string(content) != \"Home\" {\n\t\t\t\tt.Fatal(\"body: \", string(content))\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "testing/scenarios/policy_test.go",
    "content": "package scenarios\n\nimport (\n\t\"io\"\n\t\"testing\"\n\t\"time\"\n\n\t\"golang.org/x/sync/errgroup\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/app/log\"\n\t\"v2ray.com/core/app/policy\"\n\t\"v2ray.com/core/app/proxyman\"\n\t\"v2ray.com/core/common\"\n\tclog \"v2ray.com/core/common/log\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/serial\"\n\t\"v2ray.com/core/common/uuid\"\n\t\"v2ray.com/core/proxy/dokodemo\"\n\t\"v2ray.com/core/proxy/freedom\"\n\t\"v2ray.com/core/proxy/vmess\"\n\t\"v2ray.com/core/proxy/vmess/inbound\"\n\t\"v2ray.com/core/proxy/vmess/outbound\"\n\t\"v2ray.com/core/testing/servers/tcp\"\n)\n\nfunc startQuickClosingTCPServer() (net.Listener, error) {\n\tlistener, err := net.Listen(\"tcp\", \"127.0.0.1:0\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tgo func() {\n\t\tfor {\n\t\t\tconn, err := listener.Accept()\n\t\t\tif err != nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tb := make([]byte, 1024)\n\t\t\tconn.Read(b)\n\t\t\tconn.Close()\n\t\t}\n\t}()\n\treturn listener, nil\n}\n\nfunc TestVMessClosing(t *testing.T) {\n\ttcpServer, err := startQuickClosingTCPServer()\n\tcommon.Must(err)\n\tdefer tcpServer.Close()\n\n\tdest := net.DestinationFromAddr(tcpServer.Addr())\n\n\tuserID := protocol.NewID(uuid.New())\n\tserverPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&policy.Config{\n\t\t\t\tLevel: map[uint32]*policy.Policy{\n\t\t\t\t\t0: {\n\t\t\t\t\t\tTimeout: &policy.Policy_Timeout{\n\t\t\t\t\t\t\tUplinkOnly:   &policy.Second{Value: 0},\n\t\t\t\t\t\t\tDownlinkOnly: &policy.Second{Value: 0},\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\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&inbound.Config{\n\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\tId:      userID.String(),\n\t\t\t\t\t\t\t\tAlterId: 64,\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},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tclientPort := tcp.PickPort()\n\tclientConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&policy.Config{\n\t\t\t\tLevel: map[uint32]*policy.Policy{\n\t\t\t\t\t0: {\n\t\t\t\t\t\tTimeout: &policy.Policy_Timeout{\n\t\t\t\t\t\t\tUplinkOnly:   &policy.Second{Value: 0},\n\t\t\t\t\t\t\tDownlinkOnly: &policy.Second{Value: 0},\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\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(clientPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&outbound.Config{\n\t\t\t\t\tReceiver: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(serverPort),\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\t\t\tId:      userID.String(),\n\t\t\t\t\t\t\t\t\t\tAlterId: 64,\n\t\t\t\t\t\t\t\t\t\tSecuritySettings: &protocol.SecurityConfig{\n\t\t\t\t\t\t\t\t\t\t\tType: protocol.SecurityType_AES128_GCM,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t},\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},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig, clientConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\tif err := testTCPConn(clientPort, 1024, time.Second*2)(); err != io.EOF {\n\t\tt.Error(err)\n\t}\n}\n\nfunc TestZeroBuffer(t *testing.T) {\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\tdefer tcpServer.Close()\n\n\tuserID := protocol.NewID(uuid.New())\n\tserverPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&policy.Config{\n\t\t\t\tLevel: map[uint32]*policy.Policy{\n\t\t\t\t\t0: {\n\t\t\t\t\t\tTimeout: &policy.Policy_Timeout{\n\t\t\t\t\t\t\tUplinkOnly:   &policy.Second{Value: 0},\n\t\t\t\t\t\t\tDownlinkOnly: &policy.Second{Value: 0},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tBuffer: &policy.Policy_Buffer{\n\t\t\t\t\t\t\tConnection: 0,\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\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&inbound.Config{\n\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\tId:      userID.String(),\n\t\t\t\t\t\t\t\tAlterId: 64,\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},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tclientPort := tcp.PickPort()\n\tclientConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&log.Config{\n\t\t\t\tErrorLogLevel: clog.Severity_Debug,\n\t\t\t\tErrorLogType:  log.LogType_Console,\n\t\t\t}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(clientPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&outbound.Config{\n\t\t\t\t\tReceiver: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(serverPort),\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\t\t\tId:      userID.String(),\n\t\t\t\t\t\t\t\t\t\tAlterId: 64,\n\t\t\t\t\t\t\t\t\t\tSecuritySettings: &protocol.SecurityConfig{\n\t\t\t\t\t\t\t\t\t\t\tType: protocol.SecurityType_AES128_GCM,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t},\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},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig, clientConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\tvar errg errgroup.Group\n\tfor i := 0; i < 10; i++ {\n\t\terrg.Go(testTCPConn(clientPort, 10240*1024, time.Second*20))\n\t}\n\tif err := errg.Wait(); err != nil {\n\t\tt.Error(err)\n\t}\n}\n"
  },
  {
    "path": "testing/scenarios/reverse_test.go",
    "content": "package scenarios\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"golang.org/x/sync/errgroup\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/app/log\"\n\t\"v2ray.com/core/app/policy\"\n\t\"v2ray.com/core/app/proxyman\"\n\t\"v2ray.com/core/app/reverse\"\n\t\"v2ray.com/core/app/router\"\n\t\"v2ray.com/core/common\"\n\tclog \"v2ray.com/core/common/log\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/serial\"\n\t\"v2ray.com/core/common/uuid\"\n\t\"v2ray.com/core/proxy/blackhole\"\n\t\"v2ray.com/core/proxy/dokodemo\"\n\t\"v2ray.com/core/proxy/freedom\"\n\t\"v2ray.com/core/proxy/vmess\"\n\t\"v2ray.com/core/proxy/vmess/inbound\"\n\t\"v2ray.com/core/proxy/vmess/outbound\"\n\t\"v2ray.com/core/testing/servers/tcp\"\n)\n\nfunc TestReverseProxy(t *testing.T) {\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\n\tdefer tcpServer.Close()\n\n\tuserID := protocol.NewID(uuid.New())\n\texternalPort := tcp.PickPort()\n\treversePort := tcp.PickPort()\n\n\tserverConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&reverse.Config{\n\t\t\t\tPortalConfig: []*reverse.PortalConfig{\n\t\t\t\t\t{\n\t\t\t\t\t\tTag:    \"portal\",\n\t\t\t\t\t\tDomain: \"test.v2ray.com\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}),\n\t\t\tserial.ToTypedMessage(&router.Config{\n\t\t\t\tRule: []*router.RoutingRule{\n\t\t\t\t\t{\n\t\t\t\t\t\tDomain: []*router.Domain{\n\t\t\t\t\t\t\t{Type: router.Domain_Full, Value: \"test.v2ray.com\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tTargetTag: &router.RoutingRule_Tag{\n\t\t\t\t\t\t\tTag: \"portal\",\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\tInboundTag: []string{\"external\"},\n\t\t\t\t\t\tTargetTag: &router.RoutingRule_Tag{\n\t\t\t\t\t\t\tTag: \"portal\",\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\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tTag: \"external\",\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(externalPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(reversePort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&inbound.Config{\n\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\tId:      userID.String(),\n\t\t\t\t\t\t\t\tAlterId: 64,\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},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&blackhole.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tclientPort := tcp.PickPort()\n\tclientConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&reverse.Config{\n\t\t\t\tBridgeConfig: []*reverse.BridgeConfig{\n\t\t\t\t\t{\n\t\t\t\t\t\tTag:    \"bridge\",\n\t\t\t\t\t\tDomain: \"test.v2ray.com\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}),\n\t\t\tserial.ToTypedMessage(&router.Config{\n\t\t\t\tRule: []*router.RoutingRule{\n\t\t\t\t\t{\n\t\t\t\t\t\tDomain: []*router.Domain{\n\t\t\t\t\t\t\t{Type: router.Domain_Full, Value: \"test.v2ray.com\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tTargetTag: &router.RoutingRule_Tag{\n\t\t\t\t\t\t\tTag: \"reverse\",\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\tInboundTag: []string{\"bridge\"},\n\t\t\t\t\t\tTargetTag: &router.RoutingRule_Tag{\n\t\t\t\t\t\t\tTag: \"freedom\",\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\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(clientPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tTag:           \"freedom\",\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t\t{\n\t\t\t\tTag: \"reverse\",\n\t\t\t\tProxySettings: serial.ToTypedMessage(&outbound.Config{\n\t\t\t\t\tReceiver: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(reversePort),\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\t\t\tId:      userID.String(),\n\t\t\t\t\t\t\t\t\t\tAlterId: 64,\n\t\t\t\t\t\t\t\t\t\tSecuritySettings: &protocol.SecurityConfig{\n\t\t\t\t\t\t\t\t\t\t\tType: protocol.SecurityType_AES128_GCM,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t},\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},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig, clientConfig)\n\tcommon.Must(err)\n\n\tdefer CloseAllServers(servers)\n\n\tvar errg errgroup.Group\n\tfor i := 0; i < 32; i++ {\n\t\terrg.Go(testTCPConn(externalPort, 10240*1024, time.Second*40))\n\t}\n\n\tif err := errg.Wait(); err != nil {\n\t\tt.Fatal(err)\n\t}\n}\n\nfunc TestReverseProxyLongRunning(t *testing.T) {\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\n\tdefer tcpServer.Close()\n\n\tuserID := protocol.NewID(uuid.New())\n\texternalPort := tcp.PickPort()\n\treversePort := tcp.PickPort()\n\n\tserverConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&log.Config{\n\t\t\t\tErrorLogLevel: clog.Severity_Warning,\n\t\t\t\tErrorLogType:  log.LogType_Console,\n\t\t\t}),\n\t\t\tserial.ToTypedMessage(&policy.Config{\n\t\t\t\tLevel: map[uint32]*policy.Policy{\n\t\t\t\t\t0: {\n\t\t\t\t\t\tTimeout: &policy.Policy_Timeout{\n\t\t\t\t\t\t\tUplinkOnly:   &policy.Second{Value: 0},\n\t\t\t\t\t\t\tDownlinkOnly: &policy.Second{Value: 0},\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\tserial.ToTypedMessage(&reverse.Config{\n\t\t\t\tPortalConfig: []*reverse.PortalConfig{\n\t\t\t\t\t{\n\t\t\t\t\t\tTag:    \"portal\",\n\t\t\t\t\t\tDomain: \"test.v2ray.com\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}),\n\t\t\tserial.ToTypedMessage(&router.Config{\n\t\t\t\tRule: []*router.RoutingRule{\n\t\t\t\t\t{\n\t\t\t\t\t\tDomain: []*router.Domain{\n\t\t\t\t\t\t\t{Type: router.Domain_Full, Value: \"test.v2ray.com\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tTargetTag: &router.RoutingRule_Tag{\n\t\t\t\t\t\t\tTag: \"portal\",\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\tInboundTag: []string{\"external\"},\n\t\t\t\t\t\tTargetTag: &router.RoutingRule_Tag{\n\t\t\t\t\t\t\tTag: \"portal\",\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\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tTag: \"external\",\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(externalPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(reversePort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&inbound.Config{\n\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\tId:      userID.String(),\n\t\t\t\t\t\t\t\tAlterId: 64,\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},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&blackhole.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tclientPort := tcp.PickPort()\n\tclientConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&log.Config{\n\t\t\t\tErrorLogLevel: clog.Severity_Warning,\n\t\t\t\tErrorLogType:  log.LogType_Console,\n\t\t\t}),\n\t\t\tserial.ToTypedMessage(&policy.Config{\n\t\t\t\tLevel: map[uint32]*policy.Policy{\n\t\t\t\t\t0: {\n\t\t\t\t\t\tTimeout: &policy.Policy_Timeout{\n\t\t\t\t\t\t\tUplinkOnly:   &policy.Second{Value: 0},\n\t\t\t\t\t\t\tDownlinkOnly: &policy.Second{Value: 0},\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\tserial.ToTypedMessage(&reverse.Config{\n\t\t\t\tBridgeConfig: []*reverse.BridgeConfig{\n\t\t\t\t\t{\n\t\t\t\t\t\tTag:    \"bridge\",\n\t\t\t\t\t\tDomain: \"test.v2ray.com\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}),\n\t\t\tserial.ToTypedMessage(&router.Config{\n\t\t\t\tRule: []*router.RoutingRule{\n\t\t\t\t\t{\n\t\t\t\t\t\tDomain: []*router.Domain{\n\t\t\t\t\t\t\t{Type: router.Domain_Full, Value: \"test.v2ray.com\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tTargetTag: &router.RoutingRule_Tag{\n\t\t\t\t\t\t\tTag: \"reverse\",\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\tInboundTag: []string{\"bridge\"},\n\t\t\t\t\t\tTargetTag: &router.RoutingRule_Tag{\n\t\t\t\t\t\t\tTag: \"freedom\",\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\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(clientPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tTag:           \"freedom\",\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t\t{\n\t\t\t\tTag: \"reverse\",\n\t\t\t\tProxySettings: serial.ToTypedMessage(&outbound.Config{\n\t\t\t\t\tReceiver: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(reversePort),\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\t\t\tId:      userID.String(),\n\t\t\t\t\t\t\t\t\t\tAlterId: 64,\n\t\t\t\t\t\t\t\t\t\tSecuritySettings: &protocol.SecurityConfig{\n\t\t\t\t\t\t\t\t\t\t\tType: protocol.SecurityType_AES128_GCM,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t},\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},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig, clientConfig)\n\tcommon.Must(err)\n\n\tdefer CloseAllServers(servers)\n\n\tfor i := 0; i < 4096; i++ {\n\t\tif err := testTCPConn(externalPort, 1024, time.Second*20)(); err != nil {\n\t\t\tt.Error(err)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "testing/scenarios/shadowsocks_test.go",
    "content": "package scenarios\n\nimport (\n\t\"crypto/rand\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"golang.org/x/sync/errgroup\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/app/log\"\n\t\"v2ray.com/core/app/proxyman\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/errors\"\n\tclog \"v2ray.com/core/common/log\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/serial\"\n\t\"v2ray.com/core/proxy/dokodemo\"\n\t\"v2ray.com/core/proxy/freedom\"\n\t\"v2ray.com/core/proxy/shadowsocks\"\n\t\"v2ray.com/core/testing/servers/tcp\"\n\t\"v2ray.com/core/testing/servers/udp\"\n)\n\nfunc TestShadowsocksAES256TCP(t *testing.T) {\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\tdefer tcpServer.Close()\n\n\taccount := serial.ToTypedMessage(&shadowsocks.Account{\n\t\tPassword:   \"shadowsocks-password\",\n\t\tCipherType: shadowsocks.CipherType_AES_256_CFB,\n\t})\n\n\tserverPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&log.Config{\n\t\t\t\tErrorLogLevel: clog.Severity_Debug,\n\t\t\t\tErrorLogType:  log.LogType_Console,\n\t\t\t}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&shadowsocks.ServerConfig{\n\t\t\t\t\tUser: &protocol.User{\n\t\t\t\t\t\tAccount: account,\n\t\t\t\t\t\tLevel:   1,\n\t\t\t\t\t},\n\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tclientPort := tcp.PickPort()\n\tclientConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&log.Config{\n\t\t\t\tErrorLogLevel: clog.Severity_Debug,\n\t\t\t\tErrorLogType:  log.LogType_Console,\n\t\t\t}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(clientPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&shadowsocks.ClientConfig{\n\t\t\t\t\tServer: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(serverPort),\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAccount: account,\n\t\t\t\t\t\t\t\t},\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},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig, clientConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\tvar errg errgroup.Group\n\tfor i := 0; i < 10; i++ {\n\t\terrg.Go(testTCPConn(clientPort, 10240*1024, time.Second*20))\n\t}\n\tif err := errg.Wait(); err != nil {\n\t\tt.Fatal(err)\n\t}\n}\n\nfunc TestShadowsocksAES128UDP(t *testing.T) {\n\tudpServer := udp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := udpServer.Start()\n\tcommon.Must(err)\n\tdefer udpServer.Close()\n\n\taccount := serial.ToTypedMessage(&shadowsocks.Account{\n\t\tPassword:   \"shadowsocks-password\",\n\t\tCipherType: shadowsocks.CipherType_AES_128_CFB,\n\t})\n\n\tserverPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&log.Config{\n\t\t\t\tErrorLogLevel: clog.Severity_Debug,\n\t\t\t\tErrorLogType:  log.LogType_Console,\n\t\t\t}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&shadowsocks.ServerConfig{\n\t\t\t\t\tUser: &protocol.User{\n\t\t\t\t\t\tAccount: account,\n\t\t\t\t\t\tLevel:   1,\n\t\t\t\t\t},\n\t\t\t\t\tNetwork: []net.Network{net.Network_UDP},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tclientPort := tcp.PickPort()\n\tclientConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&log.Config{\n\t\t\t\tErrorLogLevel: clog.Severity_Debug,\n\t\t\t\tErrorLogType:  log.LogType_Console,\n\t\t\t}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(clientPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_UDP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&shadowsocks.ClientConfig{\n\t\t\t\t\tServer: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(serverPort),\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAccount: account,\n\t\t\t\t\t\t\t\t},\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},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig, clientConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\tvar errg errgroup.Group\n\tfor i := 0; i < 10; i++ {\n\t\terrg.Go(func() error {\n\t\t\tconn, err := net.DialUDP(\"udp\", nil, &net.UDPAddr{\n\t\t\t\tIP:   []byte{127, 0, 0, 1},\n\t\t\t\tPort: int(clientPort),\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tdefer conn.Close()\n\n\t\t\tpayload := make([]byte, 1024)\n\t\t\tcommon.Must2(rand.Read(payload))\n\n\t\t\tnBytes, err := conn.Write([]byte(payload))\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif nBytes != len(payload) {\n\t\t\t\treturn errors.New(\"expect \", len(payload), \" written, but actually \", nBytes)\n\t\t\t}\n\n\t\t\tresponse := readFrom(conn, time.Second*5, 1024)\n\t\t\tif r := cmp.Diff(response, xor(payload)); r != \"\" {\n\t\t\t\treturn errors.New(r)\n\t\t\t}\n\t\t\treturn nil\n\t\t})\n\t}\n\n\tif err := errg.Wait(); err != nil {\n\t\tt.Fatal(err)\n\t}\n}\n\nfunc TestShadowsocksChacha20TCP(t *testing.T) {\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\n\tdefer tcpServer.Close()\n\n\taccount := serial.ToTypedMessage(&shadowsocks.Account{\n\t\tPassword:   \"shadowsocks-password\",\n\t\tCipherType: shadowsocks.CipherType_CHACHA20_IETF,\n\t})\n\n\tserverPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&log.Config{\n\t\t\t\tErrorLogLevel: clog.Severity_Debug,\n\t\t\t\tErrorLogType:  log.LogType_Console,\n\t\t\t}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&shadowsocks.ServerConfig{\n\t\t\t\t\tUser: &protocol.User{\n\t\t\t\t\t\tAccount: account,\n\t\t\t\t\t\tLevel:   1,\n\t\t\t\t\t},\n\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tclientPort := tcp.PickPort()\n\tclientConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&log.Config{\n\t\t\t\tErrorLogLevel: clog.Severity_Debug,\n\t\t\t\tErrorLogType:  log.LogType_Console,\n\t\t\t}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(clientPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&shadowsocks.ClientConfig{\n\t\t\t\t\tServer: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(serverPort),\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAccount: account,\n\t\t\t\t\t\t\t\t},\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},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig, clientConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\tvar errg errgroup.Group\n\tfor i := 0; i < 10; i++ {\n\t\terrg.Go(testTCPConn(clientPort, 10240*1024, time.Second*40))\n\t}\n\n\tif err := errg.Wait(); err != nil {\n\t\tt.Error(err)\n\t}\n}\n\nfunc TestShadowsocksChacha20Poly1305TCP(t *testing.T) {\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\tdefer tcpServer.Close()\n\n\taccount := serial.ToTypedMessage(&shadowsocks.Account{\n\t\tPassword:   \"shadowsocks-password\",\n\t\tCipherType: shadowsocks.CipherType_CHACHA20_POLY1305,\n\t})\n\n\tserverPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&shadowsocks.ServerConfig{\n\t\t\t\t\tUser: &protocol.User{\n\t\t\t\t\t\tAccount: account,\n\t\t\t\t\t\tLevel:   1,\n\t\t\t\t\t},\n\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tclientPort := tcp.PickPort()\n\tclientConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(clientPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&shadowsocks.ClientConfig{\n\t\t\t\t\tServer: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(serverPort),\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAccount: account,\n\t\t\t\t\t\t\t\t},\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},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig, clientConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\tvar errg errgroup.Group\n\tfor i := 0; i < 10; i++ {\n\t\terrg.Go(testTCPConn(clientPort, 10240*1024, time.Second*20))\n\t}\n\tif err := errg.Wait(); err != nil {\n\t\tt.Error(err)\n\t}\n}\n\nfunc TestShadowsocksAES256GCMTCP(t *testing.T) {\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\tdefer tcpServer.Close()\n\n\taccount := serial.ToTypedMessage(&shadowsocks.Account{\n\t\tPassword:   \"shadowsocks-password\",\n\t\tCipherType: shadowsocks.CipherType_AES_256_GCM,\n\t})\n\n\tserverPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&log.Config{\n\t\t\t\tErrorLogLevel: clog.Severity_Debug,\n\t\t\t\tErrorLogType:  log.LogType_Console,\n\t\t\t}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&shadowsocks.ServerConfig{\n\t\t\t\t\tUser: &protocol.User{\n\t\t\t\t\t\tAccount: account,\n\t\t\t\t\t\tLevel:   1,\n\t\t\t\t\t},\n\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tclientPort := tcp.PickPort()\n\tclientConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&log.Config{\n\t\t\t\tErrorLogLevel: clog.Severity_Debug,\n\t\t\t\tErrorLogType:  log.LogType_Console,\n\t\t\t}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(clientPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&shadowsocks.ClientConfig{\n\t\t\t\t\tServer: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(serverPort),\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAccount: account,\n\t\t\t\t\t\t\t\t},\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},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig, clientConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\tvar errg errgroup.Group\n\tfor i := 0; i < 10; i++ {\n\t\terrg.Go(testTCPConn(clientPort, 10240*1024, time.Second*20))\n\t}\n\n\tif err := errg.Wait(); err != nil {\n\t\tt.Error(err)\n\t}\n}\n\nfunc TestShadowsocksAES128GCMUDP(t *testing.T) {\n\tudpServer := udp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := udpServer.Start()\n\tcommon.Must(err)\n\tdefer udpServer.Close()\n\n\taccount := serial.ToTypedMessage(&shadowsocks.Account{\n\t\tPassword:   \"shadowsocks-password\",\n\t\tCipherType: shadowsocks.CipherType_AES_128_GCM,\n\t})\n\n\tserverPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&log.Config{\n\t\t\t\tErrorLogLevel: clog.Severity_Debug,\n\t\t\t\tErrorLogType:  log.LogType_Console,\n\t\t\t}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&shadowsocks.ServerConfig{\n\t\t\t\t\tUser: &protocol.User{\n\t\t\t\t\t\tAccount: account,\n\t\t\t\t\t\tLevel:   1,\n\t\t\t\t\t},\n\t\t\t\t\tNetwork: []net.Network{net.Network_UDP},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tclientPort := tcp.PickPort()\n\tclientConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&log.Config{\n\t\t\t\tErrorLogLevel: clog.Severity_Debug,\n\t\t\t\tErrorLogType:  log.LogType_Console,\n\t\t\t}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(clientPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_UDP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&shadowsocks.ClientConfig{\n\t\t\t\t\tServer: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(serverPort),\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAccount: account,\n\t\t\t\t\t\t\t\t},\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},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig, clientConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\tvar errg errgroup.Group\n\tfor i := 0; i < 10; i++ {\n\t\terrg.Go(testUDPConn(clientPort, 1024, time.Second*5))\n\t}\n\tif err := errg.Wait(); err != nil {\n\t\tt.Error(err)\n\t}\n}\n\nfunc TestShadowsocksAES128GCMUDPMux(t *testing.T) {\n\tudpServer := udp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := udpServer.Start()\n\tcommon.Must(err)\n\tdefer udpServer.Close()\n\n\taccount := serial.ToTypedMessage(&shadowsocks.Account{\n\t\tPassword:   \"shadowsocks-password\",\n\t\tCipherType: shadowsocks.CipherType_AES_128_GCM,\n\t})\n\n\tserverPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&log.Config{\n\t\t\t\tErrorLogLevel: clog.Severity_Debug,\n\t\t\t\tErrorLogType:  log.LogType_Console,\n\t\t\t}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&shadowsocks.ServerConfig{\n\t\t\t\t\tUser: &protocol.User{\n\t\t\t\t\t\tAccount: account,\n\t\t\t\t\t\tLevel:   1,\n\t\t\t\t\t},\n\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tclientPort := tcp.PickPort()\n\tclientConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&log.Config{\n\t\t\t\tErrorLogLevel: clog.Severity_Debug,\n\t\t\t\tErrorLogType:  log.LogType_Console,\n\t\t\t}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(clientPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_UDP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tSenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{\n\t\t\t\t\tMultiplexSettings: &proxyman.MultiplexingConfig{\n\t\t\t\t\t\tEnabled:     true,\n\t\t\t\t\t\tConcurrency: 8,\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&shadowsocks.ClientConfig{\n\t\t\t\t\tServer: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(serverPort),\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAccount: account,\n\t\t\t\t\t\t\t\t},\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},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig, clientConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\tvar errg errgroup.Group\n\tfor i := 0; i < 10; i++ {\n\t\terrg.Go(testUDPConn(clientPort, 1024, time.Second*5))\n\t}\n\tif err := errg.Wait(); err != nil {\n\t\tt.Error(err)\n\t}\n}\n\nfunc TestShadowsocksNone(t *testing.T) {\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\n\tdefer tcpServer.Close()\n\n\taccount := serial.ToTypedMessage(&shadowsocks.Account{\n\t\tPassword:   \"shadowsocks-password\",\n\t\tCipherType: shadowsocks.CipherType_NONE,\n\t})\n\n\tserverPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&shadowsocks.ServerConfig{\n\t\t\t\t\tUser: &protocol.User{\n\t\t\t\t\t\tAccount: account,\n\t\t\t\t\t\tLevel:   1,\n\t\t\t\t\t},\n\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tclientPort := tcp.PickPort()\n\tclientConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(clientPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&shadowsocks.ClientConfig{\n\t\t\t\t\tServer: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(serverPort),\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAccount: account,\n\t\t\t\t\t\t\t\t},\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},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig, clientConfig)\n\tcommon.Must(err)\n\n\tdefer CloseAllServers(servers)\n\n\tvar errg errgroup.Group\n\tfor i := 0; i < 10; i++ {\n\t\terrg.Go(testTCPConn(clientPort, 10240*1024, time.Second*20))\n\t}\n\n\tif err := errg.Wait(); err != nil {\n\t\tt.Fatal(err)\n\t}\n}\n"
  },
  {
    "path": "testing/scenarios/socks_test.go",
    "content": "package scenarios\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\txproxy \"golang.org/x/net/proxy\"\n\tsocks4 \"h12.io/socks\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/app/proxyman\"\n\t\"v2ray.com/core/app/router\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/serial\"\n\t\"v2ray.com/core/proxy/blackhole\"\n\t\"v2ray.com/core/proxy/dokodemo\"\n\t\"v2ray.com/core/proxy/freedom\"\n\t\"v2ray.com/core/proxy/socks\"\n\t\"v2ray.com/core/testing/servers/tcp\"\n\t\"v2ray.com/core/testing/servers/udp\"\n)\n\nfunc TestSocksBridgeTCP(t *testing.T) {\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\tdefer tcpServer.Close()\n\n\tserverPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&socks.ServerConfig{\n\t\t\t\t\tAuthType: socks.AuthType_PASSWORD,\n\t\t\t\t\tAccounts: map[string]string{\n\t\t\t\t\t\t\"Test Account\": \"Test Password\",\n\t\t\t\t\t},\n\t\t\t\t\tAddress:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\tUdpEnabled: false,\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tclientPort := tcp.PickPort()\n\tclientConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(clientPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&socks.ClientConfig{\n\t\t\t\t\tServer: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(serverPort),\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&socks.Account{\n\t\t\t\t\t\t\t\t\t\tUsername: \"Test Account\",\n\t\t\t\t\t\t\t\t\t\tPassword: \"Test Password\",\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t},\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},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig, clientConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\tif err := testTCPConn(clientPort, 1024, time.Second*2)(); err != nil {\n\t\tt.Error(err)\n\t}\n}\n\nfunc TestSocksBridageUDP(t *testing.T) {\n\tudpServer := udp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := udpServer.Start()\n\tcommon.Must(err)\n\tdefer udpServer.Close()\n\n\tserverPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&socks.ServerConfig{\n\t\t\t\t\tAuthType: socks.AuthType_PASSWORD,\n\t\t\t\t\tAccounts: map[string]string{\n\t\t\t\t\t\t\"Test Account\": \"Test Password\",\n\t\t\t\t\t},\n\t\t\t\t\tAddress:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\tUdpEnabled: true,\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tclientPort := tcp.PickPort()\n\tclientConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(clientPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_TCP, net.Network_UDP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&socks.ClientConfig{\n\t\t\t\t\tServer: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(serverPort),\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&socks.Account{\n\t\t\t\t\t\t\t\t\t\tUsername: \"Test Account\",\n\t\t\t\t\t\t\t\t\t\tPassword: \"Test Password\",\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t},\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},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig, clientConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\tif err := testUDPConn(clientPort, 1024, time.Second*5)(); err != nil {\n\t\tt.Error(err)\n\t}\n}\n\nfunc TestSocksBridageUDPWithRouting(t *testing.T) {\n\tudpServer := udp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := udpServer.Start()\n\tcommon.Must(err)\n\tdefer udpServer.Close()\n\n\tserverPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&router.Config{\n\t\t\t\tRule: []*router.RoutingRule{\n\t\t\t\t\t{\n\t\t\t\t\t\tTargetTag: &router.RoutingRule_Tag{\n\t\t\t\t\t\t\tTag: \"out\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tInboundTag: []string{\"socks\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tTag: \"socks\",\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&socks.ServerConfig{\n\t\t\t\t\tAuthType:   socks.AuthType_NO_AUTH,\n\t\t\t\t\tAddress:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\tUdpEnabled: true,\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&blackhole.Config{}),\n\t\t\t},\n\t\t\t{\n\t\t\t\tTag:           \"out\",\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tclientPort := tcp.PickPort()\n\tclientConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(clientPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_TCP, net.Network_UDP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&socks.ClientConfig{\n\t\t\t\t\tServer: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(serverPort),\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\tservers, err := InitializeServerConfigs(serverConfig, clientConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\tif err := testUDPConn(clientPort, 1024, time.Second*5)(); err != nil {\n\t\tt.Error(err)\n\t}\n}\n\nfunc TestSocksConformanceMod(t *testing.T) {\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\tdefer tcpServer.Close()\n\n\tauthPort := tcp.PickPort()\n\tnoAuthPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(authPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&socks.ServerConfig{\n\t\t\t\t\tAuthType: socks.AuthType_PASSWORD,\n\t\t\t\t\tAccounts: map[string]string{\n\t\t\t\t\t\t\"Test Account\": \"Test Password\",\n\t\t\t\t\t},\n\t\t\t\t\tAddress:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\tUdpEnabled: false,\n\t\t\t\t}),\n\t\t\t},\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(noAuthPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&socks.ServerConfig{\n\t\t\t\t\tAuthType: socks.AuthType_NO_AUTH,\n\t\t\t\t\tAccounts: map[string]string{\n\t\t\t\t\t\t\"Test Account\": \"Test Password\",\n\t\t\t\t\t},\n\t\t\t\t\tAddress:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\tUdpEnabled: false,\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\t{\n\t\tnoAuthDialer, err := xproxy.SOCKS5(\"tcp\", net.TCPDestination(net.LocalHostIP, noAuthPort).NetAddr(), nil, xproxy.Direct)\n\t\tcommon.Must(err)\n\t\tconn, err := noAuthDialer.Dial(\"tcp\", dest.NetAddr())\n\t\tcommon.Must(err)\n\t\tdefer conn.Close()\n\n\t\tif err := testTCPConn2(conn, 1024, time.Second*5)(); err != nil {\n\t\t\tt.Error(err)\n\t\t}\n\t}\n\n\t{\n\t\tauthDialer, err := xproxy.SOCKS5(\"tcp\", net.TCPDestination(net.LocalHostIP, authPort).NetAddr(), &xproxy.Auth{User: \"Test Account\", Password: \"Test Password\"}, xproxy.Direct)\n\t\tcommon.Must(err)\n\t\tconn, err := authDialer.Dial(\"tcp\", dest.NetAddr())\n\t\tcommon.Must(err)\n\t\tdefer conn.Close()\n\n\t\tif err := testTCPConn2(conn, 1024, time.Second*5)(); err != nil {\n\t\t\tt.Error(err)\n\t\t}\n\t}\n\n\t{\n\t\tdialer := socks4.Dial(\"socks4://\" + net.TCPDestination(net.LocalHostIP, noAuthPort).NetAddr())\n\t\tconn, err := dialer(\"tcp\", dest.NetAddr())\n\t\tcommon.Must(err)\n\t\tdefer conn.Close()\n\n\t\tif err := testTCPConn2(conn, 1024, time.Second*5)(); err != nil {\n\t\t\tt.Error(err)\n\t\t}\n\t}\n\n\t{\n\t\tdialer := socks4.Dial(\"socks4://\" + net.TCPDestination(net.LocalHostIP, noAuthPort).NetAddr())\n\t\tconn, err := dialer(\"tcp\", net.TCPDestination(net.LocalHostIP, tcpServer.Port).NetAddr())\n\t\tcommon.Must(err)\n\t\tdefer conn.Close()\n\n\t\tif err := testTCPConn2(conn, 1024, time.Second*5)(); err != nil {\n\t\t\tt.Error(err)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "testing/scenarios/tls_test.go",
    "content": "package scenarios\n\nimport (\n\t\"crypto/x509\"\n\t\"runtime\"\n\t\"testing\"\n\t\"time\"\n\n\t\"golang.org/x/sync/errgroup\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/app/proxyman\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/protocol/tls/cert\"\n\t\"v2ray.com/core/common/serial\"\n\t\"v2ray.com/core/common/uuid\"\n\t\"v2ray.com/core/proxy/dokodemo\"\n\t\"v2ray.com/core/proxy/freedom\"\n\t\"v2ray.com/core/proxy/vmess\"\n\t\"v2ray.com/core/proxy/vmess/inbound\"\n\t\"v2ray.com/core/proxy/vmess/outbound\"\n\t\"v2ray.com/core/testing/servers/tcp\"\n\t\"v2ray.com/core/testing/servers/udp\"\n\t\"v2ray.com/core/transport/internet\"\n\t\"v2ray.com/core/transport/internet/http\"\n\t\"v2ray.com/core/transport/internet/tls\"\n\t\"v2ray.com/core/transport/internet/websocket\"\n)\n\nfunc TestSimpleTLSConnection(t *testing.T) {\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\tdefer tcpServer.Close()\n\n\tuserID := protocol.NewID(uuid.New())\n\tserverPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\tStreamSettings: &internet.StreamConfig{\n\t\t\t\t\t\tSecurityType: serial.GetMessageType(&tls.Config{}),\n\t\t\t\t\t\tSecuritySettings: []*serial.TypedMessage{\n\t\t\t\t\t\t\tserial.ToTypedMessage(&tls.Config{\n\t\t\t\t\t\t\t\tCertificate: []*tls.Certificate{tls.ParseCertificate(cert.MustGenerate(nil))},\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\tProxySettings: serial.ToTypedMessage(&inbound.Config{\n\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\tId: userID.String(),\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},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tclientPort := tcp.PickPort()\n\tclientConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(clientPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&outbound.Config{\n\t\t\t\t\tReceiver: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(serverPort),\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\t\t\tId: userID.String(),\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t},\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\tSenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{\n\t\t\t\t\tStreamSettings: &internet.StreamConfig{\n\t\t\t\t\t\tSecurityType: serial.GetMessageType(&tls.Config{}),\n\t\t\t\t\t\tSecuritySettings: []*serial.TypedMessage{\n\t\t\t\t\t\t\tserial.ToTypedMessage(&tls.Config{\n\t\t\t\t\t\t\t\tAllowInsecure: true,\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},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig, clientConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\tif err := testTCPConn(clientPort, 1024, time.Second*2)(); err != nil {\n\t\tt.Fatal(err)\n\t}\n}\n\nfunc TestAutoIssuingCertificate(t *testing.T) {\n\tif runtime.GOOS == \"windows\" {\n\t\t// Not supported on Windows yet.\n\t\treturn\n\t}\n\n\tif runtime.GOARCH == \"arm64\" {\n\t\treturn\n\t}\n\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\tdefer tcpServer.Close()\n\n\tcaCert, err := cert.Generate(nil, cert.Authority(true), cert.KeyUsage(x509.KeyUsageDigitalSignature|x509.KeyUsageKeyEncipherment|x509.KeyUsageCertSign))\n\tcommon.Must(err)\n\tcertPEM, keyPEM := caCert.ToPEM()\n\n\tuserID := protocol.NewID(uuid.New())\n\tserverPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\tStreamSettings: &internet.StreamConfig{\n\t\t\t\t\t\tSecurityType: serial.GetMessageType(&tls.Config{}),\n\t\t\t\t\t\tSecuritySettings: []*serial.TypedMessage{\n\t\t\t\t\t\t\tserial.ToTypedMessage(&tls.Config{\n\t\t\t\t\t\t\t\tCertificate: []*tls.Certificate{{\n\t\t\t\t\t\t\t\t\tCertificate: certPEM,\n\t\t\t\t\t\t\t\t\tKey:         keyPEM,\n\t\t\t\t\t\t\t\t\tUsage:       tls.Certificate_AUTHORITY_ISSUE,\n\t\t\t\t\t\t\t\t}},\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\tProxySettings: serial.ToTypedMessage(&inbound.Config{\n\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\tId: userID.String(),\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},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tclientPort := tcp.PickPort()\n\tclientConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(clientPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&outbound.Config{\n\t\t\t\t\tReceiver: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(serverPort),\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\t\t\tId: userID.String(),\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t},\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\tSenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{\n\t\t\t\t\tStreamSettings: &internet.StreamConfig{\n\t\t\t\t\t\tSecurityType: serial.GetMessageType(&tls.Config{}),\n\t\t\t\t\t\tSecuritySettings: []*serial.TypedMessage{\n\t\t\t\t\t\t\tserial.ToTypedMessage(&tls.Config{\n\t\t\t\t\t\t\t\tServerName: \"v2ray.com\",\n\t\t\t\t\t\t\t\tCertificate: []*tls.Certificate{{\n\t\t\t\t\t\t\t\t\tCertificate: certPEM,\n\t\t\t\t\t\t\t\t\tUsage:       tls.Certificate_AUTHORITY_VERIFY,\n\t\t\t\t\t\t\t\t}},\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},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig, clientConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\tfor i := 0; i < 10; i++ {\n\t\tif err := testTCPConn(clientPort, 1024, time.Second*2)(); err != nil {\n\t\t\tt.Error(err)\n\t\t}\n\t}\n}\n\nfunc TestTLSOverKCP(t *testing.T) {\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\tdefer tcpServer.Close()\n\n\tuserID := protocol.NewID(uuid.New())\n\tserverPort := udp.PickPort()\n\tserverConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\tStreamSettings: &internet.StreamConfig{\n\t\t\t\t\t\tProtocol:     internet.TransportProtocol_MKCP,\n\t\t\t\t\t\tSecurityType: serial.GetMessageType(&tls.Config{}),\n\t\t\t\t\t\tSecuritySettings: []*serial.TypedMessage{\n\t\t\t\t\t\t\tserial.ToTypedMessage(&tls.Config{\n\t\t\t\t\t\t\t\tCertificate: []*tls.Certificate{tls.ParseCertificate(cert.MustGenerate(nil))},\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\tProxySettings: serial.ToTypedMessage(&inbound.Config{\n\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\tId: userID.String(),\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},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tclientPort := tcp.PickPort()\n\tclientConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(clientPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&outbound.Config{\n\t\t\t\t\tReceiver: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(serverPort),\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\t\t\tId: userID.String(),\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t},\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\tSenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{\n\t\t\t\t\tStreamSettings: &internet.StreamConfig{\n\t\t\t\t\t\tProtocol:     internet.TransportProtocol_MKCP,\n\t\t\t\t\t\tSecurityType: serial.GetMessageType(&tls.Config{}),\n\t\t\t\t\t\tSecuritySettings: []*serial.TypedMessage{\n\t\t\t\t\t\t\tserial.ToTypedMessage(&tls.Config{\n\t\t\t\t\t\t\t\tAllowInsecure: true,\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},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig, clientConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\tif err := testTCPConn(clientPort, 1024, time.Second*2)(); err != nil {\n\t\tt.Error(err)\n\t}\n}\n\nfunc TestTLSOverWebSocket(t *testing.T) {\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\tdefer tcpServer.Close()\n\n\tuserID := protocol.NewID(uuid.New())\n\tserverPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\tStreamSettings: &internet.StreamConfig{\n\t\t\t\t\t\tProtocol:     internet.TransportProtocol_WebSocket,\n\t\t\t\t\t\tSecurityType: serial.GetMessageType(&tls.Config{}),\n\t\t\t\t\t\tSecuritySettings: []*serial.TypedMessage{\n\t\t\t\t\t\t\tserial.ToTypedMessage(&tls.Config{\n\t\t\t\t\t\t\t\tCertificate: []*tls.Certificate{tls.ParseCertificate(cert.MustGenerate(nil))},\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\tProxySettings: serial.ToTypedMessage(&inbound.Config{\n\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\tId: userID.String(),\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},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tclientPort := tcp.PickPort()\n\tclientConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(clientPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&outbound.Config{\n\t\t\t\t\tReceiver: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(serverPort),\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\t\t\tId: userID.String(),\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t},\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\tSenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{\n\t\t\t\t\tStreamSettings: &internet.StreamConfig{\n\t\t\t\t\t\tProtocol: internet.TransportProtocol_WebSocket,\n\t\t\t\t\t\tTransportSettings: []*internet.TransportConfig{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tProtocol: internet.TransportProtocol_WebSocket,\n\t\t\t\t\t\t\t\tSettings: serial.ToTypedMessage(&websocket.Config{}),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tSecurityType: serial.GetMessageType(&tls.Config{}),\n\t\t\t\t\t\tSecuritySettings: []*serial.TypedMessage{\n\t\t\t\t\t\t\tserial.ToTypedMessage(&tls.Config{\n\t\t\t\t\t\t\t\tAllowInsecure: true,\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},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig, clientConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\tvar errg errgroup.Group\n\tfor i := 0; i < 10; i++ {\n\t\terrg.Go(testTCPConn(clientPort, 10240*1024, time.Second*20))\n\t}\n\tif err := errg.Wait(); err != nil {\n\t\tt.Error(err)\n\t}\n}\n\nfunc TestHTTP2(t *testing.T) {\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\tdefer tcpServer.Close()\n\n\tuserID := protocol.NewID(uuid.New())\n\tserverPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\tStreamSettings: &internet.StreamConfig{\n\t\t\t\t\t\tProtocol: internet.TransportProtocol_HTTP,\n\t\t\t\t\t\tTransportSettings: []*internet.TransportConfig{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tProtocol: internet.TransportProtocol_HTTP,\n\t\t\t\t\t\t\t\tSettings: serial.ToTypedMessage(&http.Config{\n\t\t\t\t\t\t\t\t\tHost: []string{\"v2ray.com\"},\n\t\t\t\t\t\t\t\t\tPath: \"/testpath\",\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tSecurityType: serial.GetMessageType(&tls.Config{}),\n\t\t\t\t\t\tSecuritySettings: []*serial.TypedMessage{\n\t\t\t\t\t\t\tserial.ToTypedMessage(&tls.Config{\n\t\t\t\t\t\t\t\tCertificate: []*tls.Certificate{tls.ParseCertificate(cert.MustGenerate(nil))},\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\tProxySettings: serial.ToTypedMessage(&inbound.Config{\n\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\tId: userID.String(),\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},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tclientPort := tcp.PickPort()\n\tclientConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(clientPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&outbound.Config{\n\t\t\t\t\tReceiver: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(serverPort),\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\t\t\tId: userID.String(),\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t},\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\tSenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{\n\t\t\t\t\tStreamSettings: &internet.StreamConfig{\n\t\t\t\t\t\tProtocol: internet.TransportProtocol_HTTP,\n\t\t\t\t\t\tTransportSettings: []*internet.TransportConfig{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tProtocol: internet.TransportProtocol_HTTP,\n\t\t\t\t\t\t\t\tSettings: serial.ToTypedMessage(&http.Config{\n\t\t\t\t\t\t\t\t\tHost: []string{\"v2ray.com\"},\n\t\t\t\t\t\t\t\t\tPath: \"/testpath\",\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tSecurityType: serial.GetMessageType(&tls.Config{}),\n\t\t\t\t\t\tSecuritySettings: []*serial.TypedMessage{\n\t\t\t\t\t\t\tserial.ToTypedMessage(&tls.Config{\n\t\t\t\t\t\t\t\tAllowInsecure: true,\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},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig, clientConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\tvar errg errgroup.Group\n\tfor i := 0; i < 10; i++ {\n\t\terrg.Go(testTCPConn(clientPort, 10240*1024, time.Second*40))\n\t}\n\tif err := errg.Wait(); err != nil {\n\t\tt.Error(err)\n\t}\n}\n"
  },
  {
    "path": "testing/scenarios/transport_test.go",
    "content": "package scenarios\n\nimport (\n\t\"os\"\n\t\"runtime\"\n\t\"testing\"\n\t\"time\"\n\n\t\"golang.org/x/sync/errgroup\"\n\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/app/log\"\n\t\"v2ray.com/core/app/proxyman\"\n\t\"v2ray.com/core/common\"\n\tclog \"v2ray.com/core/common/log\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/serial\"\n\t\"v2ray.com/core/common/uuid\"\n\t\"v2ray.com/core/proxy/dokodemo\"\n\t\"v2ray.com/core/proxy/freedom\"\n\t\"v2ray.com/core/proxy/vmess\"\n\t\"v2ray.com/core/proxy/vmess/inbound\"\n\t\"v2ray.com/core/proxy/vmess/outbound\"\n\t\"v2ray.com/core/testing/servers/tcp\"\n\t\"v2ray.com/core/transport/internet\"\n\t\"v2ray.com/core/transport/internet/domainsocket\"\n\t\"v2ray.com/core/transport/internet/headers/http\"\n\t\"v2ray.com/core/transport/internet/headers/wechat\"\n\t\"v2ray.com/core/transport/internet/quic\"\n\ttcptransport \"v2ray.com/core/transport/internet/tcp\"\n)\n\nfunc TestHttpConnectionHeader(t *testing.T) {\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\tdefer tcpServer.Close()\n\n\tuserID := protocol.NewID(uuid.New())\n\tserverPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\tStreamSettings: &internet.StreamConfig{\n\t\t\t\t\t\tTransportSettings: []*internet.TransportConfig{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tProtocol: internet.TransportProtocol_TCP,\n\t\t\t\t\t\t\t\tSettings: serial.ToTypedMessage(&tcptransport.Config{\n\t\t\t\t\t\t\t\t\tHeaderSettings: serial.ToTypedMessage(&http.Config{}),\n\t\t\t\t\t\t\t\t}),\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\tProxySettings: serial.ToTypedMessage(&inbound.Config{\n\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\tId: userID.String(),\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},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tclientPort := tcp.PickPort()\n\tclientConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(clientPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&outbound.Config{\n\t\t\t\t\tReceiver: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(serverPort),\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\t\t\tId: userID.String(),\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t},\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\tSenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{\n\t\t\t\t\tStreamSettings: &internet.StreamConfig{\n\t\t\t\t\t\tTransportSettings: []*internet.TransportConfig{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tProtocol: internet.TransportProtocol_TCP,\n\t\t\t\t\t\t\t\tSettings: serial.ToTypedMessage(&tcptransport.Config{\n\t\t\t\t\t\t\t\t\tHeaderSettings: serial.ToTypedMessage(&http.Config{}),\n\t\t\t\t\t\t\t\t}),\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},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig, clientConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\tif err := testTCPConn(clientPort, 1024, time.Second*2)(); err != nil {\n\t\tt.Error(err)\n\t}\n}\n\nfunc TestDomainSocket(t *testing.T) {\n\tif runtime.GOOS == \"windows\" {\n\t\tt.Skip(\"Not supported on windows\")\n\t\treturn\n\t}\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\tdefer tcpServer.Close()\n\n\tconst dsPath = \"/tmp/ds_scenario\"\n\tos.Remove(dsPath)\n\n\tuserID := protocol.NewID(uuid.New())\n\tserverPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\tStreamSettings: &internet.StreamConfig{\n\t\t\t\t\t\tProtocol: internet.TransportProtocol_DomainSocket,\n\t\t\t\t\t\tTransportSettings: []*internet.TransportConfig{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tProtocol: internet.TransportProtocol_DomainSocket,\n\t\t\t\t\t\t\t\tSettings: serial.ToTypedMessage(&domainsocket.Config{\n\t\t\t\t\t\t\t\t\tPath: dsPath,\n\t\t\t\t\t\t\t\t}),\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\tProxySettings: serial.ToTypedMessage(&inbound.Config{\n\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\tId: userID.String(),\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},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tclientPort := tcp.PickPort()\n\tclientConfig := &core.Config{\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(clientPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&outbound.Config{\n\t\t\t\t\tReceiver: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(serverPort),\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\t\t\tId: userID.String(),\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t},\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\tSenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{\n\t\t\t\t\tStreamSettings: &internet.StreamConfig{\n\t\t\t\t\t\tProtocol: internet.TransportProtocol_DomainSocket,\n\t\t\t\t\t\tTransportSettings: []*internet.TransportConfig{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tProtocol: internet.TransportProtocol_DomainSocket,\n\t\t\t\t\t\t\t\tSettings: serial.ToTypedMessage(&domainsocket.Config{\n\t\t\t\t\t\t\t\t\tPath: dsPath,\n\t\t\t\t\t\t\t\t}),\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},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig, clientConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\tif err := testTCPConn(clientPort, 1024, time.Second*2)(); err != nil {\n\t\tt.Error(err)\n\t}\n}\n\nfunc TestVMessQuic(t *testing.T) {\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\tdefer tcpServer.Close()\n\n\tuserID := protocol.NewID(uuid.New())\n\tserverPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&log.Config{\n\t\t\t\tErrorLogLevel: clog.Severity_Debug,\n\t\t\t\tErrorLogType:  log.LogType_Console,\n\t\t\t}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\tStreamSettings: &internet.StreamConfig{\n\t\t\t\t\t\tProtocolName: \"quic\",\n\t\t\t\t\t\tTransportSettings: []*internet.TransportConfig{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tProtocolName: \"quic\",\n\t\t\t\t\t\t\t\tSettings: serial.ToTypedMessage(&quic.Config{\n\t\t\t\t\t\t\t\t\tHeader: serial.ToTypedMessage(&wechat.VideoConfig{}),\n\t\t\t\t\t\t\t\t\tSecurity: &protocol.SecurityConfig{\n\t\t\t\t\t\t\t\t\t\tType: protocol.SecurityType_NONE,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t}),\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\tProxySettings: serial.ToTypedMessage(&inbound.Config{\n\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\tId:      userID.String(),\n\t\t\t\t\t\t\t\tAlterId: 64,\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},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tclientPort := tcp.PickPort()\n\tclientConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&log.Config{\n\t\t\t\tErrorLogLevel: clog.Severity_Debug,\n\t\t\t\tErrorLogType:  log.LogType_Console,\n\t\t\t}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(clientPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tSenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{\n\t\t\t\t\tStreamSettings: &internet.StreamConfig{\n\t\t\t\t\t\tProtocolName: \"quic\",\n\t\t\t\t\t\tTransportSettings: []*internet.TransportConfig{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tProtocolName: \"quic\",\n\t\t\t\t\t\t\t\tSettings: serial.ToTypedMessage(&quic.Config{\n\t\t\t\t\t\t\t\t\tHeader: serial.ToTypedMessage(&wechat.VideoConfig{}),\n\t\t\t\t\t\t\t\t\tSecurity: &protocol.SecurityConfig{\n\t\t\t\t\t\t\t\t\t\tType: protocol.SecurityType_NONE,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t}),\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\tProxySettings: serial.ToTypedMessage(&outbound.Config{\n\t\t\t\t\tReceiver: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(serverPort),\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\t\t\tId:      userID.String(),\n\t\t\t\t\t\t\t\t\t\tAlterId: 64,\n\t\t\t\t\t\t\t\t\t\tSecuritySettings: &protocol.SecurityConfig{\n\t\t\t\t\t\t\t\t\t\t\tType: protocol.SecurityType_AES128_GCM,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t},\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},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig, clientConfig)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize all servers: \", err.Error())\n\t}\n\tdefer CloseAllServers(servers)\n\n\tvar errg errgroup.Group\n\tfor i := 0; i < 10; i++ {\n\t\terrg.Go(testTCPConn(clientPort, 10240*1024, time.Second*40))\n\t}\n\n\tif err := errg.Wait(); err != nil {\n\t\tt.Error(err)\n\t}\n}\n"
  },
  {
    "path": "testing/scenarios/vmess_test.go",
    "content": "package scenarios\n\nimport (\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"golang.org/x/sync/errgroup\"\n\t\"v2ray.com/core\"\n\t\"v2ray.com/core/app/log\"\n\t\"v2ray.com/core/app/proxyman\"\n\t\"v2ray.com/core/common\"\n\tclog \"v2ray.com/core/common/log\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/serial\"\n\t\"v2ray.com/core/common/uuid\"\n\t\"v2ray.com/core/proxy/dokodemo\"\n\t\"v2ray.com/core/proxy/freedom\"\n\t\"v2ray.com/core/proxy/vmess\"\n\t\"v2ray.com/core/proxy/vmess/inbound\"\n\t\"v2ray.com/core/proxy/vmess/outbound\"\n\t\"v2ray.com/core/testing/servers/tcp\"\n\t\"v2ray.com/core/testing/servers/udp\"\n\t\"v2ray.com/core/transport/internet\"\n\t\"v2ray.com/core/transport/internet/kcp\"\n)\n\nfunc TestVMessDynamicPort(t *testing.T) {\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\tdefer tcpServer.Close()\n\n\tuserID := protocol.NewID(uuid.New())\n\tserverPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&log.Config{\n\t\t\t\tErrorLogLevel: clog.Severity_Debug,\n\t\t\t\tErrorLogType:  log.LogType_Console,\n\t\t\t}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&inbound.Config{\n\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\tId: userID.String(),\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\tDetour: &inbound.DetourConfig{\n\t\t\t\t\t\tTo: \"detour\",\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: &net.PortRange{\n\t\t\t\t\t\tFrom: uint32(serverPort + 1),\n\t\t\t\t\t\tTo:   uint32(serverPort + 100),\n\t\t\t\t\t},\n\t\t\t\t\tListen: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\tAllocationStrategy: &proxyman.AllocationStrategy{\n\t\t\t\t\t\tType: proxyman.AllocationStrategy_Random,\n\t\t\t\t\t\tConcurrency: &proxyman.AllocationStrategy_AllocationStrategyConcurrency{\n\t\t\t\t\t\t\tValue: 2,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tRefresh: &proxyman.AllocationStrategy_AllocationStrategyRefresh{\n\t\t\t\t\t\t\tValue: 5,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&inbound.Config{}),\n\t\t\t\tTag:           \"detour\",\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tclientPort := tcp.PickPort()\n\tclientConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&log.Config{\n\t\t\t\tErrorLogLevel: clog.Severity_Debug,\n\t\t\t\tErrorLogType:  log.LogType_Console,\n\t\t\t}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(clientPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&outbound.Config{\n\t\t\t\t\tReceiver: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(serverPort),\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\t\t\tId: userID.String(),\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t},\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},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig, clientConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\tfor i := 0; i < 10; i++ {\n\t\tif err := testTCPConn(clientPort, 1024, time.Second*2)(); err != nil {\n\t\t\tt.Error(err)\n\t\t}\n\t}\n}\n\nfunc TestVMessGCM(t *testing.T) {\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\tdefer tcpServer.Close()\n\n\tuserID := protocol.NewID(uuid.New())\n\tserverPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&log.Config{\n\t\t\t\tErrorLogLevel: clog.Severity_Debug,\n\t\t\t\tErrorLogType:  log.LogType_Console,\n\t\t\t}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&inbound.Config{\n\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\tId:      userID.String(),\n\t\t\t\t\t\t\t\tAlterId: 64,\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},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tclientPort := tcp.PickPort()\n\tclientConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&log.Config{\n\t\t\t\tErrorLogLevel: clog.Severity_Debug,\n\t\t\t\tErrorLogType:  log.LogType_Console,\n\t\t\t}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(clientPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&outbound.Config{\n\t\t\t\t\tReceiver: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(serverPort),\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\t\t\tId:      userID.String(),\n\t\t\t\t\t\t\t\t\t\tAlterId: 64,\n\t\t\t\t\t\t\t\t\t\tSecuritySettings: &protocol.SecurityConfig{\n\t\t\t\t\t\t\t\t\t\t\tType: protocol.SecurityType_AES128_GCM,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t},\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},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig, clientConfig)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize all servers: \", err.Error())\n\t}\n\tdefer CloseAllServers(servers)\n\n\tvar errg errgroup.Group\n\tfor i := 0; i < 10; i++ {\n\t\terrg.Go(testTCPConn(clientPort, 10240*1024, time.Second*40))\n\t}\n\n\tif err := errg.Wait(); err != nil {\n\t\tt.Error(err)\n\t}\n}\n\nfunc TestVMessGCMReadv(t *testing.T) {\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\tdefer tcpServer.Close()\n\n\tuserID := protocol.NewID(uuid.New())\n\tserverPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&log.Config{\n\t\t\t\tErrorLogLevel: clog.Severity_Debug,\n\t\t\t\tErrorLogType:  log.LogType_Console,\n\t\t\t}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&inbound.Config{\n\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\tId:      userID.String(),\n\t\t\t\t\t\t\t\tAlterId: 64,\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},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tclientPort := tcp.PickPort()\n\tclientConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&log.Config{\n\t\t\t\tErrorLogLevel: clog.Severity_Debug,\n\t\t\t\tErrorLogType:  log.LogType_Console,\n\t\t\t}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(clientPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&outbound.Config{\n\t\t\t\t\tReceiver: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(serverPort),\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\t\t\tId:      userID.String(),\n\t\t\t\t\t\t\t\t\t\tAlterId: 64,\n\t\t\t\t\t\t\t\t\t\tSecuritySettings: &protocol.SecurityConfig{\n\t\t\t\t\t\t\t\t\t\t\tType: protocol.SecurityType_AES128_GCM,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t},\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},\n\t}\n\n\tconst envName = \"V2RAY_BUF_READV\"\n\tcommon.Must(os.Setenv(envName, \"enable\"))\n\tdefer os.Unsetenv(envName)\n\n\tservers, err := InitializeServerConfigs(serverConfig, clientConfig)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize all servers: \", err.Error())\n\t}\n\tdefer CloseAllServers(servers)\n\n\tvar errg errgroup.Group\n\tfor i := 0; i < 10; i++ {\n\t\terrg.Go(testTCPConn(clientPort, 10240*1024, time.Second*40))\n\t}\n\tif err := errg.Wait(); err != nil {\n\t\tt.Error(err)\n\t}\n}\n\nfunc TestVMessGCMUDP(t *testing.T) {\n\tudpServer := udp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := udpServer.Start()\n\tcommon.Must(err)\n\tdefer udpServer.Close()\n\n\tuserID := protocol.NewID(uuid.New())\n\tserverPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&log.Config{\n\t\t\t\tErrorLogLevel: clog.Severity_Debug,\n\t\t\t\tErrorLogType:  log.LogType_Console,\n\t\t\t}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&inbound.Config{\n\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\tId:      userID.String(),\n\t\t\t\t\t\t\t\tAlterId: 64,\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},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tclientPort := tcp.PickPort()\n\tclientConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&log.Config{\n\t\t\t\tErrorLogLevel: clog.Severity_Debug,\n\t\t\t\tErrorLogType:  log.LogType_Console,\n\t\t\t}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(clientPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_UDP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&outbound.Config{\n\t\t\t\t\tReceiver: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(serverPort),\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\t\t\tId:      userID.String(),\n\t\t\t\t\t\t\t\t\t\tAlterId: 64,\n\t\t\t\t\t\t\t\t\t\tSecuritySettings: &protocol.SecurityConfig{\n\t\t\t\t\t\t\t\t\t\t\tType: protocol.SecurityType_AES128_GCM,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t},\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},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig, clientConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\tvar errg errgroup.Group\n\tfor i := 0; i < 10; i++ {\n\t\terrg.Go(testUDPConn(clientPort, 1024, time.Second*5))\n\t}\n\tif err := errg.Wait(); err != nil {\n\t\tt.Error(err)\n\t}\n}\n\nfunc TestVMessChacha20(t *testing.T) {\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\tdefer tcpServer.Close()\n\n\tuserID := protocol.NewID(uuid.New())\n\tserverPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&log.Config{\n\t\t\t\tErrorLogLevel: clog.Severity_Debug,\n\t\t\t\tErrorLogType:  log.LogType_Console,\n\t\t\t}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&inbound.Config{\n\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\tId:      userID.String(),\n\t\t\t\t\t\t\t\tAlterId: 64,\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},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tclientPort := tcp.PickPort()\n\tclientConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&log.Config{\n\t\t\t\tErrorLogLevel: clog.Severity_Debug,\n\t\t\t\tErrorLogType:  log.LogType_Console,\n\t\t\t}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(clientPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&outbound.Config{\n\t\t\t\t\tReceiver: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(serverPort),\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\t\t\tId:      userID.String(),\n\t\t\t\t\t\t\t\t\t\tAlterId: 64,\n\t\t\t\t\t\t\t\t\t\tSecuritySettings: &protocol.SecurityConfig{\n\t\t\t\t\t\t\t\t\t\t\tType: protocol.SecurityType_CHACHA20_POLY1305,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t},\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},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig, clientConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\tvar errg errgroup.Group\n\tfor i := 0; i < 10; i++ {\n\t\terrg.Go(testTCPConn(clientPort, 10240*1024, time.Second*20))\n\t}\n\n\tif err := errg.Wait(); err != nil {\n\t\tt.Error(err)\n\t}\n}\n\nfunc TestVMessNone(t *testing.T) {\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\tdefer tcpServer.Close()\n\n\tuserID := protocol.NewID(uuid.New())\n\tserverPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&log.Config{\n\t\t\t\tErrorLogLevel: clog.Severity_Debug,\n\t\t\t\tErrorLogType:  log.LogType_Console,\n\t\t\t}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&inbound.Config{\n\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\tId:      userID.String(),\n\t\t\t\t\t\t\t\tAlterId: 64,\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},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tclientPort := tcp.PickPort()\n\tclientConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&log.Config{\n\t\t\t\tErrorLogLevel: clog.Severity_Debug,\n\t\t\t\tErrorLogType:  log.LogType_Console,\n\t\t\t}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(clientPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&outbound.Config{\n\t\t\t\t\tReceiver: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(serverPort),\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\t\t\tId:      userID.String(),\n\t\t\t\t\t\t\t\t\t\tAlterId: 64,\n\t\t\t\t\t\t\t\t\t\tSecuritySettings: &protocol.SecurityConfig{\n\t\t\t\t\t\t\t\t\t\t\tType: protocol.SecurityType_NONE,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t},\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},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig, clientConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\tvar errg errgroup.Group\n\tfor i := 0; i < 10; i++ {\n\t\terrg.Go(testTCPConn(clientPort, 1024*1024, time.Second*30))\n\t}\n\tif err := errg.Wait(); err != nil {\n\t\tt.Error(err)\n\t}\n}\n\nfunc TestVMessKCP(t *testing.T) {\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\tdefer tcpServer.Close()\n\n\tuserID := protocol.NewID(uuid.New())\n\tserverPort := udp.PickPort()\n\tserverConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&log.Config{\n\t\t\t\tErrorLogLevel: clog.Severity_Debug,\n\t\t\t\tErrorLogType:  log.LogType_Console,\n\t\t\t}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\tStreamSettings: &internet.StreamConfig{\n\t\t\t\t\t\tProtocol: internet.TransportProtocol_MKCP,\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&inbound.Config{\n\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\tId:      userID.String(),\n\t\t\t\t\t\t\t\tAlterId: 64,\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},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tclientPort := tcp.PickPort()\n\tclientConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&log.Config{\n\t\t\t\tErrorLogLevel: clog.Severity_Debug,\n\t\t\t\tErrorLogType:  log.LogType_Console,\n\t\t\t}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(clientPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&outbound.Config{\n\t\t\t\t\tReceiver: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(serverPort),\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\t\t\tId:      userID.String(),\n\t\t\t\t\t\t\t\t\t\tAlterId: 64,\n\t\t\t\t\t\t\t\t\t\tSecuritySettings: &protocol.SecurityConfig{\n\t\t\t\t\t\t\t\t\t\t\tType: protocol.SecurityType_AES128_GCM,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t},\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\tSenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{\n\t\t\t\t\tStreamSettings: &internet.StreamConfig{\n\t\t\t\t\t\tProtocol: internet.TransportProtocol_MKCP,\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig, clientConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\tvar errg errgroup.Group\n\tfor i := 0; i < 10; i++ {\n\t\terrg.Go(testTCPConn(clientPort, 10240*1024, time.Minute*2))\n\t}\n\tif err := errg.Wait(); err != nil {\n\t\tt.Error(err)\n\t}\n}\n\nfunc TestVMessKCPLarge(t *testing.T) {\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\tdefer tcpServer.Close()\n\n\tuserID := protocol.NewID(uuid.New())\n\tserverPort := udp.PickPort()\n\tserverConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&log.Config{\n\t\t\t\tErrorLogLevel: clog.Severity_Debug,\n\t\t\t\tErrorLogType:  log.LogType_Console,\n\t\t\t}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\tStreamSettings: &internet.StreamConfig{\n\t\t\t\t\t\tProtocol: internet.TransportProtocol_MKCP,\n\t\t\t\t\t\tTransportSettings: []*internet.TransportConfig{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tProtocol: internet.TransportProtocol_MKCP,\n\t\t\t\t\t\t\t\tSettings: serial.ToTypedMessage(&kcp.Config{\n\t\t\t\t\t\t\t\t\tReadBuffer: &kcp.ReadBuffer{\n\t\t\t\t\t\t\t\t\t\tSize: 512 * 1024,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tWriteBuffer: &kcp.WriteBuffer{\n\t\t\t\t\t\t\t\t\t\tSize: 512 * 1024,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tUplinkCapacity: &kcp.UplinkCapacity{\n\t\t\t\t\t\t\t\t\t\tValue: 20,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tDownlinkCapacity: &kcp.DownlinkCapacity{\n\t\t\t\t\t\t\t\t\t\tValue: 20,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t}),\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\tProxySettings: serial.ToTypedMessage(&inbound.Config{\n\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\tId:      userID.String(),\n\t\t\t\t\t\t\t\tAlterId: 64,\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},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tclientPort := tcp.PickPort()\n\tclientConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&log.Config{\n\t\t\t\tErrorLogLevel: clog.Severity_Debug,\n\t\t\t\tErrorLogType:  log.LogType_Console,\n\t\t\t}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(clientPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&outbound.Config{\n\t\t\t\t\tReceiver: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(serverPort),\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\t\t\tId:      userID.String(),\n\t\t\t\t\t\t\t\t\t\tAlterId: 64,\n\t\t\t\t\t\t\t\t\t\tSecuritySettings: &protocol.SecurityConfig{\n\t\t\t\t\t\t\t\t\t\t\tType: protocol.SecurityType_AES128_GCM,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t},\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\tSenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{\n\t\t\t\t\tStreamSettings: &internet.StreamConfig{\n\t\t\t\t\t\tProtocol: internet.TransportProtocol_MKCP,\n\t\t\t\t\t\tTransportSettings: []*internet.TransportConfig{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tProtocol: internet.TransportProtocol_MKCP,\n\t\t\t\t\t\t\t\tSettings: serial.ToTypedMessage(&kcp.Config{\n\t\t\t\t\t\t\t\t\tReadBuffer: &kcp.ReadBuffer{\n\t\t\t\t\t\t\t\t\t\tSize: 512 * 1024,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tWriteBuffer: &kcp.WriteBuffer{\n\t\t\t\t\t\t\t\t\t\tSize: 512 * 1024,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tUplinkCapacity: &kcp.UplinkCapacity{\n\t\t\t\t\t\t\t\t\t\tValue: 20,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tDownlinkCapacity: &kcp.DownlinkCapacity{\n\t\t\t\t\t\t\t\t\t\tValue: 20,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t}),\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},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig, clientConfig)\n\tcommon.Must(err)\n\n\tvar errg errgroup.Group\n\tfor i := 0; i < 2; i++ {\n\t\terrg.Go(testTCPConn(clientPort, 10240*1024, time.Minute*5))\n\t}\n\tif err := errg.Wait(); err != nil {\n\t\tt.Error(err)\n\t}\n\n\tdefer func() {\n\t\t<-time.After(5 * time.Second)\n\t\tCloseAllServers(servers)\n\t}()\n}\n\nfunc TestVMessGCMMux(t *testing.T) {\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\tdefer tcpServer.Close()\n\n\tuserID := protocol.NewID(uuid.New())\n\tserverPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&log.Config{\n\t\t\t\tErrorLogLevel: clog.Severity_Debug,\n\t\t\t\tErrorLogType:  log.LogType_Console,\n\t\t\t}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&inbound.Config{\n\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\tId:      userID.String(),\n\t\t\t\t\t\t\t\tAlterId: 64,\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},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tclientPort := tcp.PickPort()\n\tclientConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&log.Config{\n\t\t\t\tErrorLogLevel: clog.Severity_Debug,\n\t\t\t\tErrorLogType:  log.LogType_Console,\n\t\t\t}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(clientPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tSenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{\n\t\t\t\t\tMultiplexSettings: &proxyman.MultiplexingConfig{\n\t\t\t\t\t\tEnabled:     true,\n\t\t\t\t\t\tConcurrency: 4,\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&outbound.Config{\n\t\t\t\t\tReceiver: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(serverPort),\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\t\t\tId:      userID.String(),\n\t\t\t\t\t\t\t\t\t\tAlterId: 64,\n\t\t\t\t\t\t\t\t\t\tSecuritySettings: &protocol.SecurityConfig{\n\t\t\t\t\t\t\t\t\t\t\tType: protocol.SecurityType_AES128_GCM,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t},\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},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig, clientConfig)\n\tcommon.Must(err)\n\tdefer CloseAllServers(servers)\n\n\tfor range \"abcd\" {\n\t\tvar errg errgroup.Group\n\t\tfor i := 0; i < 16; i++ {\n\t\t\terrg.Go(testTCPConn(clientPort, 10240, time.Second*20))\n\t\t}\n\t\tif err := errg.Wait(); err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t\ttime.Sleep(time.Second)\n\t}\n}\n\nfunc TestVMessGCMMuxUDP(t *testing.T) {\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\tdefer tcpServer.Close()\n\n\tudpServer := udp.Server{\n\t\tMsgProcessor: xor,\n\t}\n\tudpDest, err := udpServer.Start()\n\tcommon.Must(err)\n\tdefer udpServer.Close()\n\n\tuserID := protocol.NewID(uuid.New())\n\tserverPort := tcp.PickPort()\n\tserverConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&log.Config{\n\t\t\t\tErrorLogLevel: clog.Severity_Debug,\n\t\t\t\tErrorLogType:  log.LogType_Console,\n\t\t\t}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(serverPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&inbound.Config{\n\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\tId:      userID.String(),\n\t\t\t\t\t\t\t\tAlterId: 64,\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},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&freedom.Config{}),\n\t\t\t},\n\t\t},\n\t}\n\n\tclientPort := tcp.PickPort()\n\tclientUDPPort := udp.PickPort()\n\tclientConfig := &core.Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&log.Config{\n\t\t\t\tErrorLogLevel: clog.Severity_Debug,\n\t\t\t\tErrorLogType:  log.LogType_Console,\n\t\t\t}),\n\t\t},\n\t\tInbound: []*core.InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(clientPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(dest.Address),\n\t\t\t\t\tPort:    uint32(dest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_TCP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(clientUDPPort),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(udpDest.Address),\n\t\t\t\t\tPort:    uint32(udpDest.Port),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_UDP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*core.OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tSenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{\n\t\t\t\t\tMultiplexSettings: &proxyman.MultiplexingConfig{\n\t\t\t\t\t\tEnabled:     true,\n\t\t\t\t\t\tConcurrency: 4,\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&outbound.Config{\n\t\t\t\t\tReceiver: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(serverPort),\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\t\t\tId:      userID.String(),\n\t\t\t\t\t\t\t\t\t\tAlterId: 64,\n\t\t\t\t\t\t\t\t\t\tSecuritySettings: &protocol.SecurityConfig{\n\t\t\t\t\t\t\t\t\t\t\tType: protocol.SecurityType_AES128_GCM,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t},\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},\n\t}\n\n\tservers, err := InitializeServerConfigs(serverConfig, clientConfig)\n\tcommon.Must(err)\n\n\tfor range \"abcd\" {\n\t\tvar errg errgroup.Group\n\t\tfor i := 0; i < 16; i++ {\n\t\t\terrg.Go(testTCPConn(clientPort, 10240, time.Second*20))\n\t\t\terrg.Go(testUDPConn(clientUDPPort, 1024, time.Second*10))\n\t\t}\n\t\tif err := errg.Wait(); err != nil {\n\t\t\tt.Error(err)\n\t\t}\n\t\ttime.Sleep(time.Second)\n\t}\n\n\tdefer func() {\n\t\t<-time.After(5 * time.Second)\n\t\tCloseAllServers(servers)\n\t}()\n}\n"
  },
  {
    "path": "testing/servers/http/http.go",
    "content": "package tcp\n\nimport (\n\t\"net/http\"\n\n\t\"v2ray.com/core/common/net\"\n)\n\ntype Server struct {\n\tPort        net.Port\n\tPathHandler map[string]http.HandlerFunc\n\tserver      *http.Server\n}\n\nfunc (s *Server) ServeHTTP(resp http.ResponseWriter, req *http.Request) {\n\tif req.URL.Path == \"/\" {\n\t\tresp.Header().Set(\"Content-Type\", \"text/plain; charset=utf-8\")\n\t\tresp.WriteHeader(http.StatusOK)\n\t\tresp.Write([]byte(\"Home\"))\n\t\treturn\n\t}\n\n\thandler, found := s.PathHandler[req.URL.Path]\n\tif found {\n\t\thandler(resp, req)\n\t}\n}\n\nfunc (s *Server) Start() (net.Destination, error) {\n\ts.server = &http.Server{\n\t\tAddr:    \"127.0.0.1:\" + s.Port.String(),\n\t\tHandler: s,\n\t}\n\tgo s.server.ListenAndServe()\n\treturn net.TCPDestination(net.LocalHostIP, net.Port(s.Port)), nil\n}\n\nfunc (s *Server) Close() error {\n\treturn s.server.Close()\n}\n"
  },
  {
    "path": "testing/servers/tcp/port.go",
    "content": "package tcp\n\nimport (\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/net\"\n)\n\n// PickPort returns an unused TCP port in the system. The port returned is highly likely to be unused, but not guaranteed.\nfunc PickPort() net.Port {\n\tlistener, err := net.Listen(\"tcp4\", \"127.0.0.1:0\")\n\tcommon.Must(err)\n\tdefer listener.Close()\n\n\taddr := listener.Addr().(*net.TCPAddr)\n\treturn net.Port(addr.Port)\n}\n"
  },
  {
    "path": "testing/servers/tcp/tcp.go",
    "content": "package tcp\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/task\"\n\t\"v2ray.com/core/transport/internet\"\n\t\"v2ray.com/core/transport/pipe\"\n)\n\ntype Server struct {\n\tPort         net.Port\n\tMsgProcessor func(msg []byte) []byte\n\tShouldClose  bool\n\tSendFirst    []byte\n\tListen       net.Address\n\tlistener     net.Listener\n}\n\nfunc (server *Server) Start() (net.Destination, error) {\n\treturn server.StartContext(context.Background(), nil)\n}\n\nfunc (server *Server) StartContext(ctx context.Context, sockopt *internet.SocketConfig) (net.Destination, error) {\n\tlistenerAddr := server.Listen\n\tif listenerAddr == nil {\n\t\tlistenerAddr = net.LocalHostIP\n\t}\n\tlistener, err := internet.ListenSystem(ctx, &net.TCPAddr{\n\t\tIP:   listenerAddr.IP(),\n\t\tPort: int(server.Port),\n\t}, sockopt)\n\tif err != nil {\n\t\treturn net.Destination{}, err\n\t}\n\n\tlocalAddr := listener.Addr().(*net.TCPAddr)\n\tserver.Port = net.Port(localAddr.Port)\n\tserver.listener = listener\n\tgo server.acceptConnections(listener.(*net.TCPListener))\n\n\treturn net.TCPDestination(net.IPAddress(localAddr.IP), net.Port(localAddr.Port)), nil\n}\n\nfunc (server *Server) acceptConnections(listener *net.TCPListener) {\n\tfor {\n\t\tconn, err := listener.Accept()\n\t\tif err != nil {\n\t\t\tfmt.Printf(\"Failed accept TCP connection: %v\\n\", err)\n\t\t\treturn\n\t\t}\n\n\t\tgo server.handleConnection(conn)\n\t}\n}\n\nfunc (server *Server) handleConnection(conn net.Conn) {\n\tif len(server.SendFirst) > 0 {\n\t\tconn.Write(server.SendFirst)\n\t}\n\n\tpReader, pWriter := pipe.New(pipe.WithoutSizeLimit())\n\terr := task.Run(context.Background(), func() error {\n\t\tdefer pWriter.Close() // nolint: errcheck\n\n\t\tfor {\n\t\t\tb := buf.New()\n\t\t\tif _, err := b.ReadFrom(conn); err != nil {\n\t\t\t\tif err == io.EOF {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tcopy(b.Bytes(), server.MsgProcessor(b.Bytes()))\n\t\t\tif err := pWriter.WriteMultiBuffer(buf.MultiBuffer{b}); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}, func() error {\n\t\tdefer pReader.Interrupt()\n\n\t\tw := buf.NewWriter(conn)\n\t\tfor {\n\t\t\tmb, err := pReader.ReadMultiBuffer()\n\t\t\tif err != nil {\n\t\t\t\tif err == io.EOF {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif err := w.WriteMultiBuffer(mb); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t})\n\n\tif err != nil {\n\t\tfmt.Println(\"failed to transfer data: \", err.Error())\n\t}\n\n\tconn.Close() // nolint: errcheck\n}\n\nfunc (server *Server) Close() error {\n\treturn server.listener.Close()\n}\n"
  },
  {
    "path": "testing/servers/udp/port.go",
    "content": "package udp\n\nimport (\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/net\"\n)\n\n// PickPort returns an unused UDP port in the system. The port returned is highly likely to be unused, but not guaranteed.\nfunc PickPort() net.Port {\n\tconn, err := net.ListenUDP(\"udp4\", &net.UDPAddr{\n\t\tIP:   net.LocalHostIP.IP(),\n\t\tPort: 0,\n\t})\n\tcommon.Must(err)\n\tdefer conn.Close()\n\n\taddr := conn.LocalAddr().(*net.UDPAddr)\n\treturn net.Port(addr.Port)\n}\n"
  },
  {
    "path": "testing/servers/udp/udp.go",
    "content": "package udp\n\nimport (\n\t\"fmt\"\n\n\t\"v2ray.com/core/common/net\"\n)\n\ntype Server struct {\n\tPort         net.Port\n\tMsgProcessor func(msg []byte) []byte\n\taccepting    bool\n\tconn         *net.UDPConn\n}\n\nfunc (server *Server) Start() (net.Destination, error) {\n\tconn, err := net.ListenUDP(\"udp\", &net.UDPAddr{\n\t\tIP:   []byte{127, 0, 0, 1},\n\t\tPort: int(server.Port),\n\t\tZone: \"\",\n\t})\n\tif err != nil {\n\t\treturn net.Destination{}, err\n\t}\n\tserver.Port = net.Port(conn.LocalAddr().(*net.UDPAddr).Port)\n\tfmt.Println(\"UDP server started on port \", server.Port)\n\n\tserver.conn = conn\n\tgo server.handleConnection(conn)\n\tlocalAddr := conn.LocalAddr().(*net.UDPAddr)\n\treturn net.UDPDestination(net.IPAddress(localAddr.IP), net.Port(localAddr.Port)), nil\n}\n\nfunc (server *Server) handleConnection(conn *net.UDPConn) {\n\tserver.accepting = true\n\tfor server.accepting {\n\t\tbuffer := make([]byte, 2*1024)\n\t\tnBytes, addr, err := conn.ReadFromUDP(buffer)\n\t\tif err != nil {\n\t\t\tfmt.Printf(\"Failed to read from UDP: %v\\n\", err)\n\t\t\tcontinue\n\t\t}\n\n\t\tresponse := server.MsgProcessor(buffer[:nBytes])\n\t\tif _, err := conn.WriteToUDP(response, addr); err != nil {\n\t\t\tfmt.Println(\"Failed to write to UDP: \", err.Error())\n\t\t}\n\t}\n}\n\nfunc (server *Server) Close() error {\n\tserver.accepting = false\n\treturn server.conn.Close()\n}\n"
  },
  {
    "path": "transport/config.go",
    "content": "package transport\n\nimport (\n\t\"v2ray.com/core/transport/internet\"\n)\n\n// Apply applies this Config.\nfunc (c *Config) Apply() error {\n\tif c == nil {\n\t\treturn nil\n\t}\n\treturn internet.ApplyGlobalTransportSettings(c.TransportSettings)\n}\n"
  },
  {
    "path": "transport/config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: transport/config.proto\n\npackage transport\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n\tinternet \"v2ray.com/core/transport/internet\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\n// Global transport settings. This affects all type of connections that go\n// through V2Ray. Deprecated. Use each settings in StreamConfig.\ntype Config struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tTransportSettings []*internet.TransportConfig `protobuf:\"bytes,1,rep,name=transport_settings,json=transportSettings,proto3\" json:\"transport_settings,omitempty\"`\n}\n\nfunc (x *Config) Reset() {\n\t*x = Config{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_transport_config_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Config) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Config) ProtoMessage() {}\n\nfunc (x *Config) ProtoReflect() protoreflect.Message {\n\tmi := &file_transport_config_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Config.ProtoReflect.Descriptor instead.\nfunc (*Config) Descriptor() ([]byte, []int) {\n\treturn file_transport_config_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *Config) GetTransportSettings() []*internet.TransportConfig {\n\tif x != nil {\n\t\treturn x.TransportSettings\n\t}\n\treturn nil\n}\n\nvar File_transport_config_proto protoreflect.FileDescriptor\n\nvar file_transport_config_proto_rawDesc = []byte{\n\t0x0a, 0x16, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x63, 0x6f, 0x6e, 0x66,\n\t0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x14, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,\n\t0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x1a, 0x1f,\n\t0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,\n\t0x65, 0x74, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22,\n\t0x67, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x5d, 0x0a, 0x12, 0x74, 0x72, 0x61,\n\t0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18,\n\t0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,\n\t0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74,\n\t0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x43,\n\t0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x11, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74,\n\t0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x42, 0x4d, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e,\n\t0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73,\n\t0x70, 0x6f, 0x72, 0x74, 0x50, 0x01, 0x5a, 0x18, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,\n\t0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74,\n\t0xaa, 0x02, 0x14, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x54, 0x72,\n\t0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_transport_config_proto_rawDescOnce sync.Once\n\tfile_transport_config_proto_rawDescData = file_transport_config_proto_rawDesc\n)\n\nfunc file_transport_config_proto_rawDescGZIP() []byte {\n\tfile_transport_config_proto_rawDescOnce.Do(func() {\n\t\tfile_transport_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_transport_config_proto_rawDescData)\n\t})\n\treturn file_transport_config_proto_rawDescData\n}\n\nvar file_transport_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)\nvar file_transport_config_proto_goTypes = []interface{}{\n\t(*Config)(nil),                   // 0: v2ray.core.transport.Config\n\t(*internet.TransportConfig)(nil), // 1: v2ray.core.transport.internet.TransportConfig\n}\nvar file_transport_config_proto_depIdxs = []int32{\n\t1, // 0: v2ray.core.transport.Config.transport_settings:type_name -> v2ray.core.transport.internet.TransportConfig\n\t1, // [1:1] is the sub-list for method output_type\n\t1, // [1:1] is the sub-list for method input_type\n\t1, // [1:1] is the sub-list for extension type_name\n\t1, // [1:1] is the sub-list for extension extendee\n\t0, // [0:1] is the sub-list for field type_name\n}\n\nfunc init() { file_transport_config_proto_init() }\nfunc file_transport_config_proto_init() {\n\tif File_transport_config_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_transport_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Config); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_transport_config_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   1,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_transport_config_proto_goTypes,\n\t\tDependencyIndexes: file_transport_config_proto_depIdxs,\n\t\tMessageInfos:      file_transport_config_proto_msgTypes,\n\t}.Build()\n\tFile_transport_config_proto = out.File\n\tfile_transport_config_proto_rawDesc = nil\n\tfile_transport_config_proto_goTypes = nil\n\tfile_transport_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "transport/config.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.transport;\noption csharp_namespace = \"V2Ray.Core.Transport\";\noption go_package = \"v2ray.com/core/transport\";\noption java_package = \"com.v2ray.core.transport\";\noption java_multiple_files = true;\n\nimport \"transport/internet/config.proto\";\n\n// Global transport settings. This affects all type of connections that go\n// through V2Ray. Deprecated. Use each settings in StreamConfig.\nmessage Config {\n  repeated v2ray.core.transport.internet.TransportConfig transport_settings = 1;\n}\n"
  },
  {
    "path": "transport/internet/config.go",
    "content": "package internet\n\nimport (\n\t\"v2ray.com/core/common/serial\"\n\t\"v2ray.com/core/features\"\n)\n\ntype ConfigCreator func() interface{}\n\nvar (\n\tglobalTransportConfigCreatorCache = make(map[string]ConfigCreator)\n\tglobalTransportSettings           []*TransportConfig\n)\n\nconst unknownProtocol = \"unknown\"\n\nfunc transportProtocolToString(protocol TransportProtocol) string {\n\tswitch protocol {\n\tcase TransportProtocol_TCP:\n\t\treturn \"tcp\"\n\tcase TransportProtocol_UDP:\n\t\treturn \"udp\"\n\tcase TransportProtocol_HTTP:\n\t\treturn \"http\"\n\tcase TransportProtocol_MKCP:\n\t\treturn \"mkcp\"\n\tcase TransportProtocol_WebSocket:\n\t\treturn \"websocket\"\n\tcase TransportProtocol_DomainSocket:\n\t\treturn \"domainsocket\"\n\tdefault:\n\t\treturn unknownProtocol\n\t}\n}\n\nfunc RegisterProtocolConfigCreator(name string, creator ConfigCreator) error {\n\tif _, found := globalTransportConfigCreatorCache[name]; found {\n\t\treturn newError(\"protocol \", name, \" is already registered\").AtError()\n\t}\n\tglobalTransportConfigCreatorCache[name] = creator\n\treturn nil\n}\n\nfunc CreateTransportConfig(name string) (interface{}, error) {\n\tcreator, ok := globalTransportConfigCreatorCache[name]\n\tif !ok {\n\t\treturn nil, newError(\"unknown transport protocol: \", name)\n\t}\n\treturn creator(), nil\n}\n\nfunc (c *TransportConfig) GetTypedSettings() (interface{}, error) {\n\treturn c.Settings.GetInstance()\n}\n\nfunc (c *TransportConfig) GetUnifiedProtocolName() string {\n\tif len(c.ProtocolName) > 0 {\n\t\treturn c.ProtocolName\n\t}\n\n\treturn transportProtocolToString(c.Protocol)\n}\n\nfunc (c *StreamConfig) GetEffectiveProtocol() string {\n\tif c == nil {\n\t\treturn \"tcp\"\n\t}\n\n\tif len(c.ProtocolName) > 0 {\n\t\treturn c.ProtocolName\n\t}\n\n\treturn transportProtocolToString(c.Protocol)\n}\n\nfunc (c *StreamConfig) GetEffectiveTransportSettings() (interface{}, error) {\n\tprotocol := c.GetEffectiveProtocol()\n\treturn c.GetTransportSettingsFor(protocol)\n}\n\nfunc (c *StreamConfig) GetTransportSettingsFor(protocol string) (interface{}, error) {\n\tif c != nil {\n\t\tfor _, settings := range c.TransportSettings {\n\t\t\tif settings.GetUnifiedProtocolName() == protocol {\n\t\t\t\treturn settings.GetTypedSettings()\n\t\t\t}\n\t\t}\n\t}\n\n\tfor _, settings := range globalTransportSettings {\n\t\tif settings.GetUnifiedProtocolName() == protocol {\n\t\t\treturn settings.GetTypedSettings()\n\t\t}\n\t}\n\n\treturn CreateTransportConfig(protocol)\n}\n\nfunc (c *StreamConfig) GetEffectiveSecuritySettings() (interface{}, error) {\n\tfor _, settings := range c.SecuritySettings {\n\t\tif settings.Type == c.SecurityType {\n\t\t\treturn settings.GetInstance()\n\t\t}\n\t}\n\treturn serial.GetInstance(c.SecurityType)\n}\n\nfunc (c *StreamConfig) HasSecuritySettings() bool {\n\treturn len(c.SecurityType) > 0\n}\n\nfunc ApplyGlobalTransportSettings(settings []*TransportConfig) error {\n\tfeatures.PrintDeprecatedFeatureWarning(\"global transport settings\")\n\tglobalTransportSettings = settings\n\treturn nil\n}\n\nfunc (c *ProxyConfig) HasTag() bool {\n\treturn c != nil && len(c.Tag) > 0\n}\n\nfunc (m SocketConfig_TProxyMode) IsEnabled() bool {\n\treturn m != SocketConfig_Off\n}\n"
  },
  {
    "path": "transport/internet/config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: transport/internet/config.proto\n\npackage internet\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n\tserial \"v2ray.com/core/common/serial\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype TransportProtocol int32\n\nconst (\n\tTransportProtocol_TCP          TransportProtocol = 0\n\tTransportProtocol_UDP          TransportProtocol = 1\n\tTransportProtocol_MKCP         TransportProtocol = 2\n\tTransportProtocol_WebSocket    TransportProtocol = 3\n\tTransportProtocol_HTTP         TransportProtocol = 4\n\tTransportProtocol_DomainSocket TransportProtocol = 5\n)\n\n// Enum value maps for TransportProtocol.\nvar (\n\tTransportProtocol_name = map[int32]string{\n\t\t0: \"TCP\",\n\t\t1: \"UDP\",\n\t\t2: \"MKCP\",\n\t\t3: \"WebSocket\",\n\t\t4: \"HTTP\",\n\t\t5: \"DomainSocket\",\n\t}\n\tTransportProtocol_value = map[string]int32{\n\t\t\"TCP\":          0,\n\t\t\"UDP\":          1,\n\t\t\"MKCP\":         2,\n\t\t\"WebSocket\":    3,\n\t\t\"HTTP\":         4,\n\t\t\"DomainSocket\": 5,\n\t}\n)\n\nfunc (x TransportProtocol) Enum() *TransportProtocol {\n\tp := new(TransportProtocol)\n\t*p = x\n\treturn p\n}\n\nfunc (x TransportProtocol) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (TransportProtocol) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_transport_internet_config_proto_enumTypes[0].Descriptor()\n}\n\nfunc (TransportProtocol) Type() protoreflect.EnumType {\n\treturn &file_transport_internet_config_proto_enumTypes[0]\n}\n\nfunc (x TransportProtocol) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use TransportProtocol.Descriptor instead.\nfunc (TransportProtocol) EnumDescriptor() ([]byte, []int) {\n\treturn file_transport_internet_config_proto_rawDescGZIP(), []int{0}\n}\n\ntype SocketConfig_TCPFastOpenState int32\n\nconst (\n\t// AsIs is to leave the current TFO state as is, unmodified.\n\tSocketConfig_AsIs SocketConfig_TCPFastOpenState = 0\n\t// Enable is for enabling TFO explictly.\n\tSocketConfig_Enable SocketConfig_TCPFastOpenState = 1\n\t// Disable is for disabling TFO explictly.\n\tSocketConfig_Disable SocketConfig_TCPFastOpenState = 2\n)\n\n// Enum value maps for SocketConfig_TCPFastOpenState.\nvar (\n\tSocketConfig_TCPFastOpenState_name = map[int32]string{\n\t\t0: \"AsIs\",\n\t\t1: \"Enable\",\n\t\t2: \"Disable\",\n\t}\n\tSocketConfig_TCPFastOpenState_value = map[string]int32{\n\t\t\"AsIs\":    0,\n\t\t\"Enable\":  1,\n\t\t\"Disable\": 2,\n\t}\n)\n\nfunc (x SocketConfig_TCPFastOpenState) Enum() *SocketConfig_TCPFastOpenState {\n\tp := new(SocketConfig_TCPFastOpenState)\n\t*p = x\n\treturn p\n}\n\nfunc (x SocketConfig_TCPFastOpenState) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (SocketConfig_TCPFastOpenState) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_transport_internet_config_proto_enumTypes[1].Descriptor()\n}\n\nfunc (SocketConfig_TCPFastOpenState) Type() protoreflect.EnumType {\n\treturn &file_transport_internet_config_proto_enumTypes[1]\n}\n\nfunc (x SocketConfig_TCPFastOpenState) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use SocketConfig_TCPFastOpenState.Descriptor instead.\nfunc (SocketConfig_TCPFastOpenState) EnumDescriptor() ([]byte, []int) {\n\treturn file_transport_internet_config_proto_rawDescGZIP(), []int{3, 0}\n}\n\ntype SocketConfig_TProxyMode int32\n\nconst (\n\t// TProxy is off.\n\tSocketConfig_Off SocketConfig_TProxyMode = 0\n\t// TProxy mode.\n\tSocketConfig_TProxy SocketConfig_TProxyMode = 1\n\t// Redirect mode.\n\tSocketConfig_Redirect SocketConfig_TProxyMode = 2\n)\n\n// Enum value maps for SocketConfig_TProxyMode.\nvar (\n\tSocketConfig_TProxyMode_name = map[int32]string{\n\t\t0: \"Off\",\n\t\t1: \"TProxy\",\n\t\t2: \"Redirect\",\n\t}\n\tSocketConfig_TProxyMode_value = map[string]int32{\n\t\t\"Off\":      0,\n\t\t\"TProxy\":   1,\n\t\t\"Redirect\": 2,\n\t}\n)\n\nfunc (x SocketConfig_TProxyMode) Enum() *SocketConfig_TProxyMode {\n\tp := new(SocketConfig_TProxyMode)\n\t*p = x\n\treturn p\n}\n\nfunc (x SocketConfig_TProxyMode) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (SocketConfig_TProxyMode) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_transport_internet_config_proto_enumTypes[2].Descriptor()\n}\n\nfunc (SocketConfig_TProxyMode) Type() protoreflect.EnumType {\n\treturn &file_transport_internet_config_proto_enumTypes[2]\n}\n\nfunc (x SocketConfig_TProxyMode) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use SocketConfig_TProxyMode.Descriptor instead.\nfunc (SocketConfig_TProxyMode) EnumDescriptor() ([]byte, []int) {\n\treturn file_transport_internet_config_proto_rawDescGZIP(), []int{3, 1}\n}\n\ntype TransportConfig struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Type of network that this settings supports.\n\t// Deprecated. Use the string form below.\n\tProtocol TransportProtocol `protobuf:\"varint,1,opt,name=protocol,proto3,enum=v2ray.core.transport.internet.TransportProtocol\" json:\"protocol,omitempty\"`\n\t// Type of network that this settings supports.\n\tProtocolName string `protobuf:\"bytes,3,opt,name=protocol_name,json=protocolName,proto3\" json:\"protocol_name,omitempty\"`\n\t// Specific settings. Must be of the transports.\n\tSettings *serial.TypedMessage `protobuf:\"bytes,2,opt,name=settings,proto3\" json:\"settings,omitempty\"`\n}\n\nfunc (x *TransportConfig) Reset() {\n\t*x = TransportConfig{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_transport_internet_config_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *TransportConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*TransportConfig) ProtoMessage() {}\n\nfunc (x *TransportConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_transport_internet_config_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use TransportConfig.ProtoReflect.Descriptor instead.\nfunc (*TransportConfig) Descriptor() ([]byte, []int) {\n\treturn file_transport_internet_config_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *TransportConfig) GetProtocol() TransportProtocol {\n\tif x != nil {\n\t\treturn x.Protocol\n\t}\n\treturn TransportProtocol_TCP\n}\n\nfunc (x *TransportConfig) GetProtocolName() string {\n\tif x != nil {\n\t\treturn x.ProtocolName\n\t}\n\treturn \"\"\n}\n\nfunc (x *TransportConfig) GetSettings() *serial.TypedMessage {\n\tif x != nil {\n\t\treturn x.Settings\n\t}\n\treturn nil\n}\n\ntype StreamConfig struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Effective network. Deprecated. Use the string form below.\n\t//\n\t// Deprecated: Do not use.\n\tProtocol TransportProtocol `protobuf:\"varint,1,opt,name=protocol,proto3,enum=v2ray.core.transport.internet.TransportProtocol\" json:\"protocol,omitempty\"`\n\t// Effective network.\n\tProtocolName      string             `protobuf:\"bytes,5,opt,name=protocol_name,json=protocolName,proto3\" json:\"protocol_name,omitempty\"`\n\tTransportSettings []*TransportConfig `protobuf:\"bytes,2,rep,name=transport_settings,json=transportSettings,proto3\" json:\"transport_settings,omitempty\"`\n\t// Type of security. Must be a message name of the settings proto.\n\tSecurityType string `protobuf:\"bytes,3,opt,name=security_type,json=securityType,proto3\" json:\"security_type,omitempty\"`\n\t// Settings for transport security. For now the only choice is TLS.\n\tSecuritySettings []*serial.TypedMessage `protobuf:\"bytes,4,rep,name=security_settings,json=securitySettings,proto3\" json:\"security_settings,omitempty\"`\n\tSocketSettings   *SocketConfig          `protobuf:\"bytes,6,opt,name=socket_settings,json=socketSettings,proto3\" json:\"socket_settings,omitempty\"`\n}\n\nfunc (x *StreamConfig) Reset() {\n\t*x = StreamConfig{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_transport_internet_config_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *StreamConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*StreamConfig) ProtoMessage() {}\n\nfunc (x *StreamConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_transport_internet_config_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use StreamConfig.ProtoReflect.Descriptor instead.\nfunc (*StreamConfig) Descriptor() ([]byte, []int) {\n\treturn file_transport_internet_config_proto_rawDescGZIP(), []int{1}\n}\n\n// Deprecated: Do not use.\nfunc (x *StreamConfig) GetProtocol() TransportProtocol {\n\tif x != nil {\n\t\treturn x.Protocol\n\t}\n\treturn TransportProtocol_TCP\n}\n\nfunc (x *StreamConfig) GetProtocolName() string {\n\tif x != nil {\n\t\treturn x.ProtocolName\n\t}\n\treturn \"\"\n}\n\nfunc (x *StreamConfig) GetTransportSettings() []*TransportConfig {\n\tif x != nil {\n\t\treturn x.TransportSettings\n\t}\n\treturn nil\n}\n\nfunc (x *StreamConfig) GetSecurityType() string {\n\tif x != nil {\n\t\treturn x.SecurityType\n\t}\n\treturn \"\"\n}\n\nfunc (x *StreamConfig) GetSecuritySettings() []*serial.TypedMessage {\n\tif x != nil {\n\t\treturn x.SecuritySettings\n\t}\n\treturn nil\n}\n\nfunc (x *StreamConfig) GetSocketSettings() *SocketConfig {\n\tif x != nil {\n\t\treturn x.SocketSettings\n\t}\n\treturn nil\n}\n\ntype ProxyConfig struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tTag string `protobuf:\"bytes,1,opt,name=tag,proto3\" json:\"tag,omitempty\"`\n}\n\nfunc (x *ProxyConfig) Reset() {\n\t*x = ProxyConfig{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_transport_internet_config_proto_msgTypes[2]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *ProxyConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ProxyConfig) ProtoMessage() {}\n\nfunc (x *ProxyConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_transport_internet_config_proto_msgTypes[2]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ProxyConfig.ProtoReflect.Descriptor instead.\nfunc (*ProxyConfig) Descriptor() ([]byte, []int) {\n\treturn file_transport_internet_config_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *ProxyConfig) GetTag() string {\n\tif x != nil {\n\t\treturn x.Tag\n\t}\n\treturn \"\"\n}\n\n// SocketConfig is options to be applied on network sockets.\ntype SocketConfig struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Mark of the connection. If non-zero, the value will be set to SO_MARK.\n\tMark int32 `protobuf:\"varint,1,opt,name=mark,proto3\" json:\"mark,omitempty\"`\n\t// TFO is the state of TFO settings.\n\tTfo SocketConfig_TCPFastOpenState `protobuf:\"varint,2,opt,name=tfo,proto3,enum=v2ray.core.transport.internet.SocketConfig_TCPFastOpenState\" json:\"tfo,omitempty\"`\n\t// TProxy is for enabling TProxy socket option.\n\tTproxy SocketConfig_TProxyMode `protobuf:\"varint,3,opt,name=tproxy,proto3,enum=v2ray.core.transport.internet.SocketConfig_TProxyMode\" json:\"tproxy,omitempty\"`\n\t// ReceiveOriginalDestAddress is for enabling IP_RECVORIGDSTADDR socket\n\t// option. This option is for UDP only.\n\tReceiveOriginalDestAddress bool   `protobuf:\"varint,4,opt,name=receive_original_dest_address,json=receiveOriginalDestAddress,proto3\" json:\"receive_original_dest_address,omitempty\"`\n\tBindAddress                []byte `protobuf:\"bytes,5,opt,name=bind_address,json=bindAddress,proto3\" json:\"bind_address,omitempty\"`\n\tBindPort                   uint32 `protobuf:\"varint,6,opt,name=bind_port,json=bindPort,proto3\" json:\"bind_port,omitempty\"`\n}\n\nfunc (x *SocketConfig) Reset() {\n\t*x = SocketConfig{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_transport_internet_config_proto_msgTypes[3]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *SocketConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SocketConfig) ProtoMessage() {}\n\nfunc (x *SocketConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_transport_internet_config_proto_msgTypes[3]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SocketConfig.ProtoReflect.Descriptor instead.\nfunc (*SocketConfig) Descriptor() ([]byte, []int) {\n\treturn file_transport_internet_config_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *SocketConfig) GetMark() int32 {\n\tif x != nil {\n\t\treturn x.Mark\n\t}\n\treturn 0\n}\n\nfunc (x *SocketConfig) GetTfo() SocketConfig_TCPFastOpenState {\n\tif x != nil {\n\t\treturn x.Tfo\n\t}\n\treturn SocketConfig_AsIs\n}\n\nfunc (x *SocketConfig) GetTproxy() SocketConfig_TProxyMode {\n\tif x != nil {\n\t\treturn x.Tproxy\n\t}\n\treturn SocketConfig_Off\n}\n\nfunc (x *SocketConfig) GetReceiveOriginalDestAddress() bool {\n\tif x != nil {\n\t\treturn x.ReceiveOriginalDestAddress\n\t}\n\treturn false\n}\n\nfunc (x *SocketConfig) GetBindAddress() []byte {\n\tif x != nil {\n\t\treturn x.BindAddress\n\t}\n\treturn nil\n}\n\nfunc (x *SocketConfig) GetBindPort() uint32 {\n\tif x != nil {\n\t\treturn x.BindPort\n\t}\n\treturn 0\n}\n\nvar File_transport_internet_config_proto protoreflect.FileDescriptor\n\nvar file_transport_internet_config_proto_rawDesc = []byte{\n\t0x0a, 0x1f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65,\n\t0x72, 0x6e, 0x65, 0x74, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74,\n\t0x6f, 0x12, 0x1d, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72,\n\t0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74,\n\t0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2f,\n\t0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72,\n\t0x6f, 0x74, 0x6f, 0x22, 0xc8, 0x01, 0x0a, 0x0f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72,\n\t0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x4c, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f,\n\t0x63, 0x6f, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x30, 0x2e, 0x76, 0x32, 0x72, 0x61,\n\t0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74,\n\t0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70,\n\t0x6f, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x52, 0x08, 0x70, 0x72, 0x6f,\n\t0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,\n\t0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x72,\n\t0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x42, 0x0a, 0x08, 0x73, 0x65,\n\t0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x76,\n\t0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,\n\t0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73,\n\t0x73, 0x61, 0x67, 0x65, 0x52, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0xb4,\n\t0x03, 0x0a, 0x0c, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,\n\t0x50, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28,\n\t0x0e, 0x32, 0x30, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74,\n\t0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,\n\t0x74, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f,\n\t0x63, 0x6f, 0x6c, 0x42, 0x02, 0x18, 0x01, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,\n\t0x6c, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x5f, 0x6e, 0x61,\n\t0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63,\n\t0x6f, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x5d, 0x0a, 0x12, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70,\n\t0x6f, 0x72, 0x74, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03,\n\t0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,\n\t0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,\n\t0x65, 0x74, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x66,\n\t0x69, 0x67, 0x52, 0x11, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x65, 0x74,\n\t0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74,\n\t0x79, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x65,\n\t0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x53, 0x0a, 0x11, 0x73, 0x65,\n\t0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18,\n\t0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,\n\t0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c,\n\t0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x10, 0x73,\n\t0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12,\n\t0x54, 0x0a, 0x0f, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e,\n\t0x67, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,\n\t0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e,\n\t0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x43,\n\t0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x53, 0x65, 0x74,\n\t0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x1f, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x43, 0x6f,\n\t0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28,\n\t0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x22, 0xad, 0x03, 0x0a, 0x0c, 0x53, 0x6f, 0x63, 0x6b, 0x65,\n\t0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x61, 0x72, 0x6b, 0x18,\n\t0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x6d, 0x61, 0x72, 0x6b, 0x12, 0x4e, 0x0a, 0x03, 0x74,\n\t0x66, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x3c, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,\n\t0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e,\n\t0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x43,\n\t0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x54, 0x43, 0x50, 0x46, 0x61, 0x73, 0x74, 0x4f, 0x70, 0x65,\n\t0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x03, 0x74, 0x66, 0x6f, 0x12, 0x4e, 0x0a, 0x06, 0x74,\n\t0x70, 0x72, 0x6f, 0x78, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x36, 0x2e, 0x76, 0x32,\n\t0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f,\n\t0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x53, 0x6f, 0x63, 0x6b,\n\t0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x54, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x4d,\n\t0x6f, 0x64, 0x65, 0x52, 0x06, 0x74, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x12, 0x41, 0x0a, 0x1d, 0x72,\n\t0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x5f, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x5f,\n\t0x64, 0x65, 0x73, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01,\n\t0x28, 0x08, 0x52, 0x1a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x4f, 0x72, 0x69, 0x67, 0x69,\n\t0x6e, 0x61, 0x6c, 0x44, 0x65, 0x73, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x21,\n\t0x0a, 0x0c, 0x62, 0x69, 0x6e, 0x64, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x05,\n\t0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x62, 0x69, 0x6e, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73,\n\t0x73, 0x12, 0x1b, 0x0a, 0x09, 0x62, 0x69, 0x6e, 0x64, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x06,\n\t0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x62, 0x69, 0x6e, 0x64, 0x50, 0x6f, 0x72, 0x74, 0x22, 0x35,\n\t0x0a, 0x10, 0x54, 0x43, 0x50, 0x46, 0x61, 0x73, 0x74, 0x4f, 0x70, 0x65, 0x6e, 0x53, 0x74, 0x61,\n\t0x74, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x41, 0x73, 0x49, 0x73, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06,\n\t0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x69, 0x73, 0x61,\n\t0x62, 0x6c, 0x65, 0x10, 0x02, 0x22, 0x2f, 0x0a, 0x0a, 0x54, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x4d,\n\t0x6f, 0x64, 0x65, 0x12, 0x07, 0x0a, 0x03, 0x4f, 0x66, 0x66, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06,\n\t0x54, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x52, 0x65, 0x64, 0x69,\n\t0x72, 0x65, 0x63, 0x74, 0x10, 0x02, 0x2a, 0x5a, 0x0a, 0x11, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70,\n\t0x6f, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x07, 0x0a, 0x03, 0x54,\n\t0x43, 0x50, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x55, 0x44, 0x50, 0x10, 0x01, 0x12, 0x08, 0x0a,\n\t0x04, 0x4d, 0x4b, 0x43, 0x50, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x57, 0x65, 0x62, 0x53, 0x6f,\n\t0x63, 0x6b, 0x65, 0x74, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x10, 0x04,\n\t0x12, 0x10, 0x0a, 0x0c, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74,\n\t0x10, 0x05, 0x42, 0x68, 0x0a, 0x21, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,\n\t0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69,\n\t0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x50, 0x01, 0x5a, 0x21, 0x76, 0x32, 0x72, 0x61, 0x79,\n\t0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70,\n\t0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0xaa, 0x02, 0x1d, 0x56,\n\t0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70,\n\t0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x62, 0x06, 0x70, 0x72,\n\t0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_transport_internet_config_proto_rawDescOnce sync.Once\n\tfile_transport_internet_config_proto_rawDescData = file_transport_internet_config_proto_rawDesc\n)\n\nfunc file_transport_internet_config_proto_rawDescGZIP() []byte {\n\tfile_transport_internet_config_proto_rawDescOnce.Do(func() {\n\t\tfile_transport_internet_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_transport_internet_config_proto_rawDescData)\n\t})\n\treturn file_transport_internet_config_proto_rawDescData\n}\n\nvar file_transport_internet_config_proto_enumTypes = make([]protoimpl.EnumInfo, 3)\nvar file_transport_internet_config_proto_msgTypes = make([]protoimpl.MessageInfo, 4)\nvar file_transport_internet_config_proto_goTypes = []interface{}{\n\t(TransportProtocol)(0),             // 0: v2ray.core.transport.internet.TransportProtocol\n\t(SocketConfig_TCPFastOpenState)(0), // 1: v2ray.core.transport.internet.SocketConfig.TCPFastOpenState\n\t(SocketConfig_TProxyMode)(0),       // 2: v2ray.core.transport.internet.SocketConfig.TProxyMode\n\t(*TransportConfig)(nil),            // 3: v2ray.core.transport.internet.TransportConfig\n\t(*StreamConfig)(nil),               // 4: v2ray.core.transport.internet.StreamConfig\n\t(*ProxyConfig)(nil),                // 5: v2ray.core.transport.internet.ProxyConfig\n\t(*SocketConfig)(nil),               // 6: v2ray.core.transport.internet.SocketConfig\n\t(*serial.TypedMessage)(nil),        // 7: v2ray.core.common.serial.TypedMessage\n}\nvar file_transport_internet_config_proto_depIdxs = []int32{\n\t0, // 0: v2ray.core.transport.internet.TransportConfig.protocol:type_name -> v2ray.core.transport.internet.TransportProtocol\n\t7, // 1: v2ray.core.transport.internet.TransportConfig.settings:type_name -> v2ray.core.common.serial.TypedMessage\n\t0, // 2: v2ray.core.transport.internet.StreamConfig.protocol:type_name -> v2ray.core.transport.internet.TransportProtocol\n\t3, // 3: v2ray.core.transport.internet.StreamConfig.transport_settings:type_name -> v2ray.core.transport.internet.TransportConfig\n\t7, // 4: v2ray.core.transport.internet.StreamConfig.security_settings:type_name -> v2ray.core.common.serial.TypedMessage\n\t6, // 5: v2ray.core.transport.internet.StreamConfig.socket_settings:type_name -> v2ray.core.transport.internet.SocketConfig\n\t1, // 6: v2ray.core.transport.internet.SocketConfig.tfo:type_name -> v2ray.core.transport.internet.SocketConfig.TCPFastOpenState\n\t2, // 7: v2ray.core.transport.internet.SocketConfig.tproxy:type_name -> v2ray.core.transport.internet.SocketConfig.TProxyMode\n\t8, // [8:8] is the sub-list for method output_type\n\t8, // [8:8] is the sub-list for method input_type\n\t8, // [8:8] is the sub-list for extension type_name\n\t8, // [8:8] is the sub-list for extension extendee\n\t0, // [0:8] is the sub-list for field type_name\n}\n\nfunc init() { file_transport_internet_config_proto_init() }\nfunc file_transport_internet_config_proto_init() {\n\tif File_transport_internet_config_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_transport_internet_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*TransportConfig); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_transport_internet_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*StreamConfig); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_transport_internet_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*ProxyConfig); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_transport_internet_config_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*SocketConfig); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_transport_internet_config_proto_rawDesc,\n\t\t\tNumEnums:      3,\n\t\t\tNumMessages:   4,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_transport_internet_config_proto_goTypes,\n\t\tDependencyIndexes: file_transport_internet_config_proto_depIdxs,\n\t\tEnumInfos:         file_transport_internet_config_proto_enumTypes,\n\t\tMessageInfos:      file_transport_internet_config_proto_msgTypes,\n\t}.Build()\n\tFile_transport_internet_config_proto = out.File\n\tfile_transport_internet_config_proto_rawDesc = nil\n\tfile_transport_internet_config_proto_goTypes = nil\n\tfile_transport_internet_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "transport/internet/config.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.transport.internet;\noption csharp_namespace = \"V2Ray.Core.Transport.Internet\";\noption go_package = \"v2ray.com/core/transport/internet\";\noption java_package = \"com.v2ray.core.transport.internet\";\noption java_multiple_files = true;\n\nimport \"common/serial/typed_message.proto\";\n\nenum TransportProtocol {\n  TCP = 0;\n  UDP = 1;\n  MKCP = 2;\n  WebSocket = 3;\n  HTTP = 4;\n  DomainSocket = 5;\n}\n\nmessage TransportConfig {\n  // Type of network that this settings supports.\n  // Deprecated. Use the string form below.\n  TransportProtocol protocol = 1;\n\n  // Type of network that this settings supports.\n  string protocol_name = 3;\n\n  // Specific settings. Must be of the transports.\n  v2ray.core.common.serial.TypedMessage settings = 2;\n}\n\nmessage StreamConfig {\n  // Effective network. Deprecated. Use the string form below.\n  TransportProtocol protocol = 1 [deprecated = true];\n\n  // Effective network.\n  string protocol_name = 5;\n\n  repeated TransportConfig transport_settings = 2;\n\n  // Type of security. Must be a message name of the settings proto.\n  string security_type = 3;\n\n  // Settings for transport security. For now the only choice is TLS.\n  repeated v2ray.core.common.serial.TypedMessage security_settings = 4;\n\n  SocketConfig socket_settings = 6;\n}\n\nmessage ProxyConfig {\n  string tag = 1;\n}\n\n// SocketConfig is options to be applied on network sockets.\nmessage SocketConfig {\n  // Mark of the connection. If non-zero, the value will be set to SO_MARK.\n  int32 mark = 1;\n\n  enum TCPFastOpenState {\n    // AsIs is to leave the current TFO state as is, unmodified.\n    AsIs = 0;\n    // Enable is for enabling TFO explictly.\n    Enable = 1;\n    // Disable is for disabling TFO explictly.\n    Disable = 2;\n  }\n\n  // TFO is the state of TFO settings.\n  TCPFastOpenState tfo = 2;\n\n  enum TProxyMode {\n    // TProxy is off.\n    Off = 0;\n    // TProxy mode.\n    TProxy = 1;\n    // Redirect mode.\n    Redirect = 2;\n  }\n\n  // TProxy is for enabling TProxy socket option.\n  TProxyMode tproxy = 3;\n\n  // ReceiveOriginalDestAddress is for enabling IP_RECVORIGDSTADDR socket\n  // option. This option is for UDP only.\n  bool receive_original_dest_address = 4;\n\n  bytes bind_address = 5;\n\n  uint32 bind_port = 6;\n}\n"
  },
  {
    "path": "transport/internet/connection.go",
    "content": "package internet\n\nimport (\n\t\"net\"\n\n\t\"v2ray.com/core/features/stats\"\n)\n\ntype Connection interface {\n\tnet.Conn\n}\n\ntype StatCouterConnection struct {\n\tConnection\n\tReadCounter  stats.Counter\n\tWriteCounter stats.Counter\n}\n\nfunc (c *StatCouterConnection) Read(b []byte) (int, error) {\n\tnBytes, err := c.Connection.Read(b)\n\tif c.ReadCounter != nil {\n\t\tc.ReadCounter.Add(int64(nBytes))\n\t}\n\n\treturn nBytes, err\n}\n\nfunc (c *StatCouterConnection) Write(b []byte) (int, error) {\n\tnBytes, err := c.Connection.Write(b)\n\tif c.WriteCounter != nil {\n\t\tc.WriteCounter.Add(int64(nBytes))\n\t}\n\treturn nBytes, err\n}\n"
  },
  {
    "path": "transport/internet/dialer.go",
    "content": "package internet\n\nimport (\n\t\"context\"\n\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/session\"\n)\n\n// Dialer is the interface for dialing outbound connections.\ntype Dialer interface {\n\t// Dial dials a system connection to the given destination.\n\tDial(ctx context.Context, destination net.Destination) (Connection, error)\n\n\t// Address returns the address used by this Dialer. Maybe nil if not known.\n\tAddress() net.Address\n}\n\n// dialFunc is an interface to dial network connection to a specific destination.\ntype dialFunc func(ctx context.Context, dest net.Destination, streamSettings *MemoryStreamConfig) (Connection, error)\n\nvar (\n\ttransportDialerCache = make(map[string]dialFunc)\n)\n\n// RegisterTransportDialer registers a Dialer with given name.\nfunc RegisterTransportDialer(protocol string, dialer dialFunc) error {\n\tif _, found := transportDialerCache[protocol]; found {\n\t\treturn newError(protocol, \" dialer already registered\").AtError()\n\t}\n\ttransportDialerCache[protocol] = dialer\n\treturn nil\n}\n\n// Dial dials a internet connection towards the given destination.\nfunc Dial(ctx context.Context, dest net.Destination, streamSettings *MemoryStreamConfig) (Connection, error) {\n\tif dest.Network == net.Network_TCP {\n\t\tif streamSettings == nil {\n\t\t\ts, err := ToMemoryStreamConfig(nil)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, newError(\"failed to create default stream settings\").Base(err)\n\t\t\t}\n\t\t\tstreamSettings = s\n\t\t}\n\n\t\tprotocol := streamSettings.ProtocolName\n\t\tdialer := transportDialerCache[protocol]\n\t\tif dialer == nil {\n\t\t\treturn nil, newError(protocol, \" dialer not registered\").AtError()\n\t\t}\n\t\treturn dialer(ctx, dest, streamSettings)\n\t}\n\n\tif dest.Network == net.Network_UDP {\n\t\tudpDialer := transportDialerCache[\"udp\"]\n\t\tif udpDialer == nil {\n\t\t\treturn nil, newError(\"UDP dialer not registered\").AtError()\n\t\t}\n\t\treturn udpDialer(ctx, dest, streamSettings)\n\t}\n\n\treturn nil, newError(\"unknown network \", dest.Network)\n}\n\n// DialSystem calls system dialer to create a network connection.\nfunc DialSystem(ctx context.Context, dest net.Destination, sockopt *SocketConfig) (net.Conn, error) {\n\tvar src net.Address\n\tif outbound := session.OutboundFromContext(ctx); outbound != nil {\n\t\tsrc = outbound.Gateway\n\t}\n\treturn effectiveSystemDialer.Dial(ctx, src, dest, sockopt)\n}\n"
  },
  {
    "path": "transport/internet/dialer_test.go",
    "content": "package internet_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/testing/servers/tcp\"\n\t. \"v2ray.com/core/transport/internet\"\n)\n\nfunc TestDialWithLocalAddr(t *testing.T) {\n\tserver := &tcp.Server{}\n\tdest, err := server.Start()\n\tcommon.Must(err)\n\tdefer server.Close()\n\n\tconn, err := DialSystem(context.Background(), net.TCPDestination(net.LocalHostIP, dest.Port), nil)\n\tcommon.Must(err)\n\tif r := cmp.Diff(conn.RemoteAddr().String(), \"127.0.0.1:\"+dest.Port.String()); r != \"\" {\n\t\tt.Error(r)\n\t}\n\tconn.Close()\n}\n"
  },
  {
    "path": "transport/internet/domainsocket/config.go",
    "content": "// +build !confonly\n\npackage domainsocket\n\nimport (\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/transport/internet\"\n)\n\nconst protocolName = \"domainsocket\"\nconst sizeofSunPath = 108\n\nfunc (c *Config) GetUnixAddr() (*net.UnixAddr, error) {\n\tpath := c.Path\n\tif path == \"\" {\n\t\treturn nil, newError(\"empty domain socket path\")\n\t}\n\tif c.Abstract && path[0] != '@' {\n\t\tpath = \"@\" + path\n\t}\n\tif c.Abstract && c.Padding {\n\t\traw := []byte(path)\n\t\taddr := make([]byte, sizeofSunPath)\n\t\tfor i, c := range raw {\n\t\t\taddr[i] = c\n\t\t}\n\t\tpath = string(addr)\n\t}\n\treturn &net.UnixAddr{\n\t\tName: path,\n\t\tNet:  \"unix\",\n\t}, nil\n}\n\nfunc init() {\n\tcommon.Must(internet.RegisterProtocolConfigCreator(protocolName, func() interface{} {\n\t\treturn new(Config)\n\t}))\n}\n"
  },
  {
    "path": "transport/internet/domainsocket/config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: transport/internet/domainsocket/config.proto\n\npackage domainsocket\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype Config struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Path of the domain socket. This overrides the IP/Port parameter from\n\t// upstream caller.\n\tPath string `protobuf:\"bytes,1,opt,name=path,proto3\" json:\"path,omitempty\"`\n\t// Abstract speicifies whether to use abstract namespace or not.\n\t// Traditionally Unix domain socket is file system based. Abstract domain\n\t// socket can be used without acquiring file lock.\n\tAbstract bool `protobuf:\"varint,2,opt,name=abstract,proto3\" json:\"abstract,omitempty\"`\n\t// Some apps, eg. haproxy, use the full length of sockaddr_un.sun_path to\n\t// connect(2) or bind(2) when using abstract UDS.\n\tPadding             bool `protobuf:\"varint,3,opt,name=padding,proto3\" json:\"padding,omitempty\"`\n\tAcceptProxyProtocol bool `protobuf:\"varint,4,opt,name=acceptProxyProtocol,proto3\" json:\"acceptProxyProtocol,omitempty\"`\n}\n\nfunc (x *Config) Reset() {\n\t*x = Config{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_transport_internet_domainsocket_config_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Config) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Config) ProtoMessage() {}\n\nfunc (x *Config) ProtoReflect() protoreflect.Message {\n\tmi := &file_transport_internet_domainsocket_config_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Config.ProtoReflect.Descriptor instead.\nfunc (*Config) Descriptor() ([]byte, []int) {\n\treturn file_transport_internet_domainsocket_config_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *Config) GetPath() string {\n\tif x != nil {\n\t\treturn x.Path\n\t}\n\treturn \"\"\n}\n\nfunc (x *Config) GetAbstract() bool {\n\tif x != nil {\n\t\treturn x.Abstract\n\t}\n\treturn false\n}\n\nfunc (x *Config) GetPadding() bool {\n\tif x != nil {\n\t\treturn x.Padding\n\t}\n\treturn false\n}\n\nfunc (x *Config) GetAcceptProxyProtocol() bool {\n\tif x != nil {\n\t\treturn x.AcceptProxyProtocol\n\t}\n\treturn false\n}\n\nvar File_transport_internet_domainsocket_config_proto protoreflect.FileDescriptor\n\nvar file_transport_internet_domainsocket_config_proto_rawDesc = []byte{\n\t0x0a, 0x2c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65,\n\t0x72, 0x6e, 0x65, 0x74, 0x2f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x6f, 0x63, 0x6b, 0x65,\n\t0x74, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x2a,\n\t0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73,\n\t0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x64, 0x6f,\n\t0x6d, 0x61, 0x69, 0x6e, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x22, 0x84, 0x01, 0x0a, 0x06, 0x43,\n\t0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20,\n\t0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x62, 0x73,\n\t0x74, 0x72, 0x61, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x61, 0x62, 0x73,\n\t0x74, 0x72, 0x61, 0x63, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,\n\t0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x12,\n\t0x30, 0x0a, 0x13, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x50, 0x72,\n\t0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x61, 0x63,\n\t0x63, 0x65, 0x70, 0x74, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,\n\t0x6c, 0x42, 0x8f, 0x01, 0x0a, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,\n\t0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69,\n\t0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x6f,\n\t0x63, 0x6b, 0x65, 0x74, 0x50, 0x01, 0x5a, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,\n\t0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74,\n\t0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e,\n\t0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0xaa, 0x02, 0x2a, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43,\n\t0x6f, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e,\n\t0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x6f, 0x63,\n\t0x6b, 0x65, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_transport_internet_domainsocket_config_proto_rawDescOnce sync.Once\n\tfile_transport_internet_domainsocket_config_proto_rawDescData = file_transport_internet_domainsocket_config_proto_rawDesc\n)\n\nfunc file_transport_internet_domainsocket_config_proto_rawDescGZIP() []byte {\n\tfile_transport_internet_domainsocket_config_proto_rawDescOnce.Do(func() {\n\t\tfile_transport_internet_domainsocket_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_transport_internet_domainsocket_config_proto_rawDescData)\n\t})\n\treturn file_transport_internet_domainsocket_config_proto_rawDescData\n}\n\nvar file_transport_internet_domainsocket_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)\nvar file_transport_internet_domainsocket_config_proto_goTypes = []interface{}{\n\t(*Config)(nil), // 0: v2ray.core.transport.internet.domainsocket.Config\n}\nvar file_transport_internet_domainsocket_config_proto_depIdxs = []int32{\n\t0, // [0:0] is the sub-list for method output_type\n\t0, // [0:0] is the sub-list for method input_type\n\t0, // [0:0] is the sub-list for extension type_name\n\t0, // [0:0] is the sub-list for extension extendee\n\t0, // [0:0] is the sub-list for field type_name\n}\n\nfunc init() { file_transport_internet_domainsocket_config_proto_init() }\nfunc file_transport_internet_domainsocket_config_proto_init() {\n\tif File_transport_internet_domainsocket_config_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_transport_internet_domainsocket_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Config); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_transport_internet_domainsocket_config_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   1,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_transport_internet_domainsocket_config_proto_goTypes,\n\t\tDependencyIndexes: file_transport_internet_domainsocket_config_proto_depIdxs,\n\t\tMessageInfos:      file_transport_internet_domainsocket_config_proto_msgTypes,\n\t}.Build()\n\tFile_transport_internet_domainsocket_config_proto = out.File\n\tfile_transport_internet_domainsocket_config_proto_rawDesc = nil\n\tfile_transport_internet_domainsocket_config_proto_goTypes = nil\n\tfile_transport_internet_domainsocket_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "transport/internet/domainsocket/config.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.transport.internet.domainsocket;\noption csharp_namespace = \"V2Ray.Core.Transport.Internet.DomainSocket\";\noption go_package = \"v2ray.com/core/transport/internet/domainsocket\";\noption java_package = \"com.v2ray.core.transport.internet.domainsocket\";\noption java_multiple_files = true;\n\nmessage Config {\n  // Path of the domain socket. This overrides the IP/Port parameter from\n  // upstream caller.\n  string path = 1;\n  // Abstract speicifies whether to use abstract namespace or not.\n  // Traditionally Unix domain socket is file system based. Abstract domain\n  // socket can be used without acquiring file lock.\n  bool abstract = 2;\n  // Some apps, eg. haproxy, use the full length of sockaddr_un.sun_path to\n  // connect(2) or bind(2) when using abstract UDS.\n  bool padding = 3;\n  bool acceptProxyProtocol = 4;\n}\n"
  },
  {
    "path": "transport/internet/domainsocket/dial.go",
    "content": "// +build !windows\n// +build !wasm\n// +build !confonly\n\npackage domainsocket\n\nimport (\n\t\"context\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/transport/internet\"\n\t\"v2ray.com/core/transport/internet/tls\"\n\t\"v2ray.com/core/transport/internet/xtls\"\n)\n\nfunc Dial(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (internet.Connection, error) {\n\tsettings := streamSettings.ProtocolSettings.(*Config)\n\taddr, err := settings.GetUnixAddr()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tconn, err := net.DialUnix(\"unix\", nil, addr)\n\tif err != nil {\n\t\treturn nil, newError(\"failed to dial unix: \", settings.Path).Base(err).AtWarning()\n\t}\n\n\tif config := tls.ConfigFromStreamSettings(streamSettings); config != nil {\n\t\treturn tls.Client(conn, config.GetTLSConfig(tls.WithDestination(dest))), nil\n\t} else if config := xtls.ConfigFromStreamSettings(streamSettings); config != nil {\n\t\treturn xtls.Client(conn, config.GetXTLSConfig(xtls.WithDestination(dest))), nil\n\t}\n\n\treturn conn, nil\n}\n\nfunc init() {\n\tcommon.Must(internet.RegisterTransportDialer(protocolName, Dial))\n}\n"
  },
  {
    "path": "transport/internet/domainsocket/errgen.go",
    "content": "package domainsocket\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n"
  },
  {
    "path": "transport/internet/domainsocket/errors.generated.go",
    "content": "package domainsocket\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "transport/internet/domainsocket/listener.go",
    "content": "// +build !windows\n// +build !wasm\n// +build !confonly\n\npackage domainsocket\n\nimport (\n\t\"context\"\n\tgotls \"crypto/tls\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/pires/go-proxyproto\"\n\tgoxtls \"github.com/xtls/go\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/session\"\n\t\"v2ray.com/core/transport/internet\"\n\t\"v2ray.com/core/transport/internet/tls\"\n\t\"v2ray.com/core/transport/internet/xtls\"\n)\n\ntype Listener struct {\n\taddr       *net.UnixAddr\n\tln         net.Listener\n\ttlsConfig  *gotls.Config\n\txtlsConfig *goxtls.Config\n\tconfig     *Config\n\taddConn    internet.ConnHandler\n\tlocker     *fileLocker\n}\n\nfunc Listen(ctx context.Context, address net.Address, port net.Port, streamSettings *internet.MemoryStreamConfig, handler internet.ConnHandler) (internet.Listener, error) {\n\tsettings := streamSettings.ProtocolSettings.(*Config)\n\taddr, err := settings.GetUnixAddr()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tunixListener, err := net.ListenUnix(\"unix\", addr)\n\tif err != nil {\n\t\treturn nil, newError(\"failed to listen domain socket\").Base(err).AtWarning()\n\t}\n\n\tvar ln *Listener\n\tif settings.AcceptProxyProtocol {\n\t\tpolicyFunc := func(upstream net.Addr) (proxyproto.Policy, error) { return proxyproto.REQUIRE, nil }\n\t\tln = &Listener{\n\t\t\taddr:    addr,\n\t\t\tln:      &proxyproto.Listener{Listener: unixListener, Policy: policyFunc},\n\t\t\tconfig:  settings,\n\t\t\taddConn: handler,\n\t\t}\n\t\tnewError(\"accepting PROXY protocol\").AtWarning().WriteToLog(session.ExportIDToError(ctx))\n\t} else {\n\t\tln = &Listener{\n\t\t\taddr:    addr,\n\t\t\tln:      unixListener,\n\t\t\tconfig:  settings,\n\t\t\taddConn: handler,\n\t\t}\n\t}\n\n\tif !settings.Abstract {\n\t\tln.locker = &fileLocker{\n\t\t\tpath: settings.Path + \".lock\",\n\t\t}\n\t\tif err := ln.locker.Acquire(); err != nil {\n\t\t\tunixListener.Close()\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tif config := tls.ConfigFromStreamSettings(streamSettings); config != nil {\n\t\tln.tlsConfig = config.GetTLSConfig()\n\t}\n\tif config := xtls.ConfigFromStreamSettings(streamSettings); config != nil {\n\t\tln.xtlsConfig = config.GetXTLSConfig()\n\t}\n\n\tgo ln.run()\n\n\treturn ln, nil\n}\n\nfunc (ln *Listener) Addr() net.Addr {\n\treturn ln.addr\n}\n\nfunc (ln *Listener) Close() error {\n\tif ln.locker != nil {\n\t\tln.locker.Release()\n\t}\n\treturn ln.ln.Close()\n}\n\nfunc (ln *Listener) run() {\n\tfor {\n\t\tconn, err := ln.ln.Accept()\n\t\tif err != nil {\n\t\t\tif strings.Contains(err.Error(), \"closed\") {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tnewError(\"failed to accepted raw connections\").Base(err).AtWarning().WriteToLog()\n\t\t\tcontinue\n\t\t}\n\n\t\tif ln.tlsConfig != nil {\n\t\t\tconn = tls.Server(conn, ln.tlsConfig)\n\t\t} else if ln.xtlsConfig != nil {\n\t\t\tconn = xtls.Server(conn, ln.xtlsConfig)\n\t\t}\n\n\t\tln.addConn(internet.Connection(conn))\n\t}\n}\n\ntype fileLocker struct {\n\tpath string\n\tfile *os.File\n}\n\nfunc (fl *fileLocker) Acquire() error {\n\tf, err := os.Create(fl.path)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif err := unix.Flock(int(f.Fd()), unix.LOCK_EX); err != nil {\n\t\tf.Close()\n\t\treturn newError(\"failed to lock file: \", fl.path).Base(err)\n\t}\n\tfl.file = f\n\treturn nil\n}\n\nfunc (fl *fileLocker) Release() {\n\tif err := unix.Flock(int(fl.file.Fd()), unix.LOCK_UN); err != nil {\n\t\tnewError(\"failed to unlock file: \", fl.path).Base(err).WriteToLog()\n\t}\n\tif err := fl.file.Close(); err != nil {\n\t\tnewError(\"failed to close file: \", fl.path).Base(err).WriteToLog()\n\t}\n\tif err := os.Remove(fl.path); err != nil {\n\t\tnewError(\"failed to remove file: \", fl.path).Base(err).WriteToLog()\n\t}\n}\n\nfunc init() {\n\tcommon.Must(internet.RegisterTransportListener(protocolName, Listen))\n}\n"
  },
  {
    "path": "transport/internet/domainsocket/listener_test.go",
    "content": "// +build !windows\n\npackage domainsocket_test\n\nimport (\n\t\"context\"\n\t\"runtime\"\n\t\"testing\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/transport/internet\"\n\t. \"v2ray.com/core/transport/internet/domainsocket\"\n)\n\nfunc TestListen(t *testing.T) {\n\tctx := context.Background()\n\tstreamSettings := &internet.MemoryStreamConfig{\n\t\tProtocolName: \"domainsocket\",\n\t\tProtocolSettings: &Config{\n\t\t\tPath: \"/tmp/ts3\",\n\t\t},\n\t}\n\tlistener, err := Listen(ctx, nil, net.Port(0), streamSettings, func(conn internet.Connection) {\n\t\tdefer conn.Close()\n\n\t\tb := buf.New()\n\t\tdefer b.Release()\n\t\tcommon.Must2(b.ReadFrom(conn))\n\t\tb.WriteString(\"Response\")\n\n\t\tcommon.Must2(conn.Write(b.Bytes()))\n\t})\n\tcommon.Must(err)\n\tdefer listener.Close()\n\n\tconn, err := Dial(ctx, net.Destination{}, streamSettings)\n\tcommon.Must(err)\n\tdefer conn.Close()\n\n\tcommon.Must2(conn.Write([]byte(\"Request\")))\n\n\tb := buf.New()\n\tdefer b.Release()\n\tcommon.Must2(b.ReadFrom(conn))\n\n\tif b.String() != \"RequestResponse\" {\n\t\tt.Error(\"expected response as 'RequestResponse' but got \", b.String())\n\t}\n}\n\nfunc TestListenAbstract(t *testing.T) {\n\tif runtime.GOOS != \"linux\" {\n\t\treturn\n\t}\n\n\tctx := context.Background()\n\tstreamSettings := &internet.MemoryStreamConfig{\n\t\tProtocolName: \"domainsocket\",\n\t\tProtocolSettings: &Config{\n\t\t\tPath:     \"/tmp/ts3\",\n\t\t\tAbstract: true,\n\t\t},\n\t}\n\tlistener, err := Listen(ctx, nil, net.Port(0), streamSettings, func(conn internet.Connection) {\n\t\tdefer conn.Close()\n\n\t\tb := buf.New()\n\t\tdefer b.Release()\n\t\tcommon.Must2(b.ReadFrom(conn))\n\t\tb.WriteString(\"Response\")\n\n\t\tcommon.Must2(conn.Write(b.Bytes()))\n\t})\n\tcommon.Must(err)\n\tdefer listener.Close()\n\n\tconn, err := Dial(ctx, net.Destination{}, streamSettings)\n\tcommon.Must(err)\n\tdefer conn.Close()\n\n\tcommon.Must2(conn.Write([]byte(\"Request\")))\n\n\tb := buf.New()\n\tdefer b.Release()\n\tcommon.Must2(b.ReadFrom(conn))\n\n\tif b.String() != \"RequestResponse\" {\n\t\tt.Error(\"expected response as 'RequestResponse' but got \", b.String())\n\t}\n}\n"
  },
  {
    "path": "transport/internet/errors.generated.go",
    "content": "package internet\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "transport/internet/header.go",
    "content": "package internet\n\nimport (\n\t\"context\"\n\t\"net\"\n\n\t\"v2ray.com/core/common\"\n)\n\ntype PacketHeader interface {\n\tSize() int32\n\tSerialize([]byte)\n}\n\nfunc CreatePacketHeader(config interface{}) (PacketHeader, error) {\n\theader, err := common.CreateObject(context.Background(), config)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif h, ok := header.(PacketHeader); ok {\n\t\treturn h, nil\n\t}\n\treturn nil, newError(\"not a packet header\")\n}\n\ntype ConnectionAuthenticator interface {\n\tClient(net.Conn) net.Conn\n\tServer(net.Conn) net.Conn\n}\n\nfunc CreateConnectionAuthenticator(config interface{}) (ConnectionAuthenticator, error) {\n\tauth, err := common.CreateObject(context.Background(), config)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif a, ok := auth.(ConnectionAuthenticator); ok {\n\t\treturn a, nil\n\t}\n\treturn nil, newError(\"not a ConnectionAuthenticator\")\n}\n"
  },
  {
    "path": "transport/internet/header_test.go",
    "content": "package internet_test\n\nimport (\n\t\"testing\"\n\n\t\"v2ray.com/core/common\"\n\t. \"v2ray.com/core/transport/internet\"\n\t\"v2ray.com/core/transport/internet/headers/noop\"\n\t\"v2ray.com/core/transport/internet/headers/srtp\"\n\t\"v2ray.com/core/transport/internet/headers/utp\"\n\t\"v2ray.com/core/transport/internet/headers/wechat\"\n\t\"v2ray.com/core/transport/internet/headers/wireguard\"\n)\n\nfunc TestAllHeadersLoadable(t *testing.T) {\n\ttestCases := []struct {\n\t\tInput interface{}\n\t\tSize  int32\n\t}{\n\t\t{\n\t\t\tInput: new(noop.Config),\n\t\t\tSize:  0,\n\t\t},\n\t\t{\n\t\t\tInput: new(srtp.Config),\n\t\t\tSize:  4,\n\t\t},\n\t\t{\n\t\t\tInput: new(utp.Config),\n\t\t\tSize:  4,\n\t\t},\n\t\t{\n\t\t\tInput: new(wechat.VideoConfig),\n\t\t\tSize:  13,\n\t\t},\n\t\t{\n\t\t\tInput: new(wireguard.WireguardConfig),\n\t\t\tSize:  4,\n\t\t},\n\t}\n\n\tfor _, testCase := range testCases {\n\t\theader, err := CreatePacketHeader(testCase.Input)\n\t\tcommon.Must(err)\n\t\tif header.Size() != testCase.Size {\n\t\t\tt.Error(\"expected size \", testCase.Size, \" but got \", header.Size())\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "transport/internet/headers/http/config.go",
    "content": "package http\n\nimport (\n\t\"strings\"\n\n\t\"v2ray.com/core/common/dice\"\n)\n\nfunc pickString(arr []string) string {\n\tn := len(arr)\n\tswitch n {\n\tcase 0:\n\t\treturn \"\"\n\tcase 1:\n\t\treturn arr[0]\n\tdefault:\n\t\treturn arr[dice.Roll(n)]\n\t}\n}\n\nfunc (v *RequestConfig) PickUri() string {\n\treturn pickString(v.Uri)\n}\n\nfunc (v *RequestConfig) PickHeaders() []string {\n\tn := len(v.Header)\n\tif n == 0 {\n\t\treturn nil\n\t}\n\theaders := make([]string, n)\n\tfor idx, headerConfig := range v.Header {\n\t\theaderName := headerConfig.Name\n\t\theaderValue := pickString(headerConfig.Value)\n\t\theaders[idx] = headerName + \": \" + headerValue\n\t}\n\treturn headers\n}\n\nfunc (v *RequestConfig) GetVersionValue() string {\n\tif v == nil || v.Version == nil {\n\t\treturn \"1.1\"\n\t}\n\treturn v.Version.Value\n}\n\nfunc (v *RequestConfig) GetMethodValue() string {\n\tif v == nil || v.Method == nil {\n\t\treturn \"GET\"\n\t}\n\treturn v.Method.Value\n}\n\nfunc (v *RequestConfig) GetFullVersion() string {\n\treturn \"HTTP/\" + v.GetVersionValue()\n}\n\nfunc (v *ResponseConfig) HasHeader(header string) bool {\n\tcHeader := strings.ToLower(header)\n\tfor _, tHeader := range v.Header {\n\t\tif strings.EqualFold(tHeader.Name, cHeader) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc (v *ResponseConfig) PickHeaders() []string {\n\tn := len(v.Header)\n\tif n == 0 {\n\t\treturn nil\n\t}\n\theaders := make([]string, n)\n\tfor idx, headerConfig := range v.Header {\n\t\theaderName := headerConfig.Name\n\t\theaderValue := pickString(headerConfig.Value)\n\t\theaders[idx] = headerName + \": \" + headerValue\n\t}\n\treturn headers\n}\n\nfunc (v *ResponseConfig) GetVersionValue() string {\n\tif v == nil || v.Version == nil {\n\t\treturn \"1.1\"\n\t}\n\treturn v.Version.Value\n}\n\nfunc (v *ResponseConfig) GetFullVersion() string {\n\treturn \"HTTP/\" + v.GetVersionValue()\n}\n\nfunc (v *ResponseConfig) GetStatusValue() *Status {\n\tif v == nil || v.Status == nil {\n\t\treturn &Status{\n\t\t\tCode:   \"200\",\n\t\t\tReason: \"OK\",\n\t\t}\n\t}\n\treturn v.Status\n}\n"
  },
  {
    "path": "transport/internet/headers/http/config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: transport/internet/headers/http/config.proto\n\npackage http\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype Header struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// \"Accept\", \"Cookie\", etc\n\tName string `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n\t// Each entry must be valid in one piece. Random entry will be chosen if\n\t// multiple entries present.\n\tValue []string `protobuf:\"bytes,2,rep,name=value,proto3\" json:\"value,omitempty\"`\n}\n\nfunc (x *Header) Reset() {\n\t*x = Header{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_transport_internet_headers_http_config_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Header) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Header) ProtoMessage() {}\n\nfunc (x *Header) ProtoReflect() protoreflect.Message {\n\tmi := &file_transport_internet_headers_http_config_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Header.ProtoReflect.Descriptor instead.\nfunc (*Header) Descriptor() ([]byte, []int) {\n\treturn file_transport_internet_headers_http_config_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *Header) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *Header) GetValue() []string {\n\tif x != nil {\n\t\treturn x.Value\n\t}\n\treturn nil\n}\n\n// HTTP version. Default value \"1.1\".\ntype Version struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tValue string `protobuf:\"bytes,1,opt,name=value,proto3\" json:\"value,omitempty\"`\n}\n\nfunc (x *Version) Reset() {\n\t*x = Version{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_transport_internet_headers_http_config_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Version) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Version) ProtoMessage() {}\n\nfunc (x *Version) ProtoReflect() protoreflect.Message {\n\tmi := &file_transport_internet_headers_http_config_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Version.ProtoReflect.Descriptor instead.\nfunc (*Version) Descriptor() ([]byte, []int) {\n\treturn file_transport_internet_headers_http_config_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *Version) GetValue() string {\n\tif x != nil {\n\t\treturn x.Value\n\t}\n\treturn \"\"\n}\n\n// HTTP method. Default value \"GET\".\ntype Method struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tValue string `protobuf:\"bytes,1,opt,name=value,proto3\" json:\"value,omitempty\"`\n}\n\nfunc (x *Method) Reset() {\n\t*x = Method{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_transport_internet_headers_http_config_proto_msgTypes[2]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Method) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Method) ProtoMessage() {}\n\nfunc (x *Method) ProtoReflect() protoreflect.Message {\n\tmi := &file_transport_internet_headers_http_config_proto_msgTypes[2]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Method.ProtoReflect.Descriptor instead.\nfunc (*Method) Descriptor() ([]byte, []int) {\n\treturn file_transport_internet_headers_http_config_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *Method) GetValue() string {\n\tif x != nil {\n\t\treturn x.Value\n\t}\n\treturn \"\"\n}\n\ntype RequestConfig struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Full HTTP version like \"1.1\".\n\tVersion *Version `protobuf:\"bytes,1,opt,name=version,proto3\" json:\"version,omitempty\"`\n\t// GET, POST, CONNECT etc\n\tMethod *Method `protobuf:\"bytes,2,opt,name=method,proto3\" json:\"method,omitempty\"`\n\t// URI like \"/login.php\"\n\tUri    []string  `protobuf:\"bytes,3,rep,name=uri,proto3\" json:\"uri,omitempty\"`\n\tHeader []*Header `protobuf:\"bytes,4,rep,name=header,proto3\" json:\"header,omitempty\"`\n}\n\nfunc (x *RequestConfig) Reset() {\n\t*x = RequestConfig{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_transport_internet_headers_http_config_proto_msgTypes[3]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *RequestConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RequestConfig) ProtoMessage() {}\n\nfunc (x *RequestConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_transport_internet_headers_http_config_proto_msgTypes[3]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RequestConfig.ProtoReflect.Descriptor instead.\nfunc (*RequestConfig) Descriptor() ([]byte, []int) {\n\treturn file_transport_internet_headers_http_config_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *RequestConfig) GetVersion() *Version {\n\tif x != nil {\n\t\treturn x.Version\n\t}\n\treturn nil\n}\n\nfunc (x *RequestConfig) GetMethod() *Method {\n\tif x != nil {\n\t\treturn x.Method\n\t}\n\treturn nil\n}\n\nfunc (x *RequestConfig) GetUri() []string {\n\tif x != nil {\n\t\treturn x.Uri\n\t}\n\treturn nil\n}\n\nfunc (x *RequestConfig) GetHeader() []*Header {\n\tif x != nil {\n\t\treturn x.Header\n\t}\n\treturn nil\n}\n\ntype Status struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Status code. Default \"200\".\n\tCode string `protobuf:\"bytes,1,opt,name=code,proto3\" json:\"code,omitempty\"`\n\t// Statue reason. Default \"OK\".\n\tReason string `protobuf:\"bytes,2,opt,name=reason,proto3\" json:\"reason,omitempty\"`\n}\n\nfunc (x *Status) Reset() {\n\t*x = Status{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_transport_internet_headers_http_config_proto_msgTypes[4]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Status) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Status) ProtoMessage() {}\n\nfunc (x *Status) ProtoReflect() protoreflect.Message {\n\tmi := &file_transport_internet_headers_http_config_proto_msgTypes[4]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Status.ProtoReflect.Descriptor instead.\nfunc (*Status) Descriptor() ([]byte, []int) {\n\treturn file_transport_internet_headers_http_config_proto_rawDescGZIP(), []int{4}\n}\n\nfunc (x *Status) GetCode() string {\n\tif x != nil {\n\t\treturn x.Code\n\t}\n\treturn \"\"\n}\n\nfunc (x *Status) GetReason() string {\n\tif x != nil {\n\t\treturn x.Reason\n\t}\n\treturn \"\"\n}\n\ntype ResponseConfig struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tVersion *Version  `protobuf:\"bytes,1,opt,name=version,proto3\" json:\"version,omitempty\"`\n\tStatus  *Status   `protobuf:\"bytes,2,opt,name=status,proto3\" json:\"status,omitempty\"`\n\tHeader  []*Header `protobuf:\"bytes,3,rep,name=header,proto3\" json:\"header,omitempty\"`\n}\n\nfunc (x *ResponseConfig) Reset() {\n\t*x = ResponseConfig{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_transport_internet_headers_http_config_proto_msgTypes[5]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *ResponseConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ResponseConfig) ProtoMessage() {}\n\nfunc (x *ResponseConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_transport_internet_headers_http_config_proto_msgTypes[5]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ResponseConfig.ProtoReflect.Descriptor instead.\nfunc (*ResponseConfig) Descriptor() ([]byte, []int) {\n\treturn file_transport_internet_headers_http_config_proto_rawDescGZIP(), []int{5}\n}\n\nfunc (x *ResponseConfig) GetVersion() *Version {\n\tif x != nil {\n\t\treturn x.Version\n\t}\n\treturn nil\n}\n\nfunc (x *ResponseConfig) GetStatus() *Status {\n\tif x != nil {\n\t\treturn x.Status\n\t}\n\treturn nil\n}\n\nfunc (x *ResponseConfig) GetHeader() []*Header {\n\tif x != nil {\n\t\treturn x.Header\n\t}\n\treturn nil\n}\n\ntype Config struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Settings for authenticating requests. If not set, client side will not send\n\t// authenication header, and server side will bypass authentication.\n\tRequest *RequestConfig `protobuf:\"bytes,1,opt,name=request,proto3\" json:\"request,omitempty\"`\n\t// Settings for authenticating responses. If not set, client side will bypass\n\t// authentication, and server side will not send authentication header.\n\tResponse *ResponseConfig `protobuf:\"bytes,2,opt,name=response,proto3\" json:\"response,omitempty\"`\n}\n\nfunc (x *Config) Reset() {\n\t*x = Config{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_transport_internet_headers_http_config_proto_msgTypes[6]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Config) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Config) ProtoMessage() {}\n\nfunc (x *Config) ProtoReflect() protoreflect.Message {\n\tmi := &file_transport_internet_headers_http_config_proto_msgTypes[6]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Config.ProtoReflect.Descriptor instead.\nfunc (*Config) Descriptor() ([]byte, []int) {\n\treturn file_transport_internet_headers_http_config_proto_rawDescGZIP(), []int{6}\n}\n\nfunc (x *Config) GetRequest() *RequestConfig {\n\tif x != nil {\n\t\treturn x.Request\n\t}\n\treturn nil\n}\n\nfunc (x *Config) GetResponse() *ResponseConfig {\n\tif x != nil {\n\t\treturn x.Response\n\t}\n\treturn nil\n}\n\nvar File_transport_internet_headers_http_config_proto protoreflect.FileDescriptor\n\nvar file_transport_internet_headers_http_config_proto_rawDesc = []byte{\n\t0x0a, 0x2c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65,\n\t0x72, 0x6e, 0x65, 0x74, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2f, 0x68, 0x74, 0x74,\n\t0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x2a,\n\t0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73,\n\t0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x68, 0x65,\n\t0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x22, 0x32, 0x0a, 0x06, 0x48, 0x65,\n\t0x61, 0x64, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01,\n\t0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,\n\t0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x1f,\n\t0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c,\n\t0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22,\n\t0x1e, 0x0a, 0x06, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c,\n\t0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22,\n\t0x88, 0x02, 0x0a, 0x0d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69,\n\t0x67, 0x12, 0x4d, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01,\n\t0x28, 0x0b, 0x32, 0x33, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,\n\t0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,\n\t0x65, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x2e,\n\t0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,\n\t0x12, 0x4a, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,\n\t0x32, 0x32, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72,\n\t0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74,\n\t0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x2e, 0x4d, 0x65,\n\t0x74, 0x68, 0x6f, 0x64, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x10, 0x0a, 0x03,\n\t0x75, 0x72, 0x69, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x69, 0x12, 0x4a,\n\t0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32,\n\t0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e,\n\t0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x68,\n\t0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x2e, 0x48, 0x65, 0x61, 0x64,\n\t0x65, 0x72, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x22, 0x34, 0x0a, 0x06, 0x53, 0x74,\n\t0x61, 0x74, 0x75, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01,\n\t0x28, 0x09, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73,\n\t0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e,\n\t0x22, 0xf7, 0x01, 0x0a, 0x0e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x43, 0x6f, 0x6e,\n\t0x66, 0x69, 0x67, 0x12, 0x4d, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01,\n\t0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72,\n\t0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65,\n\t0x72, 0x6e, 0x65, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x68, 0x74, 0x74,\n\t0x70, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69,\n\t0x6f, 0x6e, 0x12, 0x4a, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01,\n\t0x28, 0x0b, 0x32, 0x32, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,\n\t0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,\n\t0x65, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x2e,\n\t0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x4a,\n\t0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32,\n\t0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e,\n\t0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x68,\n\t0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x2e, 0x48, 0x65, 0x61, 0x64,\n\t0x65, 0x72, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x22, 0xb5, 0x01, 0x0a, 0x06, 0x43,\n\t0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x53, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,\n\t0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,\n\t0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e,\n\t0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x68,\n\t0x74, 0x74, 0x70, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69,\n\t0x67, 0x52, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x56, 0x0a, 0x08, 0x72, 0x65,\n\t0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x76,\n\t0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70,\n\t0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x68, 0x65, 0x61,\n\t0x64, 0x65, 0x72, 0x73, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,\n\t0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e,\n\t0x73, 0x65, 0x42, 0x8f, 0x01, 0x0a, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,\n\t0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e,\n\t0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73,\n\t0x2e, 0x68, 0x74, 0x74, 0x70, 0x50, 0x01, 0x5a, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,\n\t0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72,\n\t0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65,\n\t0x72, 0x73, 0x2f, 0x68, 0x74, 0x74, 0x70, 0xaa, 0x02, 0x2a, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e,\n\t0x43, 0x6f, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49,\n\t0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e,\n\t0x48, 0x74, 0x74, 0x70, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_transport_internet_headers_http_config_proto_rawDescOnce sync.Once\n\tfile_transport_internet_headers_http_config_proto_rawDescData = file_transport_internet_headers_http_config_proto_rawDesc\n)\n\nfunc file_transport_internet_headers_http_config_proto_rawDescGZIP() []byte {\n\tfile_transport_internet_headers_http_config_proto_rawDescOnce.Do(func() {\n\t\tfile_transport_internet_headers_http_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_transport_internet_headers_http_config_proto_rawDescData)\n\t})\n\treturn file_transport_internet_headers_http_config_proto_rawDescData\n}\n\nvar file_transport_internet_headers_http_config_proto_msgTypes = make([]protoimpl.MessageInfo, 7)\nvar file_transport_internet_headers_http_config_proto_goTypes = []interface{}{\n\t(*Header)(nil),         // 0: v2ray.core.transport.internet.headers.http.Header\n\t(*Version)(nil),        // 1: v2ray.core.transport.internet.headers.http.Version\n\t(*Method)(nil),         // 2: v2ray.core.transport.internet.headers.http.Method\n\t(*RequestConfig)(nil),  // 3: v2ray.core.transport.internet.headers.http.RequestConfig\n\t(*Status)(nil),         // 4: v2ray.core.transport.internet.headers.http.Status\n\t(*ResponseConfig)(nil), // 5: v2ray.core.transport.internet.headers.http.ResponseConfig\n\t(*Config)(nil),         // 6: v2ray.core.transport.internet.headers.http.Config\n}\nvar file_transport_internet_headers_http_config_proto_depIdxs = []int32{\n\t1, // 0: v2ray.core.transport.internet.headers.http.RequestConfig.version:type_name -> v2ray.core.transport.internet.headers.http.Version\n\t2, // 1: v2ray.core.transport.internet.headers.http.RequestConfig.method:type_name -> v2ray.core.transport.internet.headers.http.Method\n\t0, // 2: v2ray.core.transport.internet.headers.http.RequestConfig.header:type_name -> v2ray.core.transport.internet.headers.http.Header\n\t1, // 3: v2ray.core.transport.internet.headers.http.ResponseConfig.version:type_name -> v2ray.core.transport.internet.headers.http.Version\n\t4, // 4: v2ray.core.transport.internet.headers.http.ResponseConfig.status:type_name -> v2ray.core.transport.internet.headers.http.Status\n\t0, // 5: v2ray.core.transport.internet.headers.http.ResponseConfig.header:type_name -> v2ray.core.transport.internet.headers.http.Header\n\t3, // 6: v2ray.core.transport.internet.headers.http.Config.request:type_name -> v2ray.core.transport.internet.headers.http.RequestConfig\n\t5, // 7: v2ray.core.transport.internet.headers.http.Config.response:type_name -> v2ray.core.transport.internet.headers.http.ResponseConfig\n\t8, // [8:8] is the sub-list for method output_type\n\t8, // [8:8] is the sub-list for method input_type\n\t8, // [8:8] is the sub-list for extension type_name\n\t8, // [8:8] is the sub-list for extension extendee\n\t0, // [0:8] is the sub-list for field type_name\n}\n\nfunc init() { file_transport_internet_headers_http_config_proto_init() }\nfunc file_transport_internet_headers_http_config_proto_init() {\n\tif File_transport_internet_headers_http_config_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_transport_internet_headers_http_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Header); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_transport_internet_headers_http_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Version); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_transport_internet_headers_http_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Method); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_transport_internet_headers_http_config_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*RequestConfig); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_transport_internet_headers_http_config_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Status); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_transport_internet_headers_http_config_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*ResponseConfig); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_transport_internet_headers_http_config_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Config); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_transport_internet_headers_http_config_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   7,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_transport_internet_headers_http_config_proto_goTypes,\n\t\tDependencyIndexes: file_transport_internet_headers_http_config_proto_depIdxs,\n\t\tMessageInfos:      file_transport_internet_headers_http_config_proto_msgTypes,\n\t}.Build()\n\tFile_transport_internet_headers_http_config_proto = out.File\n\tfile_transport_internet_headers_http_config_proto_rawDesc = nil\n\tfile_transport_internet_headers_http_config_proto_goTypes = nil\n\tfile_transport_internet_headers_http_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "transport/internet/headers/http/config.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.transport.internet.headers.http;\noption csharp_namespace = \"V2Ray.Core.Transport.Internet.Headers.Http\";\noption go_package = \"v2ray.com/core/transport/internet/headers/http\";\noption java_package = \"com.v2ray.core.transport.internet.headers.http\";\noption java_multiple_files = true;\n\nmessage Header {\n  // \"Accept\", \"Cookie\", etc\n  string name = 1;\n\n  // Each entry must be valid in one piece. Random entry will be chosen if\n  // multiple entries present.\n  repeated string value = 2;\n}\n\n// HTTP version. Default value \"1.1\".\nmessage Version {\n  string value = 1;\n}\n\n// HTTP method. Default value \"GET\".\nmessage Method {\n  string value = 1;\n}\n\nmessage RequestConfig {\n  // Full HTTP version like \"1.1\".\n  Version version = 1;\n\n  // GET, POST, CONNECT etc\n  Method method = 2;\n\n  // URI like \"/login.php\"\n  repeated string uri = 3;\n\n  repeated Header header = 4;\n}\n\nmessage Status {\n  // Status code. Default \"200\".\n  string code = 1;\n\n  // Statue reason. Default \"OK\".\n  string reason = 2;\n}\n\nmessage ResponseConfig {\n  Version version = 1;\n\n  Status status = 2;\n\n  repeated Header header = 3;\n}\n\nmessage Config {\n  // Settings for authenticating requests. If not set, client side will not send\n  // authenication header, and server side will bypass authentication.\n  RequestConfig request = 1;\n\n  // Settings for authenticating responses. If not set, client side will bypass\n  // authentication, and server side will not send authentication header.\n  ResponseConfig response = 2;\n}\n"
  },
  {
    "path": "transport/internet/headers/http/errors.generated.go",
    "content": "package http\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "transport/internet/headers/http/http.go",
    "content": "package http\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"context\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"strings\"\n\t\"time\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n)\n\nconst (\n\t// CRLF is the line ending in HTTP header\n\tCRLF = \"\\r\\n\"\n\n\t// ENDING is the double line ending between HTTP header and body.\n\tENDING = CRLF + CRLF\n\n\t// max length of HTTP header. Safety precaution for DDoS attack.\n\tmaxHeaderLength = 8192\n)\n\nvar (\n\tErrHeaderToLong = newError(\"Header too long.\")\n\n\tErrHeaderMisMatch = newError(\"Header Mismatch.\")\n)\n\ntype Reader interface {\n\tRead(io.Reader) (*buf.Buffer, error)\n}\n\ntype Writer interface {\n\tWrite(io.Writer) error\n}\n\ntype NoOpReader struct{}\n\nfunc (NoOpReader) Read(io.Reader) (*buf.Buffer, error) {\n\treturn nil, nil\n}\n\ntype NoOpWriter struct{}\n\nfunc (NoOpWriter) Write(io.Writer) error {\n\treturn nil\n}\n\ntype HeaderReader struct {\n\treq            *http.Request\n\texpectedHeader *RequestConfig\n}\n\nfunc (h *HeaderReader) ExpectThisRequest(expectedHeader *RequestConfig) *HeaderReader {\n\th.expectedHeader = expectedHeader\n\treturn h\n}\n\nfunc (h *HeaderReader) Read(reader io.Reader) (*buf.Buffer, error) {\n\tbuffer := buf.New()\n\ttotalBytes := int32(0)\n\tendingDetected := false\n\n\tvar headerBuf bytes.Buffer\n\n\tfor totalBytes < maxHeaderLength {\n\t\t_, err := buffer.ReadFrom(reader)\n\t\tif err != nil {\n\t\t\tbuffer.Release()\n\t\t\treturn nil, err\n\t\t}\n\t\tif n := bytes.Index(buffer.Bytes(), []byte(ENDING)); n != -1 {\n\t\t\theaderBuf.Write(buffer.BytesRange(0, int32(n+len(ENDING))))\n\t\t\tbuffer.Advance(int32(n + len(ENDING)))\n\t\t\tendingDetected = true\n\t\t\tbreak\n\t\t}\n\t\tlenEnding := int32(len(ENDING))\n\t\tif buffer.Len() >= lenEnding {\n\t\t\ttotalBytes += buffer.Len() - lenEnding\n\t\t\theaderBuf.Write(buffer.BytesRange(0, buffer.Len()-lenEnding))\n\t\t\tleftover := buffer.BytesFrom(-lenEnding)\n\t\t\tbuffer.Clear()\n\t\t\tcopy(buffer.Extend(lenEnding), leftover)\n\n\t\t\tif _, err := readRequest(bufio.NewReader(bytes.NewReader(headerBuf.Bytes())), false); err != io.ErrUnexpectedEOF {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\t}\n\n\tif !endingDetected {\n\t\tbuffer.Release()\n\t\treturn nil, ErrHeaderToLong\n\t}\n\n\tif h.expectedHeader == nil {\n\t\tif buffer.IsEmpty() {\n\t\t\tbuffer.Release()\n\t\t\treturn nil, nil\n\t\t}\n\t\treturn buffer, nil\n\t}\n\n\t//Parse the request\n\n\tif req, err := readRequest(bufio.NewReader(bytes.NewReader(headerBuf.Bytes())), false); err != nil {\n\t\treturn nil, err\n\t} else {\n\t\th.req = req\n\t}\n\n\t//Check req\n\tpath := h.req.URL.Path\n\thasThisUri := false\n\tfor _, u := range h.expectedHeader.Uri {\n\t\tif u == path {\n\t\t\thasThisUri = true\n\t\t}\n\t}\n\n\tif !hasThisUri {\n\t\treturn nil, ErrHeaderMisMatch\n\t}\n\n\tif buffer.IsEmpty() {\n\t\tbuffer.Release()\n\t\treturn nil, nil\n\t}\n\n\treturn buffer, nil\n}\n\ntype HeaderWriter struct {\n\theader *buf.Buffer\n}\n\nfunc NewHeaderWriter(header *buf.Buffer) *HeaderWriter {\n\treturn &HeaderWriter{\n\t\theader: header,\n\t}\n}\n\nfunc (w *HeaderWriter) Write(writer io.Writer) error {\n\tif w.header == nil {\n\t\treturn nil\n\t}\n\terr := buf.WriteAllBytes(writer, w.header.Bytes())\n\tw.header.Release()\n\tw.header = nil\n\treturn err\n}\n\ntype HttpConn struct {\n\tnet.Conn\n\n\treadBuffer          *buf.Buffer\n\toneTimeReader       Reader\n\toneTimeWriter       Writer\n\terrorWriter         Writer\n\terrorMismatchWriter Writer\n\terrorTooLongWriter  Writer\n\n\terrReason error\n}\n\nfunc NewHttpConn(conn net.Conn, reader Reader, writer Writer, errorWriter Writer, errorMismatchWriter Writer, errorTooLongWriter Writer) *HttpConn {\n\treturn &HttpConn{\n\t\tConn:                conn,\n\t\toneTimeReader:       reader,\n\t\toneTimeWriter:       writer,\n\t\terrorWriter:         errorWriter,\n\t\terrorMismatchWriter: errorMismatchWriter,\n\t\terrorTooLongWriter:  errorTooLongWriter,\n\t}\n}\n\nfunc (c *HttpConn) Read(b []byte) (int, error) {\n\tif c.oneTimeReader != nil {\n\t\tbuffer, err := c.oneTimeReader.Read(c.Conn)\n\t\tif err != nil {\n\t\t\tc.errReason = err\n\t\t\treturn 0, err\n\t\t}\n\t\tc.readBuffer = buffer\n\t\tc.oneTimeReader = nil\n\t}\n\n\tif !c.readBuffer.IsEmpty() {\n\t\tnBytes, _ := c.readBuffer.Read(b)\n\t\tif c.readBuffer.IsEmpty() {\n\t\t\tc.readBuffer.Release()\n\t\t\tc.readBuffer = nil\n\t\t}\n\t\treturn nBytes, nil\n\t}\n\n\treturn c.Conn.Read(b)\n}\n\n// Write implements io.Writer.\nfunc (c *HttpConn) Write(b []byte) (int, error) {\n\tif c.oneTimeWriter != nil {\n\t\terr := c.oneTimeWriter.Write(c.Conn)\n\t\tc.oneTimeWriter = nil\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t}\n\n\treturn c.Conn.Write(b)\n}\n\n// Close implements net.Conn.Close().\nfunc (c *HttpConn) Close() error {\n\tif c.oneTimeWriter != nil && c.errorWriter != nil {\n\t\t// Connection is being closed but header wasn't sent. This means the client request\n\t\t// is probably not valid. Sending back a server error header in this case.\n\n\t\t//Write response based on error reason\n\n\t\tif c.errReason == ErrHeaderMisMatch {\n\t\t\tc.errorMismatchWriter.Write(c.Conn)\n\t\t} else if c.errReason == ErrHeaderToLong {\n\t\t\tc.errorTooLongWriter.Write(c.Conn)\n\t\t} else {\n\t\t\tc.errorWriter.Write(c.Conn)\n\t\t}\n\t}\n\n\treturn c.Conn.Close()\n}\n\nfunc formResponseHeader(config *ResponseConfig) *HeaderWriter {\n\theader := buf.New()\n\tcommon.Must2(header.WriteString(strings.Join([]string{config.GetFullVersion(), config.GetStatusValue().Code, config.GetStatusValue().Reason}, \" \")))\n\tcommon.Must2(header.WriteString(CRLF))\n\n\theaders := config.PickHeaders()\n\tfor _, h := range headers {\n\t\tcommon.Must2(header.WriteString(h))\n\t\tcommon.Must2(header.WriteString(CRLF))\n\t}\n\tif !config.HasHeader(\"Date\") {\n\t\tcommon.Must2(header.WriteString(\"Date: \"))\n\t\tcommon.Must2(header.WriteString(time.Now().Format(http.TimeFormat)))\n\t\tcommon.Must2(header.WriteString(CRLF))\n\t}\n\tcommon.Must2(header.WriteString(CRLF))\n\treturn &HeaderWriter{\n\t\theader: header,\n\t}\n}\n\ntype HttpAuthenticator struct {\n\tconfig *Config\n}\n\nfunc (a HttpAuthenticator) GetClientWriter() *HeaderWriter {\n\theader := buf.New()\n\tconfig := a.config.Request\n\tcommon.Must2(header.WriteString(strings.Join([]string{config.GetMethodValue(), config.PickUri(), config.GetFullVersion()}, \" \")))\n\tcommon.Must2(header.WriteString(CRLF))\n\n\theaders := config.PickHeaders()\n\tfor _, h := range headers {\n\t\tcommon.Must2(header.WriteString(h))\n\t\tcommon.Must2(header.WriteString(CRLF))\n\t}\n\tcommon.Must2(header.WriteString(CRLF))\n\treturn &HeaderWriter{\n\t\theader: header,\n\t}\n}\n\nfunc (a HttpAuthenticator) GetServerWriter() *HeaderWriter {\n\treturn formResponseHeader(a.config.Response)\n}\n\nfunc (a HttpAuthenticator) Client(conn net.Conn) net.Conn {\n\tif a.config.Request == nil && a.config.Response == nil {\n\t\treturn conn\n\t}\n\tvar reader Reader = NoOpReader{}\n\tif a.config.Request != nil {\n\t\treader = new(HeaderReader)\n\t}\n\n\tvar writer Writer = NoOpWriter{}\n\tif a.config.Response != nil {\n\t\twriter = a.GetClientWriter()\n\t}\n\treturn NewHttpConn(conn, reader, writer, NoOpWriter{}, NoOpWriter{}, NoOpWriter{})\n}\n\nfunc (a HttpAuthenticator) Server(conn net.Conn) net.Conn {\n\tif a.config.Request == nil && a.config.Response == nil {\n\t\treturn conn\n\t}\n\treturn NewHttpConn(conn, new(HeaderReader).ExpectThisRequest(a.config.Request), a.GetServerWriter(),\n\t\tformResponseHeader(resp400),\n\t\tformResponseHeader(resp404),\n\t\tformResponseHeader(resp400))\n}\n\nfunc NewHttpAuthenticator(ctx context.Context, config *Config) (HttpAuthenticator, error) {\n\treturn HttpAuthenticator{\n\t\tconfig: config,\n\t}, nil\n}\n\nfunc init() {\n\tcommon.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {\n\t\treturn NewHttpAuthenticator(ctx, config.(*Config))\n\t}))\n}\n"
  },
  {
    "path": "transport/internet/headers/http/http_test.go",
    "content": "package http_test\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"context\"\n\t\"crypto/rand\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/net\"\n\t. \"v2ray.com/core/transport/internet/headers/http\"\n)\n\nfunc TestReaderWriter(t *testing.T) {\n\tcache := buf.New()\n\tb := buf.New()\n\tcommon.Must2(b.WriteString(\"abcd\" + ENDING))\n\twriter := NewHeaderWriter(b)\n\terr := writer.Write(cache)\n\tcommon.Must(err)\n\tif v := cache.Len(); v != 8 {\n\t\tt.Error(\"cache len: \", v)\n\t}\n\t_, err = cache.Write([]byte{'e', 'f', 'g'})\n\tcommon.Must(err)\n\n\treader := &HeaderReader{}\n\tbuffer, err := reader.Read(cache)\n\tif err != nil && !strings.HasPrefix(err.Error(), \"malformed HTTP request\") {\n\t\tt.Error(\"unknown error \", err)\n\t}\n\t_ = buffer\n\t/*\n\t\tif buffer.String() != \"efg\" {\n\t\t\tt.Error(\"buffer: \", buffer.String())\n\t\t}*/\n}\n\nfunc TestRequestHeader(t *testing.T) {\n\tauth, err := NewHttpAuthenticator(context.Background(), &Config{\n\t\tRequest: &RequestConfig{\n\t\t\tUri: []string{\"/\"},\n\t\t\tHeader: []*Header{\n\t\t\t\t{\n\t\t\t\t\tName:  \"Test\",\n\t\t\t\t\tValue: []string{\"Value\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t})\n\tcommon.Must(err)\n\n\tcache := buf.New()\n\terr = auth.GetClientWriter().Write(cache)\n\tcommon.Must(err)\n\n\tif cache.String() != \"GET / HTTP/1.1\\r\\nTest: Value\\r\\n\\r\\n\" {\n\t\tt.Error(\"cache: \", cache.String())\n\t}\n}\n\nfunc TestLongRequestHeader(t *testing.T) {\n\tpayload := make([]byte, buf.Size+2)\n\tcommon.Must2(rand.Read(payload[:buf.Size-2]))\n\tcopy(payload[buf.Size-2:], []byte(ENDING))\n\tpayload = append(payload, []byte(\"abcd\")...)\n\n\treader := HeaderReader{}\n\tb, err := reader.Read(bytes.NewReader(payload))\n\n\tif err != nil && !(strings.HasPrefix(err.Error(), \"invalid\") || strings.HasPrefix(err.Error(), \"malformed\")) {\n\t\tt.Error(\"unknown error \", err)\n\t}\n\t_ = b\n\t/*\n\t\tcommon.Must(err)\n\t\tif b.String() != \"abcd\" {\n\t\t\tt.Error(\"expect content abcd, but actually \", b.String())\n\t\t}*/\n}\n\nfunc TestConnection(t *testing.T) {\n\tauth, err := NewHttpAuthenticator(context.Background(), &Config{\n\t\tRequest: &RequestConfig{\n\t\t\tMethod: &Method{Value: \"Post\"},\n\t\t\tUri:    []string{\"/testpath\"},\n\t\t\tHeader: []*Header{\n\t\t\t\t{\n\t\t\t\t\tName:  \"Host\",\n\t\t\t\t\tValue: []string{\"www.v2ray.com\", \"www.google.com\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:  \"User-Agent\",\n\t\t\t\t\tValue: []string{\"Test-Agent\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tResponse: &ResponseConfig{\n\t\t\tVersion: &Version{\n\t\t\t\tValue: \"1.1\",\n\t\t\t},\n\t\t\tStatus: &Status{\n\t\t\t\tCode:   \"404\",\n\t\t\t\tReason: \"Not Found\",\n\t\t\t},\n\t\t},\n\t})\n\tcommon.Must(err)\n\n\tlistener, err := net.Listen(\"tcp\", \"127.0.0.1:0\")\n\tcommon.Must(err)\n\n\tgo func() {\n\t\tconn, err := listener.Accept()\n\t\tcommon.Must(err)\n\t\tauthConn := auth.Server(conn)\n\t\tb := make([]byte, 256)\n\t\tfor {\n\t\t\tn, err := authConn.Read(b)\n\t\t\tif err != nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\t_, err = authConn.Write(b[:n])\n\t\t\tcommon.Must(err)\n\t\t}\n\t}()\n\n\tconn, err := net.DialTCP(\"tcp\", nil, listener.Addr().(*net.TCPAddr))\n\tcommon.Must(err)\n\n\tauthConn := auth.Client(conn)\n\tdefer authConn.Close()\n\n\tauthConn.Write([]byte(\"Test payload\"))\n\tauthConn.Write([]byte(\"Test payload 2\"))\n\n\texpectedResponse := \"Test payloadTest payload 2\"\n\tactualResponse := make([]byte, 256)\n\tdeadline := time.Now().Add(time.Second * 5)\n\ttotalBytes := 0\n\tfor {\n\t\tn, err := authConn.Read(actualResponse[totalBytes:])\n\t\tcommon.Must(err)\n\t\ttotalBytes += n\n\t\tif totalBytes >= len(expectedResponse) || time.Now().After(deadline) {\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif string(actualResponse[:totalBytes]) != expectedResponse {\n\t\tt.Error(\"response: \", string(actualResponse[:totalBytes]))\n\t}\n}\n\nfunc TestConnectionInvPath(t *testing.T) {\n\tauth, err := NewHttpAuthenticator(context.Background(), &Config{\n\t\tRequest: &RequestConfig{\n\t\t\tMethod: &Method{Value: \"Post\"},\n\t\t\tUri:    []string{\"/testpath\"},\n\t\t\tHeader: []*Header{\n\t\t\t\t{\n\t\t\t\t\tName:  \"Host\",\n\t\t\t\t\tValue: []string{\"www.v2ray.com\", \"www.google.com\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:  \"User-Agent\",\n\t\t\t\t\tValue: []string{\"Test-Agent\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tResponse: &ResponseConfig{\n\t\t\tVersion: &Version{\n\t\t\t\tValue: \"1.1\",\n\t\t\t},\n\t\t\tStatus: &Status{\n\t\t\t\tCode:   \"404\",\n\t\t\t\tReason: \"Not Found\",\n\t\t\t},\n\t\t},\n\t})\n\tcommon.Must(err)\n\n\tauthR, err := NewHttpAuthenticator(context.Background(), &Config{\n\t\tRequest: &RequestConfig{\n\t\t\tMethod: &Method{Value: \"Post\"},\n\t\t\tUri:    []string{\"/testpathErr\"},\n\t\t\tHeader: []*Header{\n\t\t\t\t{\n\t\t\t\t\tName:  \"Host\",\n\t\t\t\t\tValue: []string{\"www.v2ray.com\", \"www.google.com\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:  \"User-Agent\",\n\t\t\t\t\tValue: []string{\"Test-Agent\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tResponse: &ResponseConfig{\n\t\t\tVersion: &Version{\n\t\t\t\tValue: \"1.1\",\n\t\t\t},\n\t\t\tStatus: &Status{\n\t\t\t\tCode:   \"404\",\n\t\t\t\tReason: \"Not Found\",\n\t\t\t},\n\t\t},\n\t})\n\tcommon.Must(err)\n\n\tlistener, err := net.Listen(\"tcp\", \"127.0.0.1:0\")\n\tcommon.Must(err)\n\n\tgo func() {\n\t\tconn, err := listener.Accept()\n\t\tcommon.Must(err)\n\t\tauthConn := auth.Server(conn)\n\t\tb := make([]byte, 256)\n\t\tfor {\n\t\t\tn, err := authConn.Read(b)\n\t\t\tif err != nil {\n\t\t\t\tauthConn.Close()\n\t\t\t\tbreak\n\t\t\t}\n\t\t\t_, err = authConn.Write(b[:n])\n\t\t\tcommon.Must(err)\n\t\t}\n\t}()\n\n\tconn, err := net.DialTCP(\"tcp\", nil, listener.Addr().(*net.TCPAddr))\n\tcommon.Must(err)\n\n\tauthConn := authR.Client(conn)\n\tdefer authConn.Close()\n\n\tauthConn.Write([]byte(\"Test payload\"))\n\tauthConn.Write([]byte(\"Test payload 2\"))\n\n\texpectedResponse := \"Test payloadTest payload 2\"\n\tactualResponse := make([]byte, 256)\n\tdeadline := time.Now().Add(time.Second * 5)\n\ttotalBytes := 0\n\tfor {\n\t\tn, err := authConn.Read(actualResponse[totalBytes:])\n\t\tif err == nil {\n\t\t\tt.Error(\"Error Expected\", err)\n\t\t} else {\n\t\t\treturn\n\t\t}\n\t\ttotalBytes += n\n\t\tif totalBytes >= len(expectedResponse) || time.Now().After(deadline) {\n\t\t\tbreak\n\t\t}\n\t}\n}\n\nfunc TestConnectionInvReq(t *testing.T) {\n\tauth, err := NewHttpAuthenticator(context.Background(), &Config{\n\t\tRequest: &RequestConfig{\n\t\t\tMethod: &Method{Value: \"Post\"},\n\t\t\tUri:    []string{\"/testpath\"},\n\t\t\tHeader: []*Header{\n\t\t\t\t{\n\t\t\t\t\tName:  \"Host\",\n\t\t\t\t\tValue: []string{\"www.v2ray.com\", \"www.google.com\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:  \"User-Agent\",\n\t\t\t\t\tValue: []string{\"Test-Agent\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tResponse: &ResponseConfig{\n\t\t\tVersion: &Version{\n\t\t\t\tValue: \"1.1\",\n\t\t\t},\n\t\t\tStatus: &Status{\n\t\t\t\tCode:   \"404\",\n\t\t\t\tReason: \"Not Found\",\n\t\t\t},\n\t\t},\n\t})\n\tcommon.Must(err)\n\n\tlistener, err := net.Listen(\"tcp\", \"127.0.0.1:0\")\n\tcommon.Must(err)\n\n\tgo func() {\n\t\tconn, err := listener.Accept()\n\t\tcommon.Must(err)\n\t\tauthConn := auth.Server(conn)\n\t\tb := make([]byte, 256)\n\t\tfor {\n\t\t\tn, err := authConn.Read(b)\n\t\t\tif err != nil {\n\t\t\t\tauthConn.Close()\n\t\t\t\tbreak\n\t\t\t}\n\t\t\t_, err = authConn.Write(b[:n])\n\t\t\tcommon.Must(err)\n\t\t}\n\t}()\n\n\tconn, err := net.DialTCP(\"tcp\", nil, listener.Addr().(*net.TCPAddr))\n\tcommon.Must(err)\n\n\tconn.Write([]byte(\"ABCDEFGHIJKMLN\\r\\n\\r\\n\"))\n\tl, _, err := bufio.NewReader(conn).ReadLine()\n\tcommon.Must(err)\n\tif !strings.HasPrefix(string(l), \"HTTP/1.1 400 Bad Request\") {\n\t\tt.Error(\"Resp to non http conn\", string(l))\n\t}\n}\n"
  },
  {
    "path": "transport/internet/headers/http/linkedreadRequest.go",
    "content": "package http\n\nimport (\n\t\"bufio\"\n\t\"net/http\"\n\n\t_ \"unsafe\" // required to use //go:linkname\n)\n\n//go:linkname readRequest net/http.readRequest\nfunc readRequest(b *bufio.Reader, deleteHostHeader bool) (req *http.Request, err error)\n"
  },
  {
    "path": "transport/internet/headers/http/resp.go",
    "content": "package http\n\nvar resp400 = &ResponseConfig{\n\tVersion: &Version{\n\t\tValue: \"1.1\",\n\t},\n\tStatus: &Status{\n\t\tCode:   \"400\",\n\t\tReason: \"Bad Request\",\n\t},\n\tHeader: []*Header{\n\t\t{\n\t\t\tName:  \"Connection\",\n\t\t\tValue: []string{\"close\"},\n\t\t},\n\t\t{\n\t\t\tName:  \"Cache-Control\",\n\t\t\tValue: []string{\"private\"},\n\t\t},\n\t\t{\n\t\t\tName:  \"Content-Length\",\n\t\t\tValue: []string{\"0\"},\n\t\t},\n\t},\n}\n\nvar resp404 = &ResponseConfig{\n\tVersion: &Version{\n\t\tValue: \"1.1\",\n\t},\n\tStatus: &Status{\n\t\tCode:   \"404\",\n\t\tReason: \"Not Found\",\n\t},\n\tHeader: []*Header{\n\t\t{\n\t\t\tName:  \"Connection\",\n\t\t\tValue: []string{\"close\"},\n\t\t},\n\t\t{\n\t\t\tName:  \"Cache-Control\",\n\t\t\tValue: []string{\"private\"},\n\t\t},\n\t\t{\n\t\t\tName:  \"Content-Length\",\n\t\t\tValue: []string{\"0\"},\n\t\t},\n\t},\n}\n"
  },
  {
    "path": "transport/internet/headers/noop/config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: transport/internet/headers/noop/config.proto\n\npackage noop\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype Config struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *Config) Reset() {\n\t*x = Config{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_transport_internet_headers_noop_config_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Config) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Config) ProtoMessage() {}\n\nfunc (x *Config) ProtoReflect() protoreflect.Message {\n\tmi := &file_transport_internet_headers_noop_config_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Config.ProtoReflect.Descriptor instead.\nfunc (*Config) Descriptor() ([]byte, []int) {\n\treturn file_transport_internet_headers_noop_config_proto_rawDescGZIP(), []int{0}\n}\n\ntype ConnectionConfig struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *ConnectionConfig) Reset() {\n\t*x = ConnectionConfig{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_transport_internet_headers_noop_config_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *ConnectionConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ConnectionConfig) ProtoMessage() {}\n\nfunc (x *ConnectionConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_transport_internet_headers_noop_config_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ConnectionConfig.ProtoReflect.Descriptor instead.\nfunc (*ConnectionConfig) Descriptor() ([]byte, []int) {\n\treturn file_transport_internet_headers_noop_config_proto_rawDescGZIP(), []int{1}\n}\n\nvar File_transport_internet_headers_noop_config_proto protoreflect.FileDescriptor\n\nvar file_transport_internet_headers_noop_config_proto_rawDesc = []byte{\n\t0x0a, 0x2c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65,\n\t0x72, 0x6e, 0x65, 0x74, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2f, 0x6e, 0x6f, 0x6f,\n\t0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x2a,\n\t0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73,\n\t0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x68, 0x65,\n\t0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x6e, 0x6f, 0x6f, 0x70, 0x22, 0x08, 0x0a, 0x06, 0x43, 0x6f,\n\t0x6e, 0x66, 0x69, 0x67, 0x22, 0x12, 0x0a, 0x10, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69,\n\t0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x8f, 0x01, 0x0a, 0x2e, 0x63, 0x6f, 0x6d,\n\t0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e,\n\t0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x68,\n\t0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x6e, 0x6f, 0x6f, 0x70, 0x50, 0x01, 0x5a, 0x2e, 0x76,\n\t0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72,\n\t0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74,\n\t0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2f, 0x6e, 0x6f, 0x6f, 0x70, 0xaa, 0x02, 0x2a,\n\t0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73,\n\t0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x48, 0x65,\n\t0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x4e, 0x6f, 0x6f, 0x70, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,\n\t0x6f, 0x33,\n}\n\nvar (\n\tfile_transport_internet_headers_noop_config_proto_rawDescOnce sync.Once\n\tfile_transport_internet_headers_noop_config_proto_rawDescData = file_transport_internet_headers_noop_config_proto_rawDesc\n)\n\nfunc file_transport_internet_headers_noop_config_proto_rawDescGZIP() []byte {\n\tfile_transport_internet_headers_noop_config_proto_rawDescOnce.Do(func() {\n\t\tfile_transport_internet_headers_noop_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_transport_internet_headers_noop_config_proto_rawDescData)\n\t})\n\treturn file_transport_internet_headers_noop_config_proto_rawDescData\n}\n\nvar file_transport_internet_headers_noop_config_proto_msgTypes = make([]protoimpl.MessageInfo, 2)\nvar file_transport_internet_headers_noop_config_proto_goTypes = []interface{}{\n\t(*Config)(nil),           // 0: v2ray.core.transport.internet.headers.noop.Config\n\t(*ConnectionConfig)(nil), // 1: v2ray.core.transport.internet.headers.noop.ConnectionConfig\n}\nvar file_transport_internet_headers_noop_config_proto_depIdxs = []int32{\n\t0, // [0:0] is the sub-list for method output_type\n\t0, // [0:0] is the sub-list for method input_type\n\t0, // [0:0] is the sub-list for extension type_name\n\t0, // [0:0] is the sub-list for extension extendee\n\t0, // [0:0] is the sub-list for field type_name\n}\n\nfunc init() { file_transport_internet_headers_noop_config_proto_init() }\nfunc file_transport_internet_headers_noop_config_proto_init() {\n\tif File_transport_internet_headers_noop_config_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_transport_internet_headers_noop_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Config); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_transport_internet_headers_noop_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*ConnectionConfig); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_transport_internet_headers_noop_config_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   2,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_transport_internet_headers_noop_config_proto_goTypes,\n\t\tDependencyIndexes: file_transport_internet_headers_noop_config_proto_depIdxs,\n\t\tMessageInfos:      file_transport_internet_headers_noop_config_proto_msgTypes,\n\t}.Build()\n\tFile_transport_internet_headers_noop_config_proto = out.File\n\tfile_transport_internet_headers_noop_config_proto_rawDesc = nil\n\tfile_transport_internet_headers_noop_config_proto_goTypes = nil\n\tfile_transport_internet_headers_noop_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "transport/internet/headers/noop/config.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.transport.internet.headers.noop;\noption csharp_namespace = \"V2Ray.Core.Transport.Internet.Headers.Noop\";\noption go_package = \"v2ray.com/core/transport/internet/headers/noop\";\noption java_package = \"com.v2ray.core.transport.internet.headers.noop\";\noption java_multiple_files = true;\n\nmessage Config {}\n\nmessage ConnectionConfig {}\n"
  },
  {
    "path": "transport/internet/headers/noop/noop.go",
    "content": "package noop\n\nimport (\n\t\"context\"\n\t\"net\"\n\n\t\"v2ray.com/core/common\"\n)\n\ntype NoOpHeader struct{}\n\nfunc (NoOpHeader) Size() int32 {\n\treturn 0\n}\n\n// Serialize implements PacketHeader.\nfunc (NoOpHeader) Serialize([]byte) {}\n\nfunc NewNoOpHeader(context.Context, interface{}) (interface{}, error) {\n\treturn NoOpHeader{}, nil\n}\n\ntype NoOpConnectionHeader struct{}\n\nfunc (NoOpConnectionHeader) Client(conn net.Conn) net.Conn {\n\treturn conn\n}\n\nfunc (NoOpConnectionHeader) Server(conn net.Conn) net.Conn {\n\treturn conn\n}\n\nfunc NewNoOpConnectionHeader(context.Context, interface{}) (interface{}, error) {\n\treturn NoOpConnectionHeader{}, nil\n}\n\nfunc init() {\n\tcommon.Must(common.RegisterConfig((*Config)(nil), NewNoOpHeader))\n\tcommon.Must(common.RegisterConfig((*ConnectionConfig)(nil), NewNoOpConnectionHeader))\n}\n"
  },
  {
    "path": "transport/internet/headers/srtp/config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: transport/internet/headers/srtp/config.proto\n\npackage srtp\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype Config struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tVersion     uint32 `protobuf:\"varint,1,opt,name=version,proto3\" json:\"version,omitempty\"`\n\tPadding     bool   `protobuf:\"varint,2,opt,name=padding,proto3\" json:\"padding,omitempty\"`\n\tExtension   bool   `protobuf:\"varint,3,opt,name=extension,proto3\" json:\"extension,omitempty\"`\n\tCsrcCount   uint32 `protobuf:\"varint,4,opt,name=csrc_count,json=csrcCount,proto3\" json:\"csrc_count,omitempty\"`\n\tMarker      bool   `protobuf:\"varint,5,opt,name=marker,proto3\" json:\"marker,omitempty\"`\n\tPayloadType uint32 `protobuf:\"varint,6,opt,name=payload_type,json=payloadType,proto3\" json:\"payload_type,omitempty\"`\n}\n\nfunc (x *Config) Reset() {\n\t*x = Config{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_transport_internet_headers_srtp_config_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Config) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Config) ProtoMessage() {}\n\nfunc (x *Config) ProtoReflect() protoreflect.Message {\n\tmi := &file_transport_internet_headers_srtp_config_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Config.ProtoReflect.Descriptor instead.\nfunc (*Config) Descriptor() ([]byte, []int) {\n\treturn file_transport_internet_headers_srtp_config_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *Config) GetVersion() uint32 {\n\tif x != nil {\n\t\treturn x.Version\n\t}\n\treturn 0\n}\n\nfunc (x *Config) GetPadding() bool {\n\tif x != nil {\n\t\treturn x.Padding\n\t}\n\treturn false\n}\n\nfunc (x *Config) GetExtension() bool {\n\tif x != nil {\n\t\treturn x.Extension\n\t}\n\treturn false\n}\n\nfunc (x *Config) GetCsrcCount() uint32 {\n\tif x != nil {\n\t\treturn x.CsrcCount\n\t}\n\treturn 0\n}\n\nfunc (x *Config) GetMarker() bool {\n\tif x != nil {\n\t\treturn x.Marker\n\t}\n\treturn false\n}\n\nfunc (x *Config) GetPayloadType() uint32 {\n\tif x != nil {\n\t\treturn x.PayloadType\n\t}\n\treturn 0\n}\n\nvar File_transport_internet_headers_srtp_config_proto protoreflect.FileDescriptor\n\nvar file_transport_internet_headers_srtp_config_proto_rawDesc = []byte{\n\t0x0a, 0x2c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65,\n\t0x72, 0x6e, 0x65, 0x74, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2f, 0x73, 0x72, 0x74,\n\t0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x2a,\n\t0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73,\n\t0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x68, 0x65,\n\t0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x72, 0x74, 0x70, 0x22, 0xb4, 0x01, 0x0a, 0x06, 0x43,\n\t0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,\n\t0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12,\n\t0x18, 0x0a, 0x07, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08,\n\t0x52, 0x07, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x1c, 0x0a, 0x09, 0x65, 0x78, 0x74,\n\t0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x65, 0x78,\n\t0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x73, 0x72, 0x63, 0x5f,\n\t0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x63, 0x73, 0x72,\n\t0x63, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x72,\n\t0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x72, 0x12, 0x21,\n\t0x0a, 0x0c, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x06,\n\t0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x79, 0x70,\n\t0x65, 0x42, 0x8f, 0x01, 0x0a, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,\n\t0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69,\n\t0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e,\n\t0x73, 0x72, 0x74, 0x70, 0x50, 0x01, 0x5a, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,\n\t0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74,\n\t0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72,\n\t0x73, 0x2f, 0x73, 0x72, 0x74, 0x70, 0xaa, 0x02, 0x2a, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43,\n\t0x6f, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e,\n\t0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x53,\n\t0x72, 0x74, 0x70, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_transport_internet_headers_srtp_config_proto_rawDescOnce sync.Once\n\tfile_transport_internet_headers_srtp_config_proto_rawDescData = file_transport_internet_headers_srtp_config_proto_rawDesc\n)\n\nfunc file_transport_internet_headers_srtp_config_proto_rawDescGZIP() []byte {\n\tfile_transport_internet_headers_srtp_config_proto_rawDescOnce.Do(func() {\n\t\tfile_transport_internet_headers_srtp_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_transport_internet_headers_srtp_config_proto_rawDescData)\n\t})\n\treturn file_transport_internet_headers_srtp_config_proto_rawDescData\n}\n\nvar file_transport_internet_headers_srtp_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)\nvar file_transport_internet_headers_srtp_config_proto_goTypes = []interface{}{\n\t(*Config)(nil), // 0: v2ray.core.transport.internet.headers.srtp.Config\n}\nvar file_transport_internet_headers_srtp_config_proto_depIdxs = []int32{\n\t0, // [0:0] is the sub-list for method output_type\n\t0, // [0:0] is the sub-list for method input_type\n\t0, // [0:0] is the sub-list for extension type_name\n\t0, // [0:0] is the sub-list for extension extendee\n\t0, // [0:0] is the sub-list for field type_name\n}\n\nfunc init() { file_transport_internet_headers_srtp_config_proto_init() }\nfunc file_transport_internet_headers_srtp_config_proto_init() {\n\tif File_transport_internet_headers_srtp_config_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_transport_internet_headers_srtp_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Config); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_transport_internet_headers_srtp_config_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   1,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_transport_internet_headers_srtp_config_proto_goTypes,\n\t\tDependencyIndexes: file_transport_internet_headers_srtp_config_proto_depIdxs,\n\t\tMessageInfos:      file_transport_internet_headers_srtp_config_proto_msgTypes,\n\t}.Build()\n\tFile_transport_internet_headers_srtp_config_proto = out.File\n\tfile_transport_internet_headers_srtp_config_proto_rawDesc = nil\n\tfile_transport_internet_headers_srtp_config_proto_goTypes = nil\n\tfile_transport_internet_headers_srtp_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "transport/internet/headers/srtp/config.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.transport.internet.headers.srtp;\noption csharp_namespace = \"V2Ray.Core.Transport.Internet.Headers.Srtp\";\noption go_package = \"v2ray.com/core/transport/internet/headers/srtp\";\noption java_package = \"com.v2ray.core.transport.internet.headers.srtp\";\noption java_multiple_files = true;\n\nmessage Config {\n  uint32 version = 1;\n\tbool padding = 2;\n\tbool extension   = 3;\n\tuint32 csrc_count = 4;\n\tbool marker     = 5;\n\tuint32 payload_type = 6;\n}\n"
  },
  {
    "path": "transport/internet/headers/srtp/srtp.go",
    "content": "package srtp\n\nimport (\n\t\"context\"\n\t\"encoding/binary\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/dice\"\n)\n\ntype SRTP struct {\n\theader uint16\n\tnumber uint16\n}\n\nfunc (*SRTP) Size() int32 {\n\treturn 4\n}\n\n// Serialize implements PacketHeader.\nfunc (s *SRTP) Serialize(b []byte) {\n\ts.number++\n\tbinary.BigEndian.PutUint16(b, s.header)\n\tbinary.BigEndian.PutUint16(b[2:], s.number)\n}\n\n// New returns a new SRTP instance based on the given config.\nfunc New(ctx context.Context, config interface{}) (interface{}, error) {\n\treturn &SRTP{\n\t\theader: 0xB5E8,\n\t\tnumber: dice.RollUint16(),\n\t}, nil\n}\n\nfunc init() {\n\tcommon.Must(common.RegisterConfig((*Config)(nil), New))\n}\n"
  },
  {
    "path": "transport/internet/headers/srtp/srtp_test.go",
    "content": "package srtp_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t. \"v2ray.com/core/transport/internet/headers/srtp\"\n)\n\nfunc TestSRTPWrite(t *testing.T) {\n\tcontent := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g'}\n\tsrtpRaw, err := New(context.Background(), &Config{})\n\tcommon.Must(err)\n\n\tsrtp := srtpRaw.(*SRTP)\n\n\tpayload := buf.New()\n\tsrtp.Serialize(payload.Extend(srtp.Size()))\n\tpayload.Write(content)\n\n\texpectedLen := int32(len(content)) + srtp.Size()\n\tif payload.Len() != expectedLen {\n\t\tt.Error(\"expected \", expectedLen, \" of bytes, but got \", payload.Len())\n\t}\n}\n"
  },
  {
    "path": "transport/internet/headers/tls/config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: transport/internet/headers/tls/config.proto\n\npackage tls\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype PacketConfig struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *PacketConfig) Reset() {\n\t*x = PacketConfig{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_transport_internet_headers_tls_config_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *PacketConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*PacketConfig) ProtoMessage() {}\n\nfunc (x *PacketConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_transport_internet_headers_tls_config_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use PacketConfig.ProtoReflect.Descriptor instead.\nfunc (*PacketConfig) Descriptor() ([]byte, []int) {\n\treturn file_transport_internet_headers_tls_config_proto_rawDescGZIP(), []int{0}\n}\n\nvar File_transport_internet_headers_tls_config_proto protoreflect.FileDescriptor\n\nvar file_transport_internet_headers_tls_config_proto_rawDesc = []byte{\n\t0x0a, 0x2b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65,\n\t0x72, 0x6e, 0x65, 0x74, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2f, 0x74, 0x6c, 0x73,\n\t0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x29, 0x76,\n\t0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70,\n\t0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x68, 0x65, 0x61,\n\t0x64, 0x65, 0x72, 0x73, 0x2e, 0x74, 0x6c, 0x73, 0x22, 0x0e, 0x0a, 0x0c, 0x50, 0x61, 0x63, 0x6b,\n\t0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x8c, 0x01, 0x0a, 0x2d, 0x63, 0x6f, 0x6d,\n\t0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e,\n\t0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x68,\n\t0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x74, 0x6c, 0x73, 0x50, 0x01, 0x5a, 0x2d, 0x76, 0x32,\n\t0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72, 0x61,\n\t0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2f,\n\t0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2f, 0x74, 0x6c, 0x73, 0xaa, 0x02, 0x29, 0x56, 0x32,\n\t0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f,\n\t0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x48, 0x65, 0x61, 0x64,\n\t0x65, 0x72, 0x73, 0x2e, 0x54, 0x6c, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_transport_internet_headers_tls_config_proto_rawDescOnce sync.Once\n\tfile_transport_internet_headers_tls_config_proto_rawDescData = file_transport_internet_headers_tls_config_proto_rawDesc\n)\n\nfunc file_transport_internet_headers_tls_config_proto_rawDescGZIP() []byte {\n\tfile_transport_internet_headers_tls_config_proto_rawDescOnce.Do(func() {\n\t\tfile_transport_internet_headers_tls_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_transport_internet_headers_tls_config_proto_rawDescData)\n\t})\n\treturn file_transport_internet_headers_tls_config_proto_rawDescData\n}\n\nvar file_transport_internet_headers_tls_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)\nvar file_transport_internet_headers_tls_config_proto_goTypes = []interface{}{\n\t(*PacketConfig)(nil), // 0: v2ray.core.transport.internet.headers.tls.PacketConfig\n}\nvar file_transport_internet_headers_tls_config_proto_depIdxs = []int32{\n\t0, // [0:0] is the sub-list for method output_type\n\t0, // [0:0] is the sub-list for method input_type\n\t0, // [0:0] is the sub-list for extension type_name\n\t0, // [0:0] is the sub-list for extension extendee\n\t0, // [0:0] is the sub-list for field type_name\n}\n\nfunc init() { file_transport_internet_headers_tls_config_proto_init() }\nfunc file_transport_internet_headers_tls_config_proto_init() {\n\tif File_transport_internet_headers_tls_config_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_transport_internet_headers_tls_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*PacketConfig); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_transport_internet_headers_tls_config_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   1,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_transport_internet_headers_tls_config_proto_goTypes,\n\t\tDependencyIndexes: file_transport_internet_headers_tls_config_proto_depIdxs,\n\t\tMessageInfos:      file_transport_internet_headers_tls_config_proto_msgTypes,\n\t}.Build()\n\tFile_transport_internet_headers_tls_config_proto = out.File\n\tfile_transport_internet_headers_tls_config_proto_rawDesc = nil\n\tfile_transport_internet_headers_tls_config_proto_goTypes = nil\n\tfile_transport_internet_headers_tls_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "transport/internet/headers/tls/config.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.transport.internet.headers.tls;\noption csharp_namespace = \"V2Ray.Core.Transport.Internet.Headers.Tls\";\noption go_package = \"v2ray.com/core/transport/internet/headers/tls\";\noption java_package = \"com.v2ray.core.transport.internet.headers.tls\";\noption java_multiple_files = true;\n\nmessage PacketConfig {}\n"
  },
  {
    "path": "transport/internet/headers/tls/dtls.go",
    "content": "package tls\n\nimport (\n\t\"context\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/dice\"\n)\n\n// DTLS writes header as DTLS. See https://tools.ietf.org/html/rfc6347\ntype DTLS struct {\n\tepoch    uint16\n\tlength   uint16\n\tsequence uint32\n}\n\n// Size implements PacketHeader.\nfunc (*DTLS) Size() int32 {\n\treturn 1 + 2 + 2 + 6 + 2\n}\n\n// Serialize implements PacketHeader.\nfunc (d *DTLS) Serialize(b []byte) {\n\tb[0] = 23 // application data\n\tb[1] = 254\n\tb[2] = 253\n\tb[3] = byte(d.epoch >> 8)\n\tb[4] = byte(d.epoch)\n\tb[5] = 0\n\tb[6] = 0\n\tb[7] = byte(d.sequence >> 24)\n\tb[8] = byte(d.sequence >> 16)\n\tb[9] = byte(d.sequence >> 8)\n\tb[10] = byte(d.sequence)\n\td.sequence++\n\tb[11] = byte(d.length >> 8)\n\tb[12] = byte(d.length)\n\td.length += 17\n\tif d.length > 100 {\n\t\td.length -= 50\n\t}\n}\n\n// New creates a new UTP header for the given config.\nfunc New(ctx context.Context, config interface{}) (interface{}, error) {\n\treturn &DTLS{\n\t\tepoch:    dice.RollUint16(),\n\t\tsequence: 0,\n\t\tlength:   17,\n\t}, nil\n}\n\nfunc init() {\n\tcommon.Must(common.RegisterConfig((*PacketConfig)(nil), New))\n}\n"
  },
  {
    "path": "transport/internet/headers/tls/dtls_test.go",
    "content": "package tls_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t. \"v2ray.com/core/transport/internet/headers/tls\"\n)\n\nfunc TestDTLSWrite(t *testing.T) {\n\tcontent := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g'}\n\tdtlsRaw, err := New(context.Background(), &PacketConfig{})\n\tcommon.Must(err)\n\n\tdtls := dtlsRaw.(*DTLS)\n\n\tpayload := buf.New()\n\tdtls.Serialize(payload.Extend(dtls.Size()))\n\tpayload.Write(content)\n\n\tif payload.Len() != int32(len(content))+dtls.Size() {\n\t\tt.Error(\"payload len: \", payload.Len(), \" want \", int32(len(content))+dtls.Size())\n\t}\n}\n"
  },
  {
    "path": "transport/internet/headers/utp/config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: transport/internet/headers/utp/config.proto\n\npackage utp\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype Config struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tVersion uint32 `protobuf:\"varint,1,opt,name=version,proto3\" json:\"version,omitempty\"`\n}\n\nfunc (x *Config) Reset() {\n\t*x = Config{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_transport_internet_headers_utp_config_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Config) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Config) ProtoMessage() {}\n\nfunc (x *Config) ProtoReflect() protoreflect.Message {\n\tmi := &file_transport_internet_headers_utp_config_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Config.ProtoReflect.Descriptor instead.\nfunc (*Config) Descriptor() ([]byte, []int) {\n\treturn file_transport_internet_headers_utp_config_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *Config) GetVersion() uint32 {\n\tif x != nil {\n\t\treturn x.Version\n\t}\n\treturn 0\n}\n\nvar File_transport_internet_headers_utp_config_proto protoreflect.FileDescriptor\n\nvar file_transport_internet_headers_utp_config_proto_rawDesc = []byte{\n\t0x0a, 0x2b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65,\n\t0x72, 0x6e, 0x65, 0x74, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2f, 0x75, 0x74, 0x70,\n\t0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x29, 0x76,\n\t0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70,\n\t0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x68, 0x65, 0x61,\n\t0x64, 0x65, 0x72, 0x73, 0x2e, 0x75, 0x74, 0x70, 0x22, 0x22, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66,\n\t0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20,\n\t0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x8c, 0x01, 0x0a,\n\t0x2d, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,\n\t0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,\n\t0x65, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x75, 0x74, 0x70, 0x50, 0x01,\n\t0x5a, 0x2d, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65,\n\t0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72,\n\t0x6e, 0x65, 0x74, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2f, 0x75, 0x74, 0x70, 0xaa,\n\t0x02, 0x29, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61,\n\t0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e,\n\t0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x55, 0x74, 0x70, 0x62, 0x06, 0x70, 0x72, 0x6f,\n\t0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_transport_internet_headers_utp_config_proto_rawDescOnce sync.Once\n\tfile_transport_internet_headers_utp_config_proto_rawDescData = file_transport_internet_headers_utp_config_proto_rawDesc\n)\n\nfunc file_transport_internet_headers_utp_config_proto_rawDescGZIP() []byte {\n\tfile_transport_internet_headers_utp_config_proto_rawDescOnce.Do(func() {\n\t\tfile_transport_internet_headers_utp_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_transport_internet_headers_utp_config_proto_rawDescData)\n\t})\n\treturn file_transport_internet_headers_utp_config_proto_rawDescData\n}\n\nvar file_transport_internet_headers_utp_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)\nvar file_transport_internet_headers_utp_config_proto_goTypes = []interface{}{\n\t(*Config)(nil), // 0: v2ray.core.transport.internet.headers.utp.Config\n}\nvar file_transport_internet_headers_utp_config_proto_depIdxs = []int32{\n\t0, // [0:0] is the sub-list for method output_type\n\t0, // [0:0] is the sub-list for method input_type\n\t0, // [0:0] is the sub-list for extension type_name\n\t0, // [0:0] is the sub-list for extension extendee\n\t0, // [0:0] is the sub-list for field type_name\n}\n\nfunc init() { file_transport_internet_headers_utp_config_proto_init() }\nfunc file_transport_internet_headers_utp_config_proto_init() {\n\tif File_transport_internet_headers_utp_config_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_transport_internet_headers_utp_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Config); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_transport_internet_headers_utp_config_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   1,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_transport_internet_headers_utp_config_proto_goTypes,\n\t\tDependencyIndexes: file_transport_internet_headers_utp_config_proto_depIdxs,\n\t\tMessageInfos:      file_transport_internet_headers_utp_config_proto_msgTypes,\n\t}.Build()\n\tFile_transport_internet_headers_utp_config_proto = out.File\n\tfile_transport_internet_headers_utp_config_proto_rawDesc = nil\n\tfile_transport_internet_headers_utp_config_proto_goTypes = nil\n\tfile_transport_internet_headers_utp_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "transport/internet/headers/utp/config.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.transport.internet.headers.utp;\noption csharp_namespace = \"V2Ray.Core.Transport.Internet.Headers.Utp\";\noption go_package = \"v2ray.com/core/transport/internet/headers/utp\";\noption java_package = \"com.v2ray.core.transport.internet.headers.utp\";\noption java_multiple_files = true;\n\nmessage Config {\n  uint32 version = 1;\n}\n"
  },
  {
    "path": "transport/internet/headers/utp/utp.go",
    "content": "package utp\n\nimport (\n\t\"context\"\n\t\"encoding/binary\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/dice\"\n)\n\ntype UTP struct {\n\theader       byte\n\textension    byte\n\tconnectionId uint16\n}\n\nfunc (*UTP) Size() int32 {\n\treturn 4\n}\n\n// Serialize implements PacketHeader.\nfunc (u *UTP) Serialize(b []byte) {\n\tbinary.BigEndian.PutUint16(b, u.connectionId)\n\tb[2] = u.header\n\tb[3] = u.extension\n}\n\n// New creates a new UTP header for the given config.\nfunc New(ctx context.Context, config interface{}) (interface{}, error) {\n\treturn &UTP{\n\t\theader:       1,\n\t\textension:    0,\n\t\tconnectionId: dice.RollUint16(),\n\t}, nil\n}\n\nfunc init() {\n\tcommon.Must(common.RegisterConfig((*Config)(nil), New))\n}\n"
  },
  {
    "path": "transport/internet/headers/utp/utp_test.go",
    "content": "package utp_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t. \"v2ray.com/core/transport/internet/headers/utp\"\n)\n\nfunc TestUTPWrite(t *testing.T) {\n\tcontent := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g'}\n\tutpRaw, err := New(context.Background(), &Config{})\n\tcommon.Must(err)\n\n\tutp := utpRaw.(*UTP)\n\n\tpayload := buf.New()\n\tutp.Serialize(payload.Extend(utp.Size()))\n\tpayload.Write(content)\n\n\tif payload.Len() != int32(len(content))+utp.Size() {\n\t\tt.Error(\"unexpected payload length: \", payload.Len())\n\t}\n}\n"
  },
  {
    "path": "transport/internet/headers/wechat/config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: transport/internet/headers/wechat/config.proto\n\npackage wechat\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype VideoConfig struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *VideoConfig) Reset() {\n\t*x = VideoConfig{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_transport_internet_headers_wechat_config_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *VideoConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*VideoConfig) ProtoMessage() {}\n\nfunc (x *VideoConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_transport_internet_headers_wechat_config_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use VideoConfig.ProtoReflect.Descriptor instead.\nfunc (*VideoConfig) Descriptor() ([]byte, []int) {\n\treturn file_transport_internet_headers_wechat_config_proto_rawDescGZIP(), []int{0}\n}\n\nvar File_transport_internet_headers_wechat_config_proto protoreflect.FileDescriptor\n\nvar file_transport_internet_headers_wechat_config_proto_rawDesc = []byte{\n\t0x0a, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65,\n\t0x72, 0x6e, 0x65, 0x74, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2f, 0x77, 0x65, 0x63,\n\t0x68, 0x61, 0x74, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,\n\t0x12, 0x2c, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61,\n\t0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e,\n\t0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x77, 0x65, 0x63, 0x68, 0x61, 0x74, 0x22, 0x0d,\n\t0x0a, 0x0b, 0x56, 0x69, 0x64, 0x65, 0x6f, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x95, 0x01,\n\t0x0a, 0x30, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,\n\t0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72,\n\t0x6e, 0x65, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x77, 0x65, 0x63, 0x68,\n\t0x61, 0x74, 0x50, 0x01, 0x5a, 0x30, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,\n\t0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69,\n\t0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2f,\n\t0x77, 0x65, 0x63, 0x68, 0x61, 0x74, 0xaa, 0x02, 0x2c, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43,\n\t0x6f, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e,\n\t0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x57,\n\t0x65, 0x63, 0x68, 0x61, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_transport_internet_headers_wechat_config_proto_rawDescOnce sync.Once\n\tfile_transport_internet_headers_wechat_config_proto_rawDescData = file_transport_internet_headers_wechat_config_proto_rawDesc\n)\n\nfunc file_transport_internet_headers_wechat_config_proto_rawDescGZIP() []byte {\n\tfile_transport_internet_headers_wechat_config_proto_rawDescOnce.Do(func() {\n\t\tfile_transport_internet_headers_wechat_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_transport_internet_headers_wechat_config_proto_rawDescData)\n\t})\n\treturn file_transport_internet_headers_wechat_config_proto_rawDescData\n}\n\nvar file_transport_internet_headers_wechat_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)\nvar file_transport_internet_headers_wechat_config_proto_goTypes = []interface{}{\n\t(*VideoConfig)(nil), // 0: v2ray.core.transport.internet.headers.wechat.VideoConfig\n}\nvar file_transport_internet_headers_wechat_config_proto_depIdxs = []int32{\n\t0, // [0:0] is the sub-list for method output_type\n\t0, // [0:0] is the sub-list for method input_type\n\t0, // [0:0] is the sub-list for extension type_name\n\t0, // [0:0] is the sub-list for extension extendee\n\t0, // [0:0] is the sub-list for field type_name\n}\n\nfunc init() { file_transport_internet_headers_wechat_config_proto_init() }\nfunc file_transport_internet_headers_wechat_config_proto_init() {\n\tif File_transport_internet_headers_wechat_config_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_transport_internet_headers_wechat_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*VideoConfig); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_transport_internet_headers_wechat_config_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   1,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_transport_internet_headers_wechat_config_proto_goTypes,\n\t\tDependencyIndexes: file_transport_internet_headers_wechat_config_proto_depIdxs,\n\t\tMessageInfos:      file_transport_internet_headers_wechat_config_proto_msgTypes,\n\t}.Build()\n\tFile_transport_internet_headers_wechat_config_proto = out.File\n\tfile_transport_internet_headers_wechat_config_proto_rawDesc = nil\n\tfile_transport_internet_headers_wechat_config_proto_goTypes = nil\n\tfile_transport_internet_headers_wechat_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "transport/internet/headers/wechat/config.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.transport.internet.headers.wechat;\noption csharp_namespace = \"V2Ray.Core.Transport.Internet.Headers.Wechat\";\noption go_package = \"v2ray.com/core/transport/internet/headers/wechat\";\noption java_package = \"com.v2ray.core.transport.internet.headers.wechat\";\noption java_multiple_files = true;\n\nmessage VideoConfig {}\n"
  },
  {
    "path": "transport/internet/headers/wechat/wechat.go",
    "content": "package wechat\n\nimport (\n\t\"context\"\n\t\"encoding/binary\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/dice\"\n)\n\ntype VideoChat struct {\n\tsn uint32\n}\n\nfunc (vc *VideoChat) Size() int32 {\n\treturn 13\n}\n\n// Serialize implements PacketHeader.\nfunc (vc *VideoChat) Serialize(b []byte) {\n\tvc.sn++\n\tb[0] = 0xa1\n\tb[1] = 0x08\n\tbinary.BigEndian.PutUint32(b[2:], vc.sn) // b[2:6]\n\tb[6] = 0x00\n\tb[7] = 0x10\n\tb[8] = 0x11\n\tb[9] = 0x18\n\tb[10] = 0x30\n\tb[11] = 0x22\n\tb[12] = 0x30\n}\n\n// NewVideoChat returns a new VideoChat instance based on given config.\nfunc NewVideoChat(ctx context.Context, config interface{}) (interface{}, error) {\n\treturn &VideoChat{\n\t\tsn: uint32(dice.RollUint16()),\n\t}, nil\n}\n\nfunc init() {\n\tcommon.Must(common.RegisterConfig((*VideoConfig)(nil), NewVideoChat))\n}\n"
  },
  {
    "path": "transport/internet/headers/wechat/wechat_test.go",
    "content": "package wechat_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t. \"v2ray.com/core/transport/internet/headers/wechat\"\n)\n\nfunc TestUTPWrite(t *testing.T) {\n\tvideoRaw, err := NewVideoChat(context.Background(), &VideoConfig{})\n\tcommon.Must(err)\n\n\tvideo := videoRaw.(*VideoChat)\n\n\tpayload := buf.New()\n\tvideo.Serialize(payload.Extend(video.Size()))\n\n\tif payload.Len() != video.Size() {\n\t\tt.Error(\"expected payload size \", video.Size(), \" but got \", payload.Len())\n\t}\n}\n"
  },
  {
    "path": "transport/internet/headers/wireguard/config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: transport/internet/headers/wireguard/config.proto\n\npackage wireguard\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype WireguardConfig struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *WireguardConfig) Reset() {\n\t*x = WireguardConfig{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_transport_internet_headers_wireguard_config_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *WireguardConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*WireguardConfig) ProtoMessage() {}\n\nfunc (x *WireguardConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_transport_internet_headers_wireguard_config_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use WireguardConfig.ProtoReflect.Descriptor instead.\nfunc (*WireguardConfig) Descriptor() ([]byte, []int) {\n\treturn file_transport_internet_headers_wireguard_config_proto_rawDescGZIP(), []int{0}\n}\n\nvar File_transport_internet_headers_wireguard_config_proto protoreflect.FileDescriptor\n\nvar file_transport_internet_headers_wireguard_config_proto_rawDesc = []byte{\n\t0x0a, 0x31, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65,\n\t0x72, 0x6e, 0x65, 0x74, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2f, 0x77, 0x69, 0x72,\n\t0x65, 0x67, 0x75, 0x61, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72,\n\t0x6f, 0x74, 0x6f, 0x12, 0x2f, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,\n\t0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,\n\t0x65, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x77, 0x69, 0x72, 0x65, 0x67,\n\t0x75, 0x61, 0x72, 0x64, 0x22, 0x11, 0x0a, 0x0f, 0x57, 0x69, 0x72, 0x65, 0x67, 0x75, 0x61, 0x72,\n\t0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x9e, 0x01, 0x0a, 0x33, 0x63, 0x6f, 0x6d, 0x2e,\n\t0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73,\n\t0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x68, 0x65,\n\t0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x77, 0x69, 0x72, 0x65, 0x67, 0x75, 0x61, 0x72, 0x64, 0x50,\n\t0x01, 0x5a, 0x33, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72,\n\t0x65, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65,\n\t0x72, 0x6e, 0x65, 0x74, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2f, 0x77, 0x69, 0x72,\n\t0x65, 0x67, 0x75, 0x61, 0x72, 0x64, 0xaa, 0x02, 0x2f, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43,\n\t0x6f, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e,\n\t0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x57,\n\t0x69, 0x72, 0x65, 0x67, 0x75, 0x61, 0x72, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_transport_internet_headers_wireguard_config_proto_rawDescOnce sync.Once\n\tfile_transport_internet_headers_wireguard_config_proto_rawDescData = file_transport_internet_headers_wireguard_config_proto_rawDesc\n)\n\nfunc file_transport_internet_headers_wireguard_config_proto_rawDescGZIP() []byte {\n\tfile_transport_internet_headers_wireguard_config_proto_rawDescOnce.Do(func() {\n\t\tfile_transport_internet_headers_wireguard_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_transport_internet_headers_wireguard_config_proto_rawDescData)\n\t})\n\treturn file_transport_internet_headers_wireguard_config_proto_rawDescData\n}\n\nvar file_transport_internet_headers_wireguard_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)\nvar file_transport_internet_headers_wireguard_config_proto_goTypes = []interface{}{\n\t(*WireguardConfig)(nil), // 0: v2ray.core.transport.internet.headers.wireguard.WireguardConfig\n}\nvar file_transport_internet_headers_wireguard_config_proto_depIdxs = []int32{\n\t0, // [0:0] is the sub-list for method output_type\n\t0, // [0:0] is the sub-list for method input_type\n\t0, // [0:0] is the sub-list for extension type_name\n\t0, // [0:0] is the sub-list for extension extendee\n\t0, // [0:0] is the sub-list for field type_name\n}\n\nfunc init() { file_transport_internet_headers_wireguard_config_proto_init() }\nfunc file_transport_internet_headers_wireguard_config_proto_init() {\n\tif File_transport_internet_headers_wireguard_config_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_transport_internet_headers_wireguard_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*WireguardConfig); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_transport_internet_headers_wireguard_config_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   1,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_transport_internet_headers_wireguard_config_proto_goTypes,\n\t\tDependencyIndexes: file_transport_internet_headers_wireguard_config_proto_depIdxs,\n\t\tMessageInfos:      file_transport_internet_headers_wireguard_config_proto_msgTypes,\n\t}.Build()\n\tFile_transport_internet_headers_wireguard_config_proto = out.File\n\tfile_transport_internet_headers_wireguard_config_proto_rawDesc = nil\n\tfile_transport_internet_headers_wireguard_config_proto_goTypes = nil\n\tfile_transport_internet_headers_wireguard_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "transport/internet/headers/wireguard/config.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.transport.internet.headers.wireguard;\noption csharp_namespace = \"V2Ray.Core.Transport.Internet.Headers.Wireguard\";\noption go_package = \"v2ray.com/core/transport/internet/headers/wireguard\";\noption java_package = \"com.v2ray.core.transport.internet.headers.wireguard\";\noption java_multiple_files = true;\n\nmessage WireguardConfig {}\n"
  },
  {
    "path": "transport/internet/headers/wireguard/wireguard.go",
    "content": "package wireguard\n\nimport (\n\t\"context\"\n\n\t\"v2ray.com/core/common\"\n)\n\ntype Wireguard struct{}\n\nfunc (Wireguard) Size() int32 {\n\treturn 4\n}\n\n// Serialize implements PacketHeader.\nfunc (Wireguard) Serialize(b []byte) {\n\tb[0] = 0x04\n\tb[1] = 0x00\n\tb[2] = 0x00\n\tb[3] = 0x00\n}\n\n// NewWireguard returns a new VideoChat instance based on given config.\nfunc NewWireguard(ctx context.Context, config interface{}) (interface{}, error) {\n\treturn Wireguard{}, nil\n}\n\nfunc init() {\n\tcommon.Must(common.RegisterConfig((*WireguardConfig)(nil), NewWireguard))\n}\n"
  },
  {
    "path": "transport/internet/http/config.go",
    "content": "// +build !confonly\n\npackage http\n\nimport (\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/dice\"\n\t\"v2ray.com/core/transport/internet\"\n)\n\nconst protocolName = \"http\"\n\nfunc (c *Config) getHosts() []string {\n\tif len(c.Host) == 0 {\n\t\treturn []string{\"www.example.com\"}\n\t}\n\treturn c.Host\n}\n\nfunc (c *Config) isValidHost(host string) bool {\n\thosts := c.getHosts()\n\tfor _, h := range hosts {\n\t\tif h == host {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc (c *Config) getRandomHost() string {\n\thosts := c.getHosts()\n\treturn hosts[dice.Roll(len(hosts))]\n}\n\nfunc (c *Config) getNormalizedPath() string {\n\tif c.Path == \"\" {\n\t\treturn \"/\"\n\t}\n\tif c.Path[0] != '/' {\n\t\treturn \"/\" + c.Path\n\t}\n\treturn c.Path\n}\n\nfunc init() {\n\tcommon.Must(internet.RegisterProtocolConfigCreator(protocolName, func() interface{} {\n\t\treturn new(Config)\n\t}))\n}\n"
  },
  {
    "path": "transport/internet/http/config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: transport/internet/http/config.proto\n\npackage http\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype Config struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tHost []string `protobuf:\"bytes,1,rep,name=host,proto3\" json:\"host,omitempty\"`\n\tPath string   `protobuf:\"bytes,2,opt,name=path,proto3\" json:\"path,omitempty\"`\n}\n\nfunc (x *Config) Reset() {\n\t*x = Config{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_transport_internet_http_config_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Config) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Config) ProtoMessage() {}\n\nfunc (x *Config) ProtoReflect() protoreflect.Message {\n\tmi := &file_transport_internet_http_config_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Config.ProtoReflect.Descriptor instead.\nfunc (*Config) Descriptor() ([]byte, []int) {\n\treturn file_transport_internet_http_config_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *Config) GetHost() []string {\n\tif x != nil {\n\t\treturn x.Host\n\t}\n\treturn nil\n}\n\nfunc (x *Config) GetPath() string {\n\tif x != nil {\n\t\treturn x.Path\n\t}\n\treturn \"\"\n}\n\nvar File_transport_internet_http_config_proto protoreflect.FileDescriptor\n\nvar file_transport_internet_http_config_proto_rawDesc = []byte{\n\t0x0a, 0x24, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65,\n\t0x72, 0x6e, 0x65, 0x74, 0x2f, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,\n\t0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x22, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,\n\t0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74,\n\t0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x22, 0x30, 0x0a, 0x06, 0x43, 0x6f,\n\t0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x01, 0x20, 0x03,\n\t0x28, 0x09, 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68,\n\t0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x42, 0x77, 0x0a, 0x26,\n\t0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74,\n\t0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,\n\t0x74, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x50, 0x01, 0x5a, 0x26, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,\n\t0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f,\n\t0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x68, 0x74, 0x74, 0x70,\n\t0xaa, 0x02, 0x22, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x54, 0x72,\n\t0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74,\n\t0x2e, 0x48, 0x74, 0x74, 0x70, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_transport_internet_http_config_proto_rawDescOnce sync.Once\n\tfile_transport_internet_http_config_proto_rawDescData = file_transport_internet_http_config_proto_rawDesc\n)\n\nfunc file_transport_internet_http_config_proto_rawDescGZIP() []byte {\n\tfile_transport_internet_http_config_proto_rawDescOnce.Do(func() {\n\t\tfile_transport_internet_http_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_transport_internet_http_config_proto_rawDescData)\n\t})\n\treturn file_transport_internet_http_config_proto_rawDescData\n}\n\nvar file_transport_internet_http_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)\nvar file_transport_internet_http_config_proto_goTypes = []interface{}{\n\t(*Config)(nil), // 0: v2ray.core.transport.internet.http.Config\n}\nvar file_transport_internet_http_config_proto_depIdxs = []int32{\n\t0, // [0:0] is the sub-list for method output_type\n\t0, // [0:0] is the sub-list for method input_type\n\t0, // [0:0] is the sub-list for extension type_name\n\t0, // [0:0] is the sub-list for extension extendee\n\t0, // [0:0] is the sub-list for field type_name\n}\n\nfunc init() { file_transport_internet_http_config_proto_init() }\nfunc file_transport_internet_http_config_proto_init() {\n\tif File_transport_internet_http_config_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_transport_internet_http_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Config); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_transport_internet_http_config_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   1,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_transport_internet_http_config_proto_goTypes,\n\t\tDependencyIndexes: file_transport_internet_http_config_proto_depIdxs,\n\t\tMessageInfos:      file_transport_internet_http_config_proto_msgTypes,\n\t}.Build()\n\tFile_transport_internet_http_config_proto = out.File\n\tfile_transport_internet_http_config_proto_rawDesc = nil\n\tfile_transport_internet_http_config_proto_goTypes = nil\n\tfile_transport_internet_http_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "transport/internet/http/config.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.transport.internet.http;\noption csharp_namespace = \"V2Ray.Core.Transport.Internet.Http\";\noption go_package = \"v2ray.com/core/transport/internet/http\";\noption java_package = \"com.v2ray.core.transport.internet.http\";\noption java_multiple_files = true;\n\nmessage Config {\n  repeated string host = 1;\n  string path = 2;\n}\n"
  },
  {
    "path": "transport/internet/http/dialer.go",
    "content": "// +build !confonly\n\npackage http\n\nimport (\n\t\"context\"\n\tgotls \"crypto/tls\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"sync\"\n\n\t\"golang.org/x/net/http2\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/transport/internet\"\n\t\"v2ray.com/core/transport/internet/tls\"\n\t\"v2ray.com/core/transport/pipe\"\n)\n\nvar (\n\tglobalDialerMap    map[net.Destination]*http.Client\n\tglobalDialerAccess sync.Mutex\n)\n\nfunc getHTTPClient(ctx context.Context, dest net.Destination, tlsSettings *tls.Config) (*http.Client, error) {\n\tglobalDialerAccess.Lock()\n\tdefer globalDialerAccess.Unlock()\n\n\tif globalDialerMap == nil {\n\t\tglobalDialerMap = make(map[net.Destination]*http.Client)\n\t}\n\n\tif client, found := globalDialerMap[dest]; found {\n\t\treturn client, nil\n\t}\n\n\ttransport := &http2.Transport{\n\t\tDialTLS: func(network string, addr string, tlsConfig *gotls.Config) (net.Conn, error) {\n\t\t\trawHost, rawPort, err := net.SplitHostPort(addr)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tif len(rawPort) == 0 {\n\t\t\t\trawPort = \"443\"\n\t\t\t}\n\t\t\tport, err := net.PortFromString(rawPort)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\taddress := net.ParseAddress(rawHost)\n\n\t\t\tpconn, err := internet.DialSystem(context.Background(), net.TCPDestination(address, port), nil)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tcn := gotls.Client(pconn, tlsConfig)\n\t\t\tif err := cn.Handshake(); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tif !tlsConfig.InsecureSkipVerify {\n\t\t\t\tif err := cn.VerifyHostname(tlsConfig.ServerName); err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t}\n\t\t\tstate := cn.ConnectionState()\n\t\t\tif p := state.NegotiatedProtocol; p != http2.NextProtoTLS {\n\t\t\t\treturn nil, newError(\"http2: unexpected ALPN protocol \" + p + \"; want q\" + http2.NextProtoTLS).AtError()\n\t\t\t}\n\t\t\tif !state.NegotiatedProtocolIsMutual {\n\t\t\t\treturn nil, newError(\"http2: could not negotiate protocol mutually\").AtError()\n\t\t\t}\n\t\t\treturn cn, nil\n\t\t},\n\t\tTLSClientConfig: tlsSettings.GetTLSConfig(tls.WithDestination(dest)),\n\t}\n\n\tclient := &http.Client{\n\t\tTransport: transport,\n\t}\n\n\tglobalDialerMap[dest] = client\n\treturn client, nil\n}\n\n// Dial dials a new TCP connection to the given destination.\nfunc Dial(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (internet.Connection, error) {\n\thttpSettings := streamSettings.ProtocolSettings.(*Config)\n\ttlsConfig := tls.ConfigFromStreamSettings(streamSettings)\n\tif tlsConfig == nil {\n\t\treturn nil, newError(\"TLS must be enabled for http transport.\").AtWarning()\n\t}\n\tclient, err := getHTTPClient(ctx, dest, tlsConfig)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\topts := pipe.OptionsFromContext(ctx)\n\tpreader, pwriter := pipe.New(opts...)\n\tbreader := &buf.BufferedReader{Reader: preader}\n\trequest := &http.Request{\n\t\tMethod: \"PUT\",\n\t\tHost:   httpSettings.getRandomHost(),\n\t\tBody:   breader,\n\t\tURL: &url.URL{\n\t\t\tScheme: \"https\",\n\t\t\tHost:   dest.NetAddr(),\n\t\t\tPath:   httpSettings.getNormalizedPath(),\n\t\t},\n\t\tProto:      \"HTTP/2\",\n\t\tProtoMajor: 2,\n\t\tProtoMinor: 0,\n\t\tHeader:     make(http.Header),\n\t}\n\t// Disable any compression method from server.\n\trequest.Header.Set(\"Accept-Encoding\", \"identity\")\n\n\tresponse, err := client.Do(request)\n\tif err != nil {\n\t\treturn nil, newError(\"failed to dial to \", dest).Base(err).AtWarning()\n\t}\n\tif response.StatusCode != 200 {\n\t\treturn nil, newError(\"unexpected status\", response.StatusCode).AtWarning()\n\t}\n\n\tbwriter := buf.NewBufferedWriter(pwriter)\n\tcommon.Must(bwriter.SetBuffered(false))\n\treturn net.NewConnection(\n\t\tnet.ConnectionOutput(response.Body),\n\t\tnet.ConnectionInput(bwriter),\n\t\tnet.ConnectionOnClose(common.ChainedClosable{breader, bwriter, response.Body}),\n\t), nil\n}\n\nfunc init() {\n\tcommon.Must(internet.RegisterTransportDialer(protocolName, Dial))\n}\n"
  },
  {
    "path": "transport/internet/http/errors.generated.go",
    "content": "package http\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "transport/internet/http/http.go",
    "content": "package http\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n"
  },
  {
    "path": "transport/internet/http/http_test.go",
    "content": "package http_test\n\nimport (\n\t\"context\"\n\t\"crypto/rand\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol/tls/cert\"\n\t\"v2ray.com/core/testing/servers/tcp\"\n\t\"v2ray.com/core/transport/internet\"\n\t. \"v2ray.com/core/transport/internet/http\"\n\t\"v2ray.com/core/transport/internet/tls\"\n)\n\nfunc TestHTTPConnection(t *testing.T) {\n\tport := tcp.PickPort()\n\n\tlistener, err := Listen(context.Background(), net.LocalHostIP, port, &internet.MemoryStreamConfig{\n\t\tProtocolName:     \"http\",\n\t\tProtocolSettings: &Config{},\n\t\tSecurityType:     \"tls\",\n\t\tSecuritySettings: &tls.Config{\n\t\t\tCertificate: []*tls.Certificate{tls.ParseCertificate(cert.MustGenerate(nil, cert.CommonName(\"www.v2ray.com\")))},\n\t\t},\n\t}, func(conn internet.Connection) {\n\t\tgo func() {\n\t\t\tdefer conn.Close()\n\n\t\t\tb := buf.New()\n\t\t\tdefer b.Release()\n\n\t\t\tfor {\n\t\t\t\tif _, err := b.ReadFrom(conn); err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\t_, err := conn.Write(b.Bytes())\n\t\t\t\tcommon.Must(err)\n\t\t\t}\n\t\t}()\n\t})\n\tcommon.Must(err)\n\n\tdefer listener.Close()\n\n\ttime.Sleep(time.Second)\n\n\tdctx := context.Background()\n\tconn, err := Dial(dctx, net.TCPDestination(net.LocalHostIP, port), &internet.MemoryStreamConfig{\n\t\tProtocolName:     \"http\",\n\t\tProtocolSettings: &Config{},\n\t\tSecurityType:     \"tls\",\n\t\tSecuritySettings: &tls.Config{\n\t\t\tServerName:    \"www.v2ray.com\",\n\t\t\tAllowInsecure: true,\n\t\t},\n\t})\n\tcommon.Must(err)\n\tdefer conn.Close()\n\n\tconst N = 1024\n\tb1 := make([]byte, N)\n\tcommon.Must2(rand.Read(b1))\n\tb2 := buf.New()\n\n\tnBytes, err := conn.Write(b1)\n\tcommon.Must(err)\n\tif nBytes != N {\n\t\tt.Error(\"write: \", nBytes)\n\t}\n\n\tb2.Clear()\n\tcommon.Must2(b2.ReadFullFrom(conn, N))\n\tif r := cmp.Diff(b2.Bytes(), b1); r != \"\" {\n\t\tt.Error(r)\n\t}\n\n\tnBytes, err = conn.Write(b1)\n\tcommon.Must(err)\n\tif nBytes != N {\n\t\tt.Error(\"write: \", nBytes)\n\t}\n\n\tb2.Clear()\n\tcommon.Must2(b2.ReadFullFrom(conn, N))\n\tif r := cmp.Diff(b2.Bytes(), b1); r != \"\" {\n\t\tt.Error(r)\n\t}\n}\n"
  },
  {
    "path": "transport/internet/http/hub.go",
    "content": "// +build !confonly\n\npackage http\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n\t\"time\"\n\n\t\"golang.org/x/net/http2\"\n\t\"golang.org/x/net/http2/h2c\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/net\"\n\thttp_proto \"v2ray.com/core/common/protocol/http\"\n\t\"v2ray.com/core/common/serial\"\n\t\"v2ray.com/core/common/session\"\n\t\"v2ray.com/core/common/signal/done\"\n\t\"v2ray.com/core/transport/internet\"\n\t\"v2ray.com/core/transport/internet/tls\"\n)\n\ntype Listener struct {\n\tserver  *http.Server\n\thandler internet.ConnHandler\n\tlocal   net.Addr\n\tconfig  *Config\n}\n\nfunc (l *Listener) Addr() net.Addr {\n\treturn l.local\n}\n\nfunc (l *Listener) Close() error {\n\treturn l.server.Close()\n}\n\ntype flushWriter struct {\n\tw io.Writer\n\td *done.Instance\n}\n\nfunc (fw flushWriter) Write(p []byte) (n int, err error) {\n\tif fw.d.Done() {\n\t\treturn 0, io.ErrClosedPipe\n\t}\n\n\tn, err = fw.w.Write(p)\n\tif f, ok := fw.w.(http.Flusher); ok {\n\t\tf.Flush()\n\t}\n\treturn\n}\n\nfunc (l *Listener) ServeHTTP(writer http.ResponseWriter, request *http.Request) {\n\thost := request.Host\n\tif !l.config.isValidHost(host) {\n\t\twriter.WriteHeader(404)\n\t\treturn\n\t}\n\tpath := l.config.getNormalizedPath()\n\tif !strings.HasPrefix(request.URL.Path, path) {\n\t\twriter.WriteHeader(404)\n\t\treturn\n\t}\n\n\twriter.Header().Set(\"Cache-Control\", \"no-store\")\n\twriter.WriteHeader(200)\n\tif f, ok := writer.(http.Flusher); ok {\n\t\tf.Flush()\n\t}\n\n\tremoteAddr := l.Addr()\n\tdest, err := net.ParseDestination(request.RemoteAddr)\n\tif err != nil {\n\t\tnewError(\"failed to parse request remote addr: \", request.RemoteAddr).Base(err).WriteToLog()\n\t} else {\n\t\tremoteAddr = &net.TCPAddr{\n\t\t\tIP:   dest.Address.IP(),\n\t\t\tPort: int(dest.Port),\n\t\t}\n\t}\n\n\tforwardedAddrs := http_proto.ParseXForwardedFor(request.Header)\n\tif len(forwardedAddrs) > 0 && forwardedAddrs[0].Family().IsIP() {\n\t\tremoteAddr.(*net.TCPAddr).IP = forwardedAddrs[0].IP()\n\t}\n\n\tdone := done.New()\n\tconn := net.NewConnection(\n\t\tnet.ConnectionOutput(request.Body),\n\t\tnet.ConnectionInput(flushWriter{w: writer, d: done}),\n\t\tnet.ConnectionOnClose(common.ChainedClosable{done, request.Body}),\n\t\tnet.ConnectionLocalAddr(l.Addr()),\n\t\tnet.ConnectionRemoteAddr(remoteAddr),\n\t)\n\tl.handler(conn)\n\t<-done.Wait()\n}\n\nfunc Listen(ctx context.Context, address net.Address, port net.Port, streamSettings *internet.MemoryStreamConfig, handler internet.ConnHandler) (internet.Listener, error) {\n\thttpSettings := streamSettings.ProtocolSettings.(*Config)\n\tlistener := &Listener{\n\t\thandler: handler,\n\t\tlocal: &net.TCPAddr{\n\t\t\tIP:   address.IP(),\n\t\t\tPort: int(port),\n\t\t},\n\t\tconfig: httpSettings,\n\t}\n\n\tvar server *http.Server\n\tconfig := tls.ConfigFromStreamSettings(streamSettings)\n\tif config == nil {\n\t\th2s := &http2.Server{}\n\n\t\tserver = &http.Server{\n\t\t\tAddr:              serial.Concat(address, \":\", port),\n\t\t\tHandler:           h2c.NewHandler(listener, h2s),\n\t\t\tReadHeaderTimeout: time.Second * 4,\n\t\t}\n\t} else {\n\t\tserver = &http.Server{\n\t\t\tAddr:              serial.Concat(address, \":\", port),\n\t\t\tTLSConfig:         config.GetTLSConfig(tls.WithNextProto(\"h2\")),\n\t\t\tHandler:           listener,\n\t\t\tReadHeaderTimeout: time.Second * 4,\n\t\t}\n\t}\n\n\tlistener.server = server\n\tgo func() {\n\t\ttcpListener, err := internet.ListenSystem(ctx, &net.TCPAddr{\n\t\t\tIP:   address.IP(),\n\t\t\tPort: int(port),\n\t\t}, streamSettings.SocketSettings)\n\t\tif err != nil {\n\t\t\tnewError(\"failed to listen on\", address, \":\", port).Base(err).WriteToLog(session.ExportIDToError(ctx))\n\t\t\treturn\n\t\t}\n\t\tif config == nil {\n\t\t\terr = server.Serve(tcpListener)\n\t\t\tif err != nil {\n\t\t\t\tnewError(\"stoping serving H2C\").Base(err).WriteToLog(session.ExportIDToError(ctx))\n\t\t\t}\n\t\t} else {\n\t\t\terr = server.ServeTLS(tcpListener, \"\", \"\")\n\t\t\tif err != nil {\n\t\t\t\tnewError(\"stoping serving TLS\").Base(err).WriteToLog(session.ExportIDToError(ctx))\n\t\t\t}\n\t\t}\n\t}()\n\n\treturn listener, nil\n}\n\nfunc init() {\n\tcommon.Must(internet.RegisterTransportListener(protocolName, Listen))\n}\n"
  },
  {
    "path": "transport/internet/internet.go",
    "content": "package internet\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n"
  },
  {
    "path": "transport/internet/kcp/config.go",
    "content": "// +build !confonly\n\npackage kcp\n\nimport (\n\t\"crypto/cipher\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/transport/internet\"\n)\n\nconst protocolName = \"mkcp\"\n\n// GetMTUValue returns the value of MTU settings.\nfunc (c *Config) GetMTUValue() uint32 {\n\tif c == nil || c.Mtu == nil {\n\t\treturn 1350\n\t}\n\treturn c.Mtu.Value\n}\n\n// GetTTIValue returns the value of TTI settings.\nfunc (c *Config) GetTTIValue() uint32 {\n\tif c == nil || c.Tti == nil {\n\t\treturn 50\n\t}\n\treturn c.Tti.Value\n}\n\n// GetUplinkCapacityValue returns the value of UplinkCapacity settings.\nfunc (c *Config) GetUplinkCapacityValue() uint32 {\n\tif c == nil || c.UplinkCapacity == nil {\n\t\treturn 5\n\t}\n\treturn c.UplinkCapacity.Value\n}\n\n// GetDownlinkCapacityValue returns the value of DownlinkCapacity settings.\nfunc (c *Config) GetDownlinkCapacityValue() uint32 {\n\tif c == nil || c.DownlinkCapacity == nil {\n\t\treturn 20\n\t}\n\treturn c.DownlinkCapacity.Value\n}\n\n// GetWriteBufferSize returns the size of WriterBuffer in bytes.\nfunc (c *Config) GetWriteBufferSize() uint32 {\n\tif c == nil || c.WriteBuffer == nil {\n\t\treturn 2 * 1024 * 1024\n\t}\n\treturn c.WriteBuffer.Size\n}\n\n// GetReadBufferSize returns the size of ReadBuffer in bytes.\nfunc (c *Config) GetReadBufferSize() uint32 {\n\tif c == nil || c.ReadBuffer == nil {\n\t\treturn 2 * 1024 * 1024\n\t}\n\treturn c.ReadBuffer.Size\n}\n\n// GetSecurity returns the security settings.\nfunc (c *Config) GetSecurity() (cipher.AEAD, error) {\n\tif c.Seed != nil {\n\t\treturn NewAEADAESGCMBasedOnSeed(c.Seed.Seed), nil\n\t}\n\treturn NewSimpleAuthenticator(), nil\n}\n\nfunc (c *Config) GetPackerHeader() (internet.PacketHeader, error) {\n\tif c.HeaderConfig != nil {\n\t\trawConfig, err := c.HeaderConfig.GetInstance()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\treturn internet.CreatePacketHeader(rawConfig)\n\t}\n\treturn nil, nil\n}\n\nfunc (c *Config) GetSendingInFlightSize() uint32 {\n\tsize := c.GetUplinkCapacityValue() * 1024 * 1024 / c.GetMTUValue() / (1000 / c.GetTTIValue())\n\tif size < 8 {\n\t\tsize = 8\n\t}\n\treturn size\n}\n\nfunc (c *Config) GetSendingBufferSize() uint32 {\n\treturn c.GetWriteBufferSize() / c.GetMTUValue()\n}\n\nfunc (c *Config) GetReceivingInFlightSize() uint32 {\n\tsize := c.GetDownlinkCapacityValue() * 1024 * 1024 / c.GetMTUValue() / (1000 / c.GetTTIValue())\n\tif size < 8 {\n\t\tsize = 8\n\t}\n\treturn size\n}\n\nfunc (c *Config) GetReceivingBufferSize() uint32 {\n\treturn c.GetReadBufferSize() / c.GetMTUValue()\n}\n\nfunc init() {\n\tcommon.Must(internet.RegisterProtocolConfigCreator(protocolName, func() interface{} {\n\t\treturn new(Config)\n\t}))\n}\n"
  },
  {
    "path": "transport/internet/kcp/config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: transport/internet/kcp/config.proto\n\npackage kcp\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n\tserial \"v2ray.com/core/common/serial\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\n// Maximum Transmission Unit, in bytes.\ntype MTU struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tValue uint32 `protobuf:\"varint,1,opt,name=value,proto3\" json:\"value,omitempty\"`\n}\n\nfunc (x *MTU) Reset() {\n\t*x = MTU{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_transport_internet_kcp_config_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *MTU) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*MTU) ProtoMessage() {}\n\nfunc (x *MTU) ProtoReflect() protoreflect.Message {\n\tmi := &file_transport_internet_kcp_config_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use MTU.ProtoReflect.Descriptor instead.\nfunc (*MTU) Descriptor() ([]byte, []int) {\n\treturn file_transport_internet_kcp_config_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *MTU) GetValue() uint32 {\n\tif x != nil {\n\t\treturn x.Value\n\t}\n\treturn 0\n}\n\n// Transmission Time Interview, in milli-sec.\ntype TTI struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tValue uint32 `protobuf:\"varint,1,opt,name=value,proto3\" json:\"value,omitempty\"`\n}\n\nfunc (x *TTI) Reset() {\n\t*x = TTI{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_transport_internet_kcp_config_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *TTI) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*TTI) ProtoMessage() {}\n\nfunc (x *TTI) ProtoReflect() protoreflect.Message {\n\tmi := &file_transport_internet_kcp_config_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use TTI.ProtoReflect.Descriptor instead.\nfunc (*TTI) Descriptor() ([]byte, []int) {\n\treturn file_transport_internet_kcp_config_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *TTI) GetValue() uint32 {\n\tif x != nil {\n\t\treturn x.Value\n\t}\n\treturn 0\n}\n\n// Uplink capacity, in MB.\ntype UplinkCapacity struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tValue uint32 `protobuf:\"varint,1,opt,name=value,proto3\" json:\"value,omitempty\"`\n}\n\nfunc (x *UplinkCapacity) Reset() {\n\t*x = UplinkCapacity{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_transport_internet_kcp_config_proto_msgTypes[2]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *UplinkCapacity) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*UplinkCapacity) ProtoMessage() {}\n\nfunc (x *UplinkCapacity) ProtoReflect() protoreflect.Message {\n\tmi := &file_transport_internet_kcp_config_proto_msgTypes[2]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use UplinkCapacity.ProtoReflect.Descriptor instead.\nfunc (*UplinkCapacity) Descriptor() ([]byte, []int) {\n\treturn file_transport_internet_kcp_config_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *UplinkCapacity) GetValue() uint32 {\n\tif x != nil {\n\t\treturn x.Value\n\t}\n\treturn 0\n}\n\n// Downlink capacity, in MB.\ntype DownlinkCapacity struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tValue uint32 `protobuf:\"varint,1,opt,name=value,proto3\" json:\"value,omitempty\"`\n}\n\nfunc (x *DownlinkCapacity) Reset() {\n\t*x = DownlinkCapacity{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_transport_internet_kcp_config_proto_msgTypes[3]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *DownlinkCapacity) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*DownlinkCapacity) ProtoMessage() {}\n\nfunc (x *DownlinkCapacity) ProtoReflect() protoreflect.Message {\n\tmi := &file_transport_internet_kcp_config_proto_msgTypes[3]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use DownlinkCapacity.ProtoReflect.Descriptor instead.\nfunc (*DownlinkCapacity) Descriptor() ([]byte, []int) {\n\treturn file_transport_internet_kcp_config_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *DownlinkCapacity) GetValue() uint32 {\n\tif x != nil {\n\t\treturn x.Value\n\t}\n\treturn 0\n}\n\ntype WriteBuffer struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Buffer size in bytes.\n\tSize uint32 `protobuf:\"varint,1,opt,name=size,proto3\" json:\"size,omitempty\"`\n}\n\nfunc (x *WriteBuffer) Reset() {\n\t*x = WriteBuffer{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_transport_internet_kcp_config_proto_msgTypes[4]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *WriteBuffer) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*WriteBuffer) ProtoMessage() {}\n\nfunc (x *WriteBuffer) ProtoReflect() protoreflect.Message {\n\tmi := &file_transport_internet_kcp_config_proto_msgTypes[4]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use WriteBuffer.ProtoReflect.Descriptor instead.\nfunc (*WriteBuffer) Descriptor() ([]byte, []int) {\n\treturn file_transport_internet_kcp_config_proto_rawDescGZIP(), []int{4}\n}\n\nfunc (x *WriteBuffer) GetSize() uint32 {\n\tif x != nil {\n\t\treturn x.Size\n\t}\n\treturn 0\n}\n\ntype ReadBuffer struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Buffer size in bytes.\n\tSize uint32 `protobuf:\"varint,1,opt,name=size,proto3\" json:\"size,omitempty\"`\n}\n\nfunc (x *ReadBuffer) Reset() {\n\t*x = ReadBuffer{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_transport_internet_kcp_config_proto_msgTypes[5]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *ReadBuffer) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ReadBuffer) ProtoMessage() {}\n\nfunc (x *ReadBuffer) ProtoReflect() protoreflect.Message {\n\tmi := &file_transport_internet_kcp_config_proto_msgTypes[5]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ReadBuffer.ProtoReflect.Descriptor instead.\nfunc (*ReadBuffer) Descriptor() ([]byte, []int) {\n\treturn file_transport_internet_kcp_config_proto_rawDescGZIP(), []int{5}\n}\n\nfunc (x *ReadBuffer) GetSize() uint32 {\n\tif x != nil {\n\t\treturn x.Size\n\t}\n\treturn 0\n}\n\ntype ConnectionReuse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tEnable bool `protobuf:\"varint,1,opt,name=enable,proto3\" json:\"enable,omitempty\"`\n}\n\nfunc (x *ConnectionReuse) Reset() {\n\t*x = ConnectionReuse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_transport_internet_kcp_config_proto_msgTypes[6]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *ConnectionReuse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ConnectionReuse) ProtoMessage() {}\n\nfunc (x *ConnectionReuse) ProtoReflect() protoreflect.Message {\n\tmi := &file_transport_internet_kcp_config_proto_msgTypes[6]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ConnectionReuse.ProtoReflect.Descriptor instead.\nfunc (*ConnectionReuse) Descriptor() ([]byte, []int) {\n\treturn file_transport_internet_kcp_config_proto_rawDescGZIP(), []int{6}\n}\n\nfunc (x *ConnectionReuse) GetEnable() bool {\n\tif x != nil {\n\t\treturn x.Enable\n\t}\n\treturn false\n}\n\n// Maximum Transmission Unit, in bytes.\ntype EncryptionSeed struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tSeed string `protobuf:\"bytes,1,opt,name=seed,proto3\" json:\"seed,omitempty\"`\n}\n\nfunc (x *EncryptionSeed) Reset() {\n\t*x = EncryptionSeed{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_transport_internet_kcp_config_proto_msgTypes[7]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *EncryptionSeed) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EncryptionSeed) ProtoMessage() {}\n\nfunc (x *EncryptionSeed) ProtoReflect() protoreflect.Message {\n\tmi := &file_transport_internet_kcp_config_proto_msgTypes[7]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EncryptionSeed.ProtoReflect.Descriptor instead.\nfunc (*EncryptionSeed) Descriptor() ([]byte, []int) {\n\treturn file_transport_internet_kcp_config_proto_rawDescGZIP(), []int{7}\n}\n\nfunc (x *EncryptionSeed) GetSeed() string {\n\tif x != nil {\n\t\treturn x.Seed\n\t}\n\treturn \"\"\n}\n\ntype Config struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tMtu              *MTU                 `protobuf:\"bytes,1,opt,name=mtu,proto3\" json:\"mtu,omitempty\"`\n\tTti              *TTI                 `protobuf:\"bytes,2,opt,name=tti,proto3\" json:\"tti,omitempty\"`\n\tUplinkCapacity   *UplinkCapacity      `protobuf:\"bytes,3,opt,name=uplink_capacity,json=uplinkCapacity,proto3\" json:\"uplink_capacity,omitempty\"`\n\tDownlinkCapacity *DownlinkCapacity    `protobuf:\"bytes,4,opt,name=downlink_capacity,json=downlinkCapacity,proto3\" json:\"downlink_capacity,omitempty\"`\n\tCongestion       bool                 `protobuf:\"varint,5,opt,name=congestion,proto3\" json:\"congestion,omitempty\"`\n\tWriteBuffer      *WriteBuffer         `protobuf:\"bytes,6,opt,name=write_buffer,json=writeBuffer,proto3\" json:\"write_buffer,omitempty\"`\n\tReadBuffer       *ReadBuffer          `protobuf:\"bytes,7,opt,name=read_buffer,json=readBuffer,proto3\" json:\"read_buffer,omitempty\"`\n\tHeaderConfig     *serial.TypedMessage `protobuf:\"bytes,8,opt,name=header_config,json=headerConfig,proto3\" json:\"header_config,omitempty\"`\n\tSeed             *EncryptionSeed      `protobuf:\"bytes,10,opt,name=seed,proto3\" json:\"seed,omitempty\"`\n}\n\nfunc (x *Config) Reset() {\n\t*x = Config{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_transport_internet_kcp_config_proto_msgTypes[8]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Config) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Config) ProtoMessage() {}\n\nfunc (x *Config) ProtoReflect() protoreflect.Message {\n\tmi := &file_transport_internet_kcp_config_proto_msgTypes[8]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Config.ProtoReflect.Descriptor instead.\nfunc (*Config) Descriptor() ([]byte, []int) {\n\treturn file_transport_internet_kcp_config_proto_rawDescGZIP(), []int{8}\n}\n\nfunc (x *Config) GetMtu() *MTU {\n\tif x != nil {\n\t\treturn x.Mtu\n\t}\n\treturn nil\n}\n\nfunc (x *Config) GetTti() *TTI {\n\tif x != nil {\n\t\treturn x.Tti\n\t}\n\treturn nil\n}\n\nfunc (x *Config) GetUplinkCapacity() *UplinkCapacity {\n\tif x != nil {\n\t\treturn x.UplinkCapacity\n\t}\n\treturn nil\n}\n\nfunc (x *Config) GetDownlinkCapacity() *DownlinkCapacity {\n\tif x != nil {\n\t\treturn x.DownlinkCapacity\n\t}\n\treturn nil\n}\n\nfunc (x *Config) GetCongestion() bool {\n\tif x != nil {\n\t\treturn x.Congestion\n\t}\n\treturn false\n}\n\nfunc (x *Config) GetWriteBuffer() *WriteBuffer {\n\tif x != nil {\n\t\treturn x.WriteBuffer\n\t}\n\treturn nil\n}\n\nfunc (x *Config) GetReadBuffer() *ReadBuffer {\n\tif x != nil {\n\t\treturn x.ReadBuffer\n\t}\n\treturn nil\n}\n\nfunc (x *Config) GetHeaderConfig() *serial.TypedMessage {\n\tif x != nil {\n\t\treturn x.HeaderConfig\n\t}\n\treturn nil\n}\n\nfunc (x *Config) GetSeed() *EncryptionSeed {\n\tif x != nil {\n\t\treturn x.Seed\n\t}\n\treturn nil\n}\n\nvar File_transport_internet_kcp_config_proto protoreflect.FileDescriptor\n\nvar file_transport_internet_kcp_config_proto_rawDesc = []byte{\n\t0x0a, 0x23, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65,\n\t0x72, 0x6e, 0x65, 0x74, 0x2f, 0x6b, 0x63, 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e,\n\t0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x21, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72,\n\t0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65,\n\t0x72, 0x6e, 0x65, 0x74, 0x2e, 0x6b, 0x63, 0x70, 0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,\n\t0x2f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x6d, 0x65,\n\t0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x1b, 0x0a, 0x03, 0x4d,\n\t0x54, 0x55, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,\n\t0x0d, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x1b, 0x0a, 0x03, 0x54, 0x54, 0x49, 0x12,\n\t0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05,\n\t0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x26, 0x0a, 0x0e, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x43,\n\t0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,\n\t0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x28, 0x0a,\n\t0x10, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x43, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74,\n\t0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d,\n\t0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x21, 0x0a, 0x0b, 0x57, 0x72, 0x69, 0x74, 0x65,\n\t0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x01,\n\t0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x22, 0x20, 0x0a, 0x0a, 0x52, 0x65,\n\t0x61, 0x64, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65,\n\t0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x22, 0x29, 0x0a, 0x0f,\n\t0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x75, 0x73, 0x65, 0x12,\n\t0x16, 0x0a, 0x06, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52,\n\t0x06, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x22, 0x24, 0x0a, 0x0e, 0x45, 0x6e, 0x63, 0x72, 0x79,\n\t0x70, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x65, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x65, 0x65,\n\t0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x73, 0x65, 0x65, 0x64, 0x22, 0x97, 0x05,\n\t0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x38, 0x0a, 0x03, 0x6d, 0x74, 0x75, 0x18,\n\t0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,\n\t0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74,\n\t0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x6b, 0x63, 0x70, 0x2e, 0x4d, 0x54, 0x55, 0x52, 0x03, 0x6d,\n\t0x74, 0x75, 0x12, 0x38, 0x0a, 0x03, 0x74, 0x74, 0x69, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,\n\t0x26, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61,\n\t0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e,\n\t0x6b, 0x63, 0x70, 0x2e, 0x54, 0x54, 0x49, 0x52, 0x03, 0x74, 0x74, 0x69, 0x12, 0x5a, 0x0a, 0x0f,\n\t0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x63, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x18,\n\t0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,\n\t0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74,\n\t0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x6b, 0x63, 0x70, 0x2e, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b,\n\t0x43, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x52, 0x0e, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b,\n\t0x43, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x12, 0x60, 0x0a, 0x11, 0x64, 0x6f, 0x77, 0x6e,\n\t0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x63, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x18, 0x04, 0x20,\n\t0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,\n\t0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72,\n\t0x6e, 0x65, 0x74, 0x2e, 0x6b, 0x63, 0x70, 0x2e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b,\n\t0x43, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x52, 0x10, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69,\n\t0x6e, 0x6b, 0x43, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f,\n\t0x6e, 0x67, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a,\n\t0x63, 0x6f, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x51, 0x0a, 0x0c, 0x77, 0x72,\n\t0x69, 0x74, 0x65, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b,\n\t0x32, 0x2e, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72,\n\t0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74,\n\t0x2e, 0x6b, 0x63, 0x70, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72,\n\t0x52, 0x0b, 0x77, 0x72, 0x69, 0x74, 0x65, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x12, 0x4e, 0x0a,\n\t0x0b, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01,\n\t0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,\n\t0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,\n\t0x65, 0x74, 0x2e, 0x6b, 0x63, 0x70, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x42, 0x75, 0x66, 0x66, 0x65,\n\t0x72, 0x52, 0x0a, 0x72, 0x65, 0x61, 0x64, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x12, 0x4b, 0x0a,\n\t0x0d, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x08,\n\t0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72,\n\t0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e,\n\t0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0c, 0x68, 0x65,\n\t0x61, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x45, 0x0a, 0x04, 0x73, 0x65,\n\t0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,\n\t0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e,\n\t0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x6b, 0x63, 0x70, 0x2e, 0x45, 0x6e, 0x63,\n\t0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x65, 0x64, 0x52, 0x04, 0x73, 0x65, 0x65,\n\t0x64, 0x4a, 0x04, 0x08, 0x09, 0x10, 0x0a, 0x42, 0x74, 0x0a, 0x25, 0x63, 0x6f, 0x6d, 0x2e, 0x76,\n\t0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70,\n\t0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x6b, 0x63, 0x70,\n\t0x50, 0x01, 0x5a, 0x25, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f,\n\t0x72, 0x65, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74,\n\t0x65, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x6b, 0x63, 0x70, 0xaa, 0x02, 0x21, 0x56, 0x32, 0x52, 0x61,\n\t0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74,\n\t0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x4b, 0x63, 0x70, 0x62, 0x06, 0x70,\n\t0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_transport_internet_kcp_config_proto_rawDescOnce sync.Once\n\tfile_transport_internet_kcp_config_proto_rawDescData = file_transport_internet_kcp_config_proto_rawDesc\n)\n\nfunc file_transport_internet_kcp_config_proto_rawDescGZIP() []byte {\n\tfile_transport_internet_kcp_config_proto_rawDescOnce.Do(func() {\n\t\tfile_transport_internet_kcp_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_transport_internet_kcp_config_proto_rawDescData)\n\t})\n\treturn file_transport_internet_kcp_config_proto_rawDescData\n}\n\nvar file_transport_internet_kcp_config_proto_msgTypes = make([]protoimpl.MessageInfo, 9)\nvar file_transport_internet_kcp_config_proto_goTypes = []interface{}{\n\t(*MTU)(nil),                 // 0: v2ray.core.transport.internet.kcp.MTU\n\t(*TTI)(nil),                 // 1: v2ray.core.transport.internet.kcp.TTI\n\t(*UplinkCapacity)(nil),      // 2: v2ray.core.transport.internet.kcp.UplinkCapacity\n\t(*DownlinkCapacity)(nil),    // 3: v2ray.core.transport.internet.kcp.DownlinkCapacity\n\t(*WriteBuffer)(nil),         // 4: v2ray.core.transport.internet.kcp.WriteBuffer\n\t(*ReadBuffer)(nil),          // 5: v2ray.core.transport.internet.kcp.ReadBuffer\n\t(*ConnectionReuse)(nil),     // 6: v2ray.core.transport.internet.kcp.ConnectionReuse\n\t(*EncryptionSeed)(nil),      // 7: v2ray.core.transport.internet.kcp.EncryptionSeed\n\t(*Config)(nil),              // 8: v2ray.core.transport.internet.kcp.Config\n\t(*serial.TypedMessage)(nil), // 9: v2ray.core.common.serial.TypedMessage\n}\nvar file_transport_internet_kcp_config_proto_depIdxs = []int32{\n\t0, // 0: v2ray.core.transport.internet.kcp.Config.mtu:type_name -> v2ray.core.transport.internet.kcp.MTU\n\t1, // 1: v2ray.core.transport.internet.kcp.Config.tti:type_name -> v2ray.core.transport.internet.kcp.TTI\n\t2, // 2: v2ray.core.transport.internet.kcp.Config.uplink_capacity:type_name -> v2ray.core.transport.internet.kcp.UplinkCapacity\n\t3, // 3: v2ray.core.transport.internet.kcp.Config.downlink_capacity:type_name -> v2ray.core.transport.internet.kcp.DownlinkCapacity\n\t4, // 4: v2ray.core.transport.internet.kcp.Config.write_buffer:type_name -> v2ray.core.transport.internet.kcp.WriteBuffer\n\t5, // 5: v2ray.core.transport.internet.kcp.Config.read_buffer:type_name -> v2ray.core.transport.internet.kcp.ReadBuffer\n\t9, // 6: v2ray.core.transport.internet.kcp.Config.header_config:type_name -> v2ray.core.common.serial.TypedMessage\n\t7, // 7: v2ray.core.transport.internet.kcp.Config.seed:type_name -> v2ray.core.transport.internet.kcp.EncryptionSeed\n\t8, // [8:8] is the sub-list for method output_type\n\t8, // [8:8] is the sub-list for method input_type\n\t8, // [8:8] is the sub-list for extension type_name\n\t8, // [8:8] is the sub-list for extension extendee\n\t0, // [0:8] is the sub-list for field type_name\n}\n\nfunc init() { file_transport_internet_kcp_config_proto_init() }\nfunc file_transport_internet_kcp_config_proto_init() {\n\tif File_transport_internet_kcp_config_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_transport_internet_kcp_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*MTU); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_transport_internet_kcp_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*TTI); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_transport_internet_kcp_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*UplinkCapacity); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_transport_internet_kcp_config_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*DownlinkCapacity); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_transport_internet_kcp_config_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*WriteBuffer); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_transport_internet_kcp_config_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*ReadBuffer); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_transport_internet_kcp_config_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*ConnectionReuse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_transport_internet_kcp_config_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*EncryptionSeed); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_transport_internet_kcp_config_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Config); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_transport_internet_kcp_config_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   9,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_transport_internet_kcp_config_proto_goTypes,\n\t\tDependencyIndexes: file_transport_internet_kcp_config_proto_depIdxs,\n\t\tMessageInfos:      file_transport_internet_kcp_config_proto_msgTypes,\n\t}.Build()\n\tFile_transport_internet_kcp_config_proto = out.File\n\tfile_transport_internet_kcp_config_proto_rawDesc = nil\n\tfile_transport_internet_kcp_config_proto_goTypes = nil\n\tfile_transport_internet_kcp_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "transport/internet/kcp/config.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.transport.internet.kcp;\noption csharp_namespace = \"V2Ray.Core.Transport.Internet.Kcp\";\noption go_package = \"v2ray.com/core/transport/internet/kcp\";\noption java_package = \"com.v2ray.core.transport.internet.kcp\";\noption java_multiple_files = true;\n\nimport \"common/serial/typed_message.proto\";\n\n// Maximum Transmission Unit, in bytes.\nmessage MTU {\n  uint32 value = 1;\n}\n\n// Transmission Time Interview, in milli-sec.\nmessage TTI {\n  uint32 value = 1;\n}\n\n// Uplink capacity, in MB.\nmessage UplinkCapacity {\n  uint32 value = 1;\n}\n\n// Downlink capacity, in MB.\nmessage DownlinkCapacity {\n  uint32 value = 1;\n}\n\nmessage WriteBuffer {\n  // Buffer size in bytes.\n  uint32 size = 1;\n}\n\nmessage ReadBuffer {\n  // Buffer size in bytes.\n  uint32 size = 1;\n}\n\nmessage ConnectionReuse {\n  bool enable = 1;\n}\n\n// Maximum Transmission Unit, in bytes.\nmessage EncryptionSeed {\n  string seed = 1;\n}\n\nmessage Config {\n  MTU mtu = 1;\n  TTI tti = 2;\n  UplinkCapacity uplink_capacity = 3;\n  DownlinkCapacity downlink_capacity = 4;\n  bool congestion = 5;\n  WriteBuffer write_buffer = 6;\n  ReadBuffer read_buffer = 7;\n  v2ray.core.common.serial.TypedMessage header_config = 8;\n  reserved 9;\n  EncryptionSeed seed = 10;\n}\n"
  },
  {
    "path": "transport/internet/kcp/connection.go",
    "content": "// +build !confonly\n\npackage kcp\n\nimport (\n\t\"bytes\"\n\t\"io\"\n\t\"net\"\n\t\"runtime\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/signal\"\n\t\"v2ray.com/core/common/signal/semaphore\"\n)\n\nvar (\n\tErrIOTimeout        = newError(\"Read/Write timeout\")\n\tErrClosedListener   = newError(\"Listener closed.\")\n\tErrClosedConnection = newError(\"Connection closed.\")\n)\n\n// State of the connection\ntype State int32\n\n// Is returns true if current State is one of the candidates.\nfunc (s State) Is(states ...State) bool {\n\tfor _, state := range states {\n\t\tif s == state {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nconst (\n\tStateActive          State = 0 // Connection is active\n\tStateReadyToClose    State = 1 // Connection is closed locally\n\tStatePeerClosed      State = 2 // Connection is closed on remote\n\tStateTerminating     State = 3 // Connection is ready to be destroyed locally\n\tStatePeerTerminating State = 4 // Connection is ready to be destroyed on remote\n\tStateTerminated      State = 5 // Connection is destroyed.\n)\n\nfunc nowMillisec() int64 {\n\tnow := time.Now()\n\treturn now.Unix()*1000 + int64(now.Nanosecond()/1000000)\n}\n\ntype RoundTripInfo struct {\n\tsync.RWMutex\n\tvariation        uint32\n\tsrtt             uint32\n\trto              uint32\n\tminRtt           uint32\n\tupdatedTimestamp uint32\n}\n\nfunc (info *RoundTripInfo) UpdatePeerRTO(rto uint32, current uint32) {\n\tinfo.Lock()\n\tdefer info.Unlock()\n\n\tif current-info.updatedTimestamp < 3000 {\n\t\treturn\n\t}\n\n\tinfo.updatedTimestamp = current\n\tinfo.rto = rto\n}\n\nfunc (info *RoundTripInfo) Update(rtt uint32, current uint32) {\n\tif rtt > 0x7FFFFFFF {\n\t\treturn\n\t}\n\tinfo.Lock()\n\tdefer info.Unlock()\n\n\t// https://tools.ietf.org/html/rfc6298\n\tif info.srtt == 0 {\n\t\tinfo.srtt = rtt\n\t\tinfo.variation = rtt / 2\n\t} else {\n\t\tdelta := rtt - info.srtt\n\t\tif info.srtt > rtt {\n\t\t\tdelta = info.srtt - rtt\n\t\t}\n\t\tinfo.variation = (3*info.variation + delta) / 4\n\t\tinfo.srtt = (7*info.srtt + rtt) / 8\n\t\tif info.srtt < info.minRtt {\n\t\t\tinfo.srtt = info.minRtt\n\t\t}\n\t}\n\tvar rto uint32\n\tif info.minRtt < 4*info.variation {\n\t\trto = info.srtt + 4*info.variation\n\t} else {\n\t\trto = info.srtt + info.variation\n\t}\n\n\tif rto > 10000 {\n\t\trto = 10000\n\t}\n\tinfo.rto = rto * 5 / 4\n\tinfo.updatedTimestamp = current\n}\n\nfunc (info *RoundTripInfo) Timeout() uint32 {\n\tinfo.RLock()\n\tdefer info.RUnlock()\n\n\treturn info.rto\n}\n\nfunc (info *RoundTripInfo) SmoothedTime() uint32 {\n\tinfo.RLock()\n\tdefer info.RUnlock()\n\n\treturn info.srtt\n}\n\ntype Updater struct {\n\tinterval        int64\n\tshouldContinue  func() bool\n\tshouldTerminate func() bool\n\tupdateFunc      func()\n\tnotifier        *semaphore.Instance\n}\n\nfunc NewUpdater(interval uint32, shouldContinue func() bool, shouldTerminate func() bool, updateFunc func()) *Updater {\n\tu := &Updater{\n\t\tinterval:        int64(time.Duration(interval) * time.Millisecond),\n\t\tshouldContinue:  shouldContinue,\n\t\tshouldTerminate: shouldTerminate,\n\t\tupdateFunc:      updateFunc,\n\t\tnotifier:        semaphore.New(1),\n\t}\n\treturn u\n}\n\nfunc (u *Updater) WakeUp() {\n\tselect {\n\tcase <-u.notifier.Wait():\n\t\tgo u.run()\n\tdefault:\n\t}\n}\n\nfunc (u *Updater) run() {\n\tdefer u.notifier.Signal()\n\n\tif u.shouldTerminate() {\n\t\treturn\n\t}\n\tticker := time.NewTicker(u.Interval())\n\tfor u.shouldContinue() {\n\t\tu.updateFunc()\n\t\t<-ticker.C\n\t}\n\tticker.Stop()\n}\n\nfunc (u *Updater) Interval() time.Duration {\n\treturn time.Duration(atomic.LoadInt64(&u.interval))\n}\n\nfunc (u *Updater) SetInterval(d time.Duration) {\n\tatomic.StoreInt64(&u.interval, int64(d))\n}\n\ntype ConnMetadata struct {\n\tLocalAddr    net.Addr\n\tRemoteAddr   net.Addr\n\tConversation uint16\n}\n\n// Connection is a KCP connection over UDP.\ntype Connection struct {\n\tmeta       ConnMetadata\n\tcloser     io.Closer\n\trd         time.Time\n\twd         time.Time // write deadline\n\tsince      int64\n\tdataInput  *signal.Notifier\n\tdataOutput *signal.Notifier\n\tConfig     *Config\n\n\tstate            State\n\tstateBeginTime   uint32\n\tlastIncomingTime uint32\n\tlastPingTime     uint32\n\n\tmss       uint32\n\troundTrip *RoundTripInfo\n\n\treceivingWorker *ReceivingWorker\n\tsendingWorker   *SendingWorker\n\n\toutput SegmentWriter\n\n\tdataUpdater *Updater\n\tpingUpdater *Updater\n}\n\n// NewConnection create a new KCP connection between local and remote.\nfunc NewConnection(meta ConnMetadata, writer PacketWriter, closer io.Closer, config *Config) *Connection {\n\tnewError(\"#\", meta.Conversation, \" creating connection to \", meta.RemoteAddr).WriteToLog()\n\n\tconn := &Connection{\n\t\tmeta:       meta,\n\t\tcloser:     closer,\n\t\tsince:      nowMillisec(),\n\t\tdataInput:  signal.NewNotifier(),\n\t\tdataOutput: signal.NewNotifier(),\n\t\tConfig:     config,\n\t\toutput:     NewRetryableWriter(NewSegmentWriter(writer)),\n\t\tmss:        config.GetMTUValue() - uint32(writer.Overhead()) - DataSegmentOverhead,\n\t\troundTrip: &RoundTripInfo{\n\t\t\trto:    100,\n\t\t\tminRtt: config.GetTTIValue(),\n\t\t},\n\t}\n\n\tconn.receivingWorker = NewReceivingWorker(conn)\n\tconn.sendingWorker = NewSendingWorker(conn)\n\n\tisTerminating := func() bool {\n\t\treturn conn.State().Is(StateTerminating, StateTerminated)\n\t}\n\tisTerminated := func() bool {\n\t\treturn conn.State() == StateTerminated\n\t}\n\tconn.dataUpdater = NewUpdater(\n\t\tconfig.GetTTIValue(),\n\t\tfunc() bool {\n\t\t\treturn !isTerminating() && (conn.sendingWorker.UpdateNecessary() || conn.receivingWorker.UpdateNecessary())\n\t\t},\n\t\tisTerminating,\n\t\tconn.updateTask)\n\tconn.pingUpdater = NewUpdater(\n\t\t5000, // 5 seconds\n\t\tfunc() bool { return !isTerminated() },\n\t\tisTerminated,\n\t\tconn.updateTask)\n\tconn.pingUpdater.WakeUp()\n\n\treturn conn\n}\n\nfunc (c *Connection) Elapsed() uint32 {\n\treturn uint32(nowMillisec() - c.since)\n}\n\n// ReadMultiBuffer implements buf.Reader.\nfunc (c *Connection) ReadMultiBuffer() (buf.MultiBuffer, error) {\n\tif c == nil {\n\t\treturn nil, io.EOF\n\t}\n\n\tfor {\n\t\tif c.State().Is(StateReadyToClose, StateTerminating, StateTerminated) {\n\t\t\treturn nil, io.EOF\n\t\t}\n\t\tmb := c.receivingWorker.ReadMultiBuffer()\n\t\tif !mb.IsEmpty() {\n\t\t\tc.dataUpdater.WakeUp()\n\t\t\treturn mb, nil\n\t\t}\n\n\t\tif c.State() == StatePeerTerminating {\n\t\t\treturn nil, io.EOF\n\t\t}\n\n\t\tif err := c.waitForDataInput(); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n}\n\nfunc (c *Connection) waitForDataInput() error {\n\tfor i := 0; i < 16; i++ {\n\t\tselect {\n\t\tcase <-c.dataInput.Wait():\n\t\t\treturn nil\n\t\tdefault:\n\t\t\truntime.Gosched()\n\t\t}\n\t}\n\n\tduration := time.Second * 16\n\tif !c.rd.IsZero() {\n\t\tduration = time.Until(c.rd)\n\t\tif duration < 0 {\n\t\t\treturn ErrIOTimeout\n\t\t}\n\t}\n\n\ttimeout := time.NewTimer(duration)\n\tdefer timeout.Stop()\n\n\tselect {\n\tcase <-c.dataInput.Wait():\n\tcase <-timeout.C:\n\t\tif !c.rd.IsZero() && c.rd.Before(time.Now()) {\n\t\t\treturn ErrIOTimeout\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Read implements the Conn Read method.\nfunc (c *Connection) Read(b []byte) (int, error) {\n\tif c == nil {\n\t\treturn 0, io.EOF\n\t}\n\n\tfor {\n\t\tif c.State().Is(StateReadyToClose, StateTerminating, StateTerminated) {\n\t\t\treturn 0, io.EOF\n\t\t}\n\t\tnBytes := c.receivingWorker.Read(b)\n\t\tif nBytes > 0 {\n\t\t\tc.dataUpdater.WakeUp()\n\t\t\treturn nBytes, nil\n\t\t}\n\n\t\tif err := c.waitForDataInput(); err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t}\n}\n\nfunc (c *Connection) waitForDataOutput() error {\n\tfor i := 0; i < 16; i++ {\n\t\tselect {\n\t\tcase <-c.dataOutput.Wait():\n\t\t\treturn nil\n\t\tdefault:\n\t\t\truntime.Gosched()\n\t\t}\n\t}\n\n\tduration := time.Second * 16\n\tif !c.wd.IsZero() {\n\t\tduration = time.Until(c.wd)\n\t\tif duration < 0 {\n\t\t\treturn ErrIOTimeout\n\t\t}\n\t}\n\n\ttimeout := time.NewTimer(duration)\n\tdefer timeout.Stop()\n\n\tselect {\n\tcase <-c.dataOutput.Wait():\n\tcase <-timeout.C:\n\t\tif !c.wd.IsZero() && c.wd.Before(time.Now()) {\n\t\t\treturn ErrIOTimeout\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Write implements io.Writer.\nfunc (c *Connection) Write(b []byte) (int, error) {\n\treader := bytes.NewReader(b)\n\tif err := c.writeMultiBufferInternal(reader); err != nil {\n\t\treturn 0, err\n\t}\n\treturn len(b), nil\n}\n\n// WriteMultiBuffer implements buf.Writer.\nfunc (c *Connection) WriteMultiBuffer(mb buf.MultiBuffer) error {\n\treader := &buf.MultiBufferContainer{\n\t\tMultiBuffer: mb,\n\t}\n\tdefer reader.Close()\n\n\treturn c.writeMultiBufferInternal(reader)\n}\n\nfunc (c *Connection) writeMultiBufferInternal(reader io.Reader) error {\n\tupdatePending := false\n\tdefer func() {\n\t\tif updatePending {\n\t\t\tc.dataUpdater.WakeUp()\n\t\t}\n\t}()\n\n\tvar b *buf.Buffer\n\tdefer b.Release()\n\n\tfor {\n\t\tfor {\n\t\t\tif c == nil || c.State() != StateActive {\n\t\t\t\treturn io.ErrClosedPipe\n\t\t\t}\n\n\t\t\tif b == nil {\n\t\t\t\tb = buf.New()\n\t\t\t\t_, err := b.ReadFrom(io.LimitReader(reader, int64(c.mss)))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif !c.sendingWorker.Push(b) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tupdatePending = true\n\t\t\tb = nil\n\t\t}\n\n\t\tif updatePending {\n\t\t\tc.dataUpdater.WakeUp()\n\t\t\tupdatePending = false\n\t\t}\n\n\t\tif err := c.waitForDataOutput(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n\nfunc (c *Connection) SetState(state State) {\n\tcurrent := c.Elapsed()\n\tatomic.StoreInt32((*int32)(&c.state), int32(state))\n\tatomic.StoreUint32(&c.stateBeginTime, current)\n\tnewError(\"#\", c.meta.Conversation, \" entering state \", state, \" at \", current).AtDebug().WriteToLog()\n\n\tswitch state {\n\tcase StateReadyToClose:\n\t\tc.receivingWorker.CloseRead()\n\tcase StatePeerClosed:\n\t\tc.sendingWorker.CloseWrite()\n\tcase StateTerminating:\n\t\tc.receivingWorker.CloseRead()\n\t\tc.sendingWorker.CloseWrite()\n\t\tc.pingUpdater.SetInterval(time.Second)\n\tcase StatePeerTerminating:\n\t\tc.sendingWorker.CloseWrite()\n\t\tc.pingUpdater.SetInterval(time.Second)\n\tcase StateTerminated:\n\t\tc.receivingWorker.CloseRead()\n\t\tc.sendingWorker.CloseWrite()\n\t\tc.pingUpdater.SetInterval(time.Second)\n\t\tc.dataUpdater.WakeUp()\n\t\tc.pingUpdater.WakeUp()\n\t\tgo c.Terminate()\n\t}\n}\n\n// Close closes the connection.\nfunc (c *Connection) Close() error {\n\tif c == nil {\n\t\treturn ErrClosedConnection\n\t}\n\n\tc.dataInput.Signal()\n\tc.dataOutput.Signal()\n\n\tswitch c.State() {\n\tcase StateReadyToClose, StateTerminating, StateTerminated:\n\t\treturn ErrClosedConnection\n\tcase StateActive:\n\t\tc.SetState(StateReadyToClose)\n\tcase StatePeerClosed:\n\t\tc.SetState(StateTerminating)\n\tcase StatePeerTerminating:\n\t\tc.SetState(StateTerminated)\n\t}\n\n\tnewError(\"#\", c.meta.Conversation, \" closing connection to \", c.meta.RemoteAddr).WriteToLog()\n\n\treturn nil\n}\n\n// LocalAddr returns the local network address. The Addr returned is shared by all invocations of LocalAddr, so do not modify it.\nfunc (c *Connection) LocalAddr() net.Addr {\n\tif c == nil {\n\t\treturn nil\n\t}\n\treturn c.meta.LocalAddr\n}\n\n// RemoteAddr returns the remote network address. The Addr returned is shared by all invocations of RemoteAddr, so do not modify it.\nfunc (c *Connection) RemoteAddr() net.Addr {\n\tif c == nil {\n\t\treturn nil\n\t}\n\treturn c.meta.RemoteAddr\n}\n\n// SetDeadline sets the deadline associated with the listener. A zero time value disables the deadline.\nfunc (c *Connection) SetDeadline(t time.Time) error {\n\tif err := c.SetReadDeadline(t); err != nil {\n\t\treturn err\n\t}\n\treturn c.SetWriteDeadline(t)\n}\n\n// SetReadDeadline implements the Conn SetReadDeadline method.\nfunc (c *Connection) SetReadDeadline(t time.Time) error {\n\tif c == nil || c.State() != StateActive {\n\t\treturn ErrClosedConnection\n\t}\n\tc.rd = t\n\treturn nil\n}\n\n// SetWriteDeadline implements the Conn SetWriteDeadline method.\nfunc (c *Connection) SetWriteDeadline(t time.Time) error {\n\tif c == nil || c.State() != StateActive {\n\t\treturn ErrClosedConnection\n\t}\n\tc.wd = t\n\treturn nil\n}\n\n// kcp update, input loop\nfunc (c *Connection) updateTask() {\n\tc.flush()\n}\n\nfunc (c *Connection) Terminate() {\n\tif c == nil {\n\t\treturn\n\t}\n\tnewError(\"#\", c.meta.Conversation, \" terminating connection to \", c.RemoteAddr()).WriteToLog()\n\n\t//v.SetState(StateTerminated)\n\tc.dataInput.Signal()\n\tc.dataOutput.Signal()\n\n\tc.closer.Close()\n\tc.sendingWorker.Release()\n\tc.receivingWorker.Release()\n}\n\nfunc (c *Connection) HandleOption(opt SegmentOption) {\n\tif (opt & SegmentOptionClose) == SegmentOptionClose {\n\t\tc.OnPeerClosed()\n\t}\n}\n\nfunc (c *Connection) OnPeerClosed() {\n\tswitch c.State() {\n\tcase StateReadyToClose:\n\t\tc.SetState(StateTerminating)\n\tcase StateActive:\n\t\tc.SetState(StatePeerClosed)\n\t}\n}\n\n// Input when you received a low level packet (eg. UDP packet), call it\nfunc (c *Connection) Input(segments []Segment) {\n\tcurrent := c.Elapsed()\n\tatomic.StoreUint32(&c.lastIncomingTime, current)\n\n\tfor _, seg := range segments {\n\t\tif seg.Conversation() != c.meta.Conversation {\n\t\t\tbreak\n\t\t}\n\n\t\tswitch seg := seg.(type) {\n\t\tcase *DataSegment:\n\t\t\tc.HandleOption(seg.Option)\n\t\t\tc.receivingWorker.ProcessSegment(seg)\n\t\t\tif c.receivingWorker.IsDataAvailable() {\n\t\t\t\tc.dataInput.Signal()\n\t\t\t}\n\t\t\tc.dataUpdater.WakeUp()\n\t\tcase *AckSegment:\n\t\t\tc.HandleOption(seg.Option)\n\t\t\tc.sendingWorker.ProcessSegment(current, seg, c.roundTrip.Timeout())\n\t\t\tc.dataOutput.Signal()\n\t\t\tc.dataUpdater.WakeUp()\n\t\tcase *CmdOnlySegment:\n\t\t\tc.HandleOption(seg.Option)\n\t\t\tif seg.Command() == CommandTerminate {\n\t\t\t\tswitch c.State() {\n\t\t\t\tcase StateActive, StatePeerClosed:\n\t\t\t\t\tc.SetState(StatePeerTerminating)\n\t\t\t\tcase StateReadyToClose:\n\t\t\t\t\tc.SetState(StateTerminating)\n\t\t\t\tcase StateTerminating:\n\t\t\t\t\tc.SetState(StateTerminated)\n\t\t\t\t}\n\t\t\t}\n\t\t\tif seg.Option == SegmentOptionClose || seg.Command() == CommandTerminate {\n\t\t\t\tc.dataInput.Signal()\n\t\t\t\tc.dataOutput.Signal()\n\t\t\t}\n\t\t\tc.sendingWorker.ProcessReceivingNext(seg.ReceivingNext)\n\t\t\tc.receivingWorker.ProcessSendingNext(seg.SendingNext)\n\t\t\tc.roundTrip.UpdatePeerRTO(seg.PeerRTO, current)\n\t\t\tseg.Release()\n\t\tdefault:\n\t\t}\n\t}\n}\n\nfunc (c *Connection) flush() {\n\tcurrent := c.Elapsed()\n\n\tif c.State() == StateTerminated {\n\t\treturn\n\t}\n\tif c.State() == StateActive && current-atomic.LoadUint32(&c.lastIncomingTime) >= 30000 {\n\t\tc.Close()\n\t}\n\tif c.State() == StateReadyToClose && c.sendingWorker.IsEmpty() {\n\t\tc.SetState(StateTerminating)\n\t}\n\n\tif c.State() == StateTerminating {\n\t\tnewError(\"#\", c.meta.Conversation, \" sending terminating cmd.\").AtDebug().WriteToLog()\n\t\tc.Ping(current, CommandTerminate)\n\n\t\tif current-atomic.LoadUint32(&c.stateBeginTime) > 8000 {\n\t\t\tc.SetState(StateTerminated)\n\t\t}\n\t\treturn\n\t}\n\tif c.State() == StatePeerTerminating && current-atomic.LoadUint32(&c.stateBeginTime) > 4000 {\n\t\tc.SetState(StateTerminating)\n\t}\n\n\tif c.State() == StateReadyToClose && current-atomic.LoadUint32(&c.stateBeginTime) > 15000 {\n\t\tc.SetState(StateTerminating)\n\t}\n\n\t// flush acknowledges\n\tc.receivingWorker.Flush(current)\n\tc.sendingWorker.Flush(current)\n\n\tif current-atomic.LoadUint32(&c.lastPingTime) >= 3000 {\n\t\tc.Ping(current, CommandPing)\n\t}\n}\n\nfunc (c *Connection) State() State {\n\treturn State(atomic.LoadInt32((*int32)(&c.state)))\n}\n\nfunc (c *Connection) Ping(current uint32, cmd Command) {\n\tseg := NewCmdOnlySegment()\n\tseg.Conv = c.meta.Conversation\n\tseg.Cmd = cmd\n\tseg.ReceivingNext = c.receivingWorker.NextNumber()\n\tseg.SendingNext = c.sendingWorker.FirstUnacknowledged()\n\tseg.PeerRTO = c.roundTrip.Timeout()\n\tif c.State() == StateReadyToClose {\n\t\tseg.Option = SegmentOptionClose\n\t}\n\tc.output.Write(seg)\n\tatomic.StoreUint32(&c.lastPingTime, current)\n\tseg.Release()\n}\n"
  },
  {
    "path": "transport/internet/kcp/connection_test.go",
    "content": "package kcp_test\n\nimport (\n\t\"io\"\n\t\"testing\"\n\t\"time\"\n\n\t\"v2ray.com/core/common/buf\"\n\t. \"v2ray.com/core/transport/internet/kcp\"\n)\n\ntype NoOpCloser int\n\nfunc (NoOpCloser) Close() error {\n\treturn nil\n}\n\nfunc TestConnectionReadTimeout(t *testing.T) {\n\tconn := NewConnection(ConnMetadata{Conversation: 1}, &KCPPacketWriter{\n\t\tWriter: buf.DiscardBytes,\n\t}, NoOpCloser(0), &Config{})\n\tconn.SetReadDeadline(time.Now().Add(time.Second))\n\n\tb := make([]byte, 1024)\n\tnBytes, err := conn.Read(b)\n\tif nBytes != 0 || err == nil {\n\t\tt.Error(\"unexpected read: \", nBytes, err)\n\t}\n\n\tconn.Terminate()\n}\n\nfunc TestConnectionInterface(t *testing.T) {\n\t_ = (io.Writer)(new(Connection))\n\t_ = (io.Reader)(new(Connection))\n\t_ = (buf.Reader)(new(Connection))\n\t_ = (buf.Writer)(new(Connection))\n}\n"
  },
  {
    "path": "transport/internet/kcp/crypt.go",
    "content": "// +build !confonly\n\npackage kcp\n\nimport (\n\t\"crypto/cipher\"\n\t\"encoding/binary\"\n\t\"hash/fnv\"\n\n\t\"v2ray.com/core/common\"\n)\n\n// SimpleAuthenticator is a legacy AEAD used for KCP encryption.\ntype SimpleAuthenticator struct{}\n\n// NewSimpleAuthenticator creates a new SimpleAuthenticator\nfunc NewSimpleAuthenticator() cipher.AEAD {\n\treturn &SimpleAuthenticator{}\n}\n\n// NonceSize implements cipher.AEAD.NonceSize().\nfunc (*SimpleAuthenticator) NonceSize() int {\n\treturn 0\n}\n\n// Overhead implements cipher.AEAD.NonceSize().\nfunc (*SimpleAuthenticator) Overhead() int {\n\treturn 6\n}\n\n// Seal implements cipher.AEAD.Seal().\nfunc (a *SimpleAuthenticator) Seal(dst, nonce, plain, extra []byte) []byte {\n\tdst = append(dst, 0, 0, 0, 0, 0, 0) // 4 bytes for hash, and then 2 bytes for length\n\tbinary.BigEndian.PutUint16(dst[4:], uint16(len(plain)))\n\tdst = append(dst, plain...)\n\n\tfnvHash := fnv.New32a()\n\tcommon.Must2(fnvHash.Write(dst[4:]))\n\tfnvHash.Sum(dst[:0])\n\n\tdstLen := len(dst)\n\txtra := 4 - dstLen%4\n\tif xtra != 4 {\n\t\tdst = append(dst, make([]byte, xtra)...)\n\t}\n\txorfwd(dst)\n\tif xtra != 4 {\n\t\tdst = dst[:dstLen]\n\t}\n\treturn dst\n}\n\n// Open implements cipher.AEAD.Open().\nfunc (a *SimpleAuthenticator) Open(dst, nonce, cipherText, extra []byte) ([]byte, error) {\n\tdst = append(dst, cipherText...)\n\tdstLen := len(dst)\n\txtra := 4 - dstLen%4\n\tif xtra != 4 {\n\t\tdst = append(dst, make([]byte, xtra)...)\n\t}\n\txorbkd(dst)\n\tif xtra != 4 {\n\t\tdst = dst[:dstLen]\n\t}\n\n\tfnvHash := fnv.New32a()\n\tcommon.Must2(fnvHash.Write(dst[4:]))\n\tif binary.BigEndian.Uint32(dst[:4]) != fnvHash.Sum32() {\n\t\treturn nil, newError(\"invalid auth\")\n\t}\n\n\tlength := binary.BigEndian.Uint16(dst[4:6])\n\tif len(dst)-6 != int(length) {\n\t\treturn nil, newError(\"invalid auth\")\n\t}\n\n\treturn dst[6:], nil\n}\n"
  },
  {
    "path": "transport/internet/kcp/crypt_test.go",
    "content": "package kcp_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\n\t\"v2ray.com/core/common\"\n\t. \"v2ray.com/core/transport/internet/kcp\"\n)\n\nfunc TestSimpleAuthenticator(t *testing.T) {\n\tcache := make([]byte, 512)\n\n\tpayload := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g'}\n\n\tauth := NewSimpleAuthenticator()\n\tb := auth.Seal(cache[:0], nil, payload, nil)\n\tc, err := auth.Open(cache[:0], nil, b, nil)\n\tcommon.Must(err)\n\tif r := cmp.Diff(c, payload); r != \"\" {\n\t\tt.Error(r)\n\t}\n}\n\nfunc TestSimpleAuthenticator2(t *testing.T) {\n\tcache := make([]byte, 512)\n\n\tpayload := []byte{'a', 'b'}\n\n\tauth := NewSimpleAuthenticator()\n\tb := auth.Seal(cache[:0], nil, payload, nil)\n\tc, err := auth.Open(cache[:0], nil, b, nil)\n\tcommon.Must(err)\n\tif r := cmp.Diff(c, payload); r != \"\" {\n\t\tt.Error(r)\n\t}\n}\n"
  },
  {
    "path": "transport/internet/kcp/cryptreal.go",
    "content": "package kcp\n\nimport (\n\t\"crypto/aes\"\n\t\"crypto/cipher\"\n\t\"crypto/sha256\"\n\t\"v2ray.com/core/common\"\n)\n\nfunc NewAEADAESGCMBasedOnSeed(seed string) cipher.AEAD {\n\tHashedSeed := sha256.Sum256([]byte(seed))\n\taesBlock := common.Must2(aes.NewCipher(HashedSeed[:16])).(cipher.Block)\n\treturn common.Must2(cipher.NewGCM(aesBlock)).(cipher.AEAD)\n}\n"
  },
  {
    "path": "transport/internet/kcp/dialer.go",
    "content": "// +build !confonly\n\npackage kcp\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"sync/atomic\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/dice\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/transport/internet\"\n\t\"v2ray.com/core/transport/internet/tls\"\n\t\"v2ray.com/core/transport/internet/xtls\"\n)\n\nvar (\n\tglobalConv = uint32(dice.RollUint16())\n)\n\nfunc fetchInput(ctx context.Context, input io.Reader, reader PacketReader, conn *Connection) {\n\tcache := make(chan *buf.Buffer, 1024)\n\tgo func() {\n\t\tfor {\n\t\t\tpayload := buf.New()\n\t\t\tif _, err := payload.ReadFrom(input); err != nil {\n\t\t\t\tpayload.Release()\n\t\t\t\tclose(cache)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tselect {\n\t\t\tcase cache <- payload:\n\t\t\tdefault:\n\t\t\t\tpayload.Release()\n\t\t\t}\n\t\t}\n\t}()\n\n\tfor payload := range cache {\n\t\tsegments := reader.Read(payload.Bytes())\n\t\tpayload.Release()\n\t\tif len(segments) > 0 {\n\t\t\tconn.Input(segments)\n\t\t}\n\t}\n}\n\n// DialKCP dials a new KCP connections to the specific destination.\nfunc DialKCP(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (internet.Connection, error) {\n\tdest.Network = net.Network_UDP\n\tnewError(\"dialing mKCP to \", dest).WriteToLog()\n\n\trawConn, err := internet.DialSystem(ctx, dest, streamSettings.SocketSettings)\n\tif err != nil {\n\t\treturn nil, newError(\"failed to dial to dest: \", err).AtWarning().Base(err)\n\t}\n\n\tkcpSettings := streamSettings.ProtocolSettings.(*Config)\n\n\theader, err := kcpSettings.GetPackerHeader()\n\tif err != nil {\n\t\treturn nil, newError(\"failed to create packet header\").Base(err)\n\t}\n\tsecurity, err := kcpSettings.GetSecurity()\n\tif err != nil {\n\t\treturn nil, newError(\"failed to create security\").Base(err)\n\t}\n\treader := &KCPPacketReader{\n\t\tHeader:   header,\n\t\tSecurity: security,\n\t}\n\twriter := &KCPPacketWriter{\n\t\tHeader:   header,\n\t\tSecurity: security,\n\t\tWriter:   rawConn,\n\t}\n\n\tconv := uint16(atomic.AddUint32(&globalConv, 1))\n\tsession := NewConnection(ConnMetadata{\n\t\tLocalAddr:    rawConn.LocalAddr(),\n\t\tRemoteAddr:   rawConn.RemoteAddr(),\n\t\tConversation: conv,\n\t}, writer, rawConn, kcpSettings)\n\n\tgo fetchInput(ctx, rawConn, reader, session)\n\n\tvar iConn internet.Connection = session\n\n\tif config := tls.ConfigFromStreamSettings(streamSettings); config != nil {\n\t\tiConn = tls.Client(iConn, config.GetTLSConfig(tls.WithDestination(dest)))\n\t} else if config := xtls.ConfigFromStreamSettings(streamSettings); config != nil {\n\t\tiConn = xtls.Client(iConn, config.GetXTLSConfig(xtls.WithDestination(dest)))\n\t}\n\n\treturn iConn, nil\n}\n\nfunc init() {\n\tcommon.Must(internet.RegisterTransportDialer(protocolName, DialKCP))\n}\n"
  },
  {
    "path": "transport/internet/kcp/errors.generated.go",
    "content": "package kcp\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "transport/internet/kcp/io.go",
    "content": "// +build !confonly\n\npackage kcp\n\nimport (\n\t\"crypto/cipher\"\n\t\"crypto/rand\"\n\t\"io\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/transport/internet\"\n)\n\ntype PacketReader interface {\n\tRead([]byte) []Segment\n}\n\ntype PacketWriter interface {\n\tOverhead() int\n\tio.Writer\n}\n\ntype KCPPacketReader struct {\n\tSecurity cipher.AEAD\n\tHeader   internet.PacketHeader\n}\n\nfunc (r *KCPPacketReader) Read(b []byte) []Segment {\n\tif r.Header != nil {\n\t\tif int32(len(b)) <= r.Header.Size() {\n\t\t\treturn nil\n\t\t}\n\t\tb = b[r.Header.Size():]\n\t}\n\tif r.Security != nil {\n\t\tnonceSize := r.Security.NonceSize()\n\t\toverhead := r.Security.Overhead()\n\t\tif len(b) <= nonceSize+overhead {\n\t\t\treturn nil\n\t\t}\n\t\tout, err := r.Security.Open(b[nonceSize:nonceSize], b[:nonceSize], b[nonceSize:], nil)\n\t\tif err != nil {\n\t\t\treturn nil\n\t\t}\n\t\tb = out\n\t}\n\tvar result []Segment\n\tfor len(b) > 0 {\n\t\tseg, x := ReadSegment(b)\n\t\tif seg == nil {\n\t\t\tbreak\n\t\t}\n\t\tresult = append(result, seg)\n\t\tb = x\n\t}\n\treturn result\n}\n\ntype KCPPacketWriter struct {\n\tHeader   internet.PacketHeader\n\tSecurity cipher.AEAD\n\tWriter   io.Writer\n}\n\nfunc (w *KCPPacketWriter) Overhead() int {\n\toverhead := 0\n\tif w.Header != nil {\n\t\toverhead += int(w.Header.Size())\n\t}\n\tif w.Security != nil {\n\t\toverhead += w.Security.Overhead()\n\t}\n\treturn overhead\n}\n\nfunc (w *KCPPacketWriter) Write(b []byte) (int, error) {\n\tbb := buf.StackNew()\n\tdefer bb.Release()\n\n\tif w.Header != nil {\n\t\tw.Header.Serialize(bb.Extend(w.Header.Size()))\n\t}\n\tif w.Security != nil {\n\t\tnonceSize := w.Security.NonceSize()\n\t\tcommon.Must2(bb.ReadFullFrom(rand.Reader, int32(nonceSize)))\n\t\tnonce := bb.BytesFrom(int32(-nonceSize))\n\n\t\tencrypted := bb.Extend(int32(w.Security.Overhead() + len(b)))\n\t\tw.Security.Seal(encrypted[:0], nonce, b, nil)\n\t} else {\n\t\tbb.Write(b)\n\t}\n\n\t_, err := w.Writer.Write(bb.Bytes())\n\treturn len(b), err\n}\n"
  },
  {
    "path": "transport/internet/kcp/io_test.go",
    "content": "package kcp_test\n\nimport (\n\t\"testing\"\n\n\t. \"v2ray.com/core/transport/internet/kcp\"\n)\n\nfunc TestKCPPacketReader(t *testing.T) {\n\treader := KCPPacketReader{\n\t\tSecurity: &SimpleAuthenticator{},\n\t}\n\n\ttestCases := []struct {\n\t\tInput  []byte\n\t\tOutput []Segment\n\t}{\n\t\t{\n\t\t\tInput:  []byte{},\n\t\t\tOutput: nil,\n\t\t},\n\t\t{\n\t\t\tInput:  []byte{1},\n\t\t\tOutput: nil,\n\t\t},\n\t}\n\n\tfor _, testCase := range testCases {\n\t\tseg := reader.Read(testCase.Input)\n\t\tif testCase.Output == nil && seg != nil {\n\t\t\tt.Errorf(\"Expect nothing returned, but actually %v\", seg)\n\t\t} else if testCase.Output != nil && seg == nil {\n\t\t\tt.Errorf(\"Expect some output, but got nil\")\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "transport/internet/kcp/kcp.go",
    "content": "// Package kcp - A Fast and Reliable ARQ Protocol\n//\n// Acknowledgement:\n//    skywind3000@github for inventing the KCP protocol\n//    xtaci@github for translating to Golang\npackage kcp\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n"
  },
  {
    "path": "transport/internet/kcp/kcp_test.go",
    "content": "package kcp_test\n\nimport (\n\t\"context\"\n\t\"crypto/rand\"\n\t\"io\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"golang.org/x/sync/errgroup\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/errors\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/transport/internet\"\n\t. \"v2ray.com/core/transport/internet/kcp\"\n)\n\nfunc TestDialAndListen(t *testing.T) {\n\tlisterner, err := NewListener(context.Background(), net.LocalHostIP, net.Port(0), &internet.MemoryStreamConfig{\n\t\tProtocolName:     \"mkcp\",\n\t\tProtocolSettings: &Config{},\n\t}, func(conn internet.Connection) {\n\t\tgo func(c internet.Connection) {\n\t\t\tpayload := make([]byte, 4096)\n\t\t\tfor {\n\t\t\t\tnBytes, err := c.Read(payload)\n\t\t\t\tif err != nil {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tfor idx, b := range payload[:nBytes] {\n\t\t\t\t\tpayload[idx] = b ^ 'c'\n\t\t\t\t}\n\t\t\t\tc.Write(payload[:nBytes])\n\t\t\t}\n\t\t\tc.Close()\n\t\t}(conn)\n\t})\n\tcommon.Must(err)\n\tdefer listerner.Close()\n\n\tport := net.Port(listerner.Addr().(*net.UDPAddr).Port)\n\n\tvar errg errgroup.Group\n\tfor i := 0; i < 10; i++ {\n\t\terrg.Go(func() error {\n\t\t\tclientConn, err := DialKCP(context.Background(), net.UDPDestination(net.LocalHostIP, port), &internet.MemoryStreamConfig{\n\t\t\t\tProtocolName:     \"mkcp\",\n\t\t\t\tProtocolSettings: &Config{},\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tdefer clientConn.Close()\n\n\t\t\tclientSend := make([]byte, 1024*1024)\n\t\t\trand.Read(clientSend)\n\t\t\tgo clientConn.Write(clientSend)\n\n\t\t\tclientReceived := make([]byte, 1024*1024)\n\t\t\tcommon.Must2(io.ReadFull(clientConn, clientReceived))\n\n\t\t\tclientExpected := make([]byte, 1024*1024)\n\t\t\tfor idx, b := range clientSend {\n\t\t\t\tclientExpected[idx] = b ^ 'c'\n\t\t\t}\n\t\t\tif r := cmp.Diff(clientReceived, clientExpected); r != \"\" {\n\t\t\t\treturn errors.New(r)\n\t\t\t}\n\t\t\treturn nil\n\t\t})\n\t}\n\n\tif err := errg.Wait(); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tfor i := 0; i < 60 && listerner.ActiveConnections() > 0; i++ {\n\t\ttime.Sleep(500 * time.Millisecond)\n\t}\n\tif v := listerner.ActiveConnections(); v != 0 {\n\t\tt.Error(\"active connections: \", v)\n\t}\n}\n"
  },
  {
    "path": "transport/internet/kcp/listener.go",
    "content": "// +build !confonly\n\npackage kcp\n\nimport (\n\t\"context\"\n\t\"crypto/cipher\"\n\tgotls \"crypto/tls\"\n\t\"sync\"\n\n\tgoxtls \"github.com/xtls/go\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/transport/internet\"\n\t\"v2ray.com/core/transport/internet/tls\"\n\t\"v2ray.com/core/transport/internet/udp\"\n\t\"v2ray.com/core/transport/internet/xtls\"\n)\n\ntype ConnectionID struct {\n\tRemote net.Address\n\tPort   net.Port\n\tConv   uint16\n}\n\n// Listener defines a server listening for connections\ntype Listener struct {\n\tsync.Mutex\n\tsessions   map[ConnectionID]*Connection\n\thub        *udp.Hub\n\ttlsConfig  *gotls.Config\n\txtlsConfig *goxtls.Config\n\tconfig     *Config\n\treader     PacketReader\n\theader     internet.PacketHeader\n\tsecurity   cipher.AEAD\n\taddConn    internet.ConnHandler\n}\n\nfunc NewListener(ctx context.Context, address net.Address, port net.Port, streamSettings *internet.MemoryStreamConfig, addConn internet.ConnHandler) (*Listener, error) {\n\tkcpSettings := streamSettings.ProtocolSettings.(*Config)\n\theader, err := kcpSettings.GetPackerHeader()\n\tif err != nil {\n\t\treturn nil, newError(\"failed to create packet header\").Base(err).AtError()\n\t}\n\tsecurity, err := kcpSettings.GetSecurity()\n\tif err != nil {\n\t\treturn nil, newError(\"failed to create security\").Base(err).AtError()\n\t}\n\tl := &Listener{\n\t\theader:   header,\n\t\tsecurity: security,\n\t\treader: &KCPPacketReader{\n\t\t\tHeader:   header,\n\t\t\tSecurity: security,\n\t\t},\n\t\tsessions: make(map[ConnectionID]*Connection),\n\t\tconfig:   kcpSettings,\n\t\taddConn:  addConn,\n\t}\n\n\tif config := tls.ConfigFromStreamSettings(streamSettings); config != nil {\n\t\tl.tlsConfig = config.GetTLSConfig()\n\t}\n\tif config := xtls.ConfigFromStreamSettings(streamSettings); config != nil {\n\t\tl.xtlsConfig = config.GetXTLSConfig()\n\t}\n\n\thub, err := udp.ListenUDP(ctx, address, port, streamSettings, udp.HubCapacity(1024))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tl.Lock()\n\tl.hub = hub\n\tl.Unlock()\n\tnewError(\"listening on \", address, \":\", port).WriteToLog()\n\n\tgo l.handlePackets()\n\n\treturn l, nil\n}\n\nfunc (l *Listener) handlePackets() {\n\treceive := l.hub.Receive()\n\tfor payload := range receive {\n\t\tl.OnReceive(payload.Payload, payload.Source)\n\t}\n}\n\nfunc (l *Listener) OnReceive(payload *buf.Buffer, src net.Destination) {\n\tsegments := l.reader.Read(payload.Bytes())\n\tpayload.Release()\n\n\tif len(segments) == 0 {\n\t\tnewError(\"discarding invalid payload from \", src).WriteToLog()\n\t\treturn\n\t}\n\n\tconv := segments[0].Conversation()\n\tcmd := segments[0].Command()\n\n\tid := ConnectionID{\n\t\tRemote: src.Address,\n\t\tPort:   src.Port,\n\t\tConv:   conv,\n\t}\n\n\tl.Lock()\n\tdefer l.Unlock()\n\n\tconn, found := l.sessions[id]\n\n\tif !found {\n\t\tif cmd == CommandTerminate {\n\t\t\treturn\n\t\t}\n\t\twriter := &Writer{\n\t\t\tid:       id,\n\t\t\thub:      l.hub,\n\t\t\tdest:     src,\n\t\t\tlistener: l,\n\t\t}\n\t\tremoteAddr := &net.UDPAddr{\n\t\t\tIP:   src.Address.IP(),\n\t\t\tPort: int(src.Port),\n\t\t}\n\t\tlocalAddr := l.hub.Addr()\n\t\tconn = NewConnection(ConnMetadata{\n\t\t\tLocalAddr:    localAddr,\n\t\t\tRemoteAddr:   remoteAddr,\n\t\t\tConversation: conv,\n\t\t}, &KCPPacketWriter{\n\t\t\tHeader:   l.header,\n\t\t\tSecurity: l.security,\n\t\t\tWriter:   writer,\n\t\t}, writer, l.config)\n\t\tvar netConn internet.Connection = conn\n\t\tif l.tlsConfig != nil {\n\t\t\tnetConn = gotls.Server(conn, l.tlsConfig)\n\t\t} else if l.xtlsConfig != nil {\n\t\t\tnetConn = goxtls.Server(conn, l.xtlsConfig)\n\t\t}\n\n\t\tl.addConn(netConn)\n\t\tl.sessions[id] = conn\n\t}\n\tconn.Input(segments)\n}\n\nfunc (l *Listener) Remove(id ConnectionID) {\n\tl.Lock()\n\tdelete(l.sessions, id)\n\tl.Unlock()\n}\n\n// Close stops listening on the UDP address. Already Accepted connections are not closed.\nfunc (l *Listener) Close() error {\n\tl.hub.Close()\n\n\tl.Lock()\n\tdefer l.Unlock()\n\n\tfor _, conn := range l.sessions {\n\t\tgo conn.Terminate()\n\t}\n\n\treturn nil\n}\n\nfunc (l *Listener) ActiveConnections() int {\n\tl.Lock()\n\tdefer l.Unlock()\n\n\treturn len(l.sessions)\n}\n\n// Addr returns the listener's network address, The Addr returned is shared by all invocations of Addr, so do not modify it.\nfunc (l *Listener) Addr() net.Addr {\n\treturn l.hub.Addr()\n}\n\ntype Writer struct {\n\tid       ConnectionID\n\tdest     net.Destination\n\thub      *udp.Hub\n\tlistener *Listener\n}\n\nfunc (w *Writer) Write(payload []byte) (int, error) {\n\treturn w.hub.WriteTo(payload, w.dest)\n}\n\nfunc (w *Writer) Close() error {\n\tw.listener.Remove(w.id)\n\treturn nil\n}\n\nfunc ListenKCP(ctx context.Context, address net.Address, port net.Port, streamSettings *internet.MemoryStreamConfig, addConn internet.ConnHandler) (internet.Listener, error) {\n\treturn NewListener(ctx, address, port, streamSettings, addConn)\n}\n\nfunc init() {\n\tcommon.Must(internet.RegisterTransportListener(protocolName, ListenKCP))\n}\n"
  },
  {
    "path": "transport/internet/kcp/output.go",
    "content": "// +build !confonly\n\npackage kcp\n\nimport (\n\t\"io\"\n\t\"sync\"\n\n\t\"v2ray.com/core/common/retry\"\n\n\t\"v2ray.com/core/common/buf\"\n)\n\ntype SegmentWriter interface {\n\tWrite(seg Segment) error\n}\n\ntype SimpleSegmentWriter struct {\n\tsync.Mutex\n\tbuffer *buf.Buffer\n\twriter io.Writer\n}\n\nfunc NewSegmentWriter(writer io.Writer) SegmentWriter {\n\treturn &SimpleSegmentWriter{\n\t\twriter: writer,\n\t\tbuffer: buf.New(),\n\t}\n}\n\nfunc (w *SimpleSegmentWriter) Write(seg Segment) error {\n\tw.Lock()\n\tdefer w.Unlock()\n\n\tw.buffer.Clear()\n\trawBytes := w.buffer.Extend(seg.ByteSize())\n\tseg.Serialize(rawBytes)\n\t_, err := w.writer.Write(w.buffer.Bytes())\n\treturn err\n}\n\ntype RetryableWriter struct {\n\twriter SegmentWriter\n}\n\nfunc NewRetryableWriter(writer SegmentWriter) SegmentWriter {\n\treturn &RetryableWriter{\n\t\twriter: writer,\n\t}\n}\n\nfunc (w *RetryableWriter) Write(seg Segment) error {\n\treturn retry.Timed(5, 100).On(func() error {\n\t\treturn w.writer.Write(seg)\n\t})\n}\n"
  },
  {
    "path": "transport/internet/kcp/receiving.go",
    "content": "// +build !confonly\n\npackage kcp\n\nimport (\n\t\"sync\"\n\n\t\"v2ray.com/core/common/buf\"\n)\n\ntype ReceivingWindow struct {\n\tcache map[uint32]*DataSegment\n}\n\nfunc NewReceivingWindow() *ReceivingWindow {\n\treturn &ReceivingWindow{\n\t\tcache: make(map[uint32]*DataSegment),\n\t}\n}\n\nfunc (w *ReceivingWindow) Set(id uint32, value *DataSegment) bool {\n\t_, f := w.cache[id]\n\tif f {\n\t\treturn false\n\t}\n\tw.cache[id] = value\n\treturn true\n}\n\nfunc (w *ReceivingWindow) Has(id uint32) bool {\n\t_, f := w.cache[id]\n\treturn f\n}\n\nfunc (w *ReceivingWindow) Remove(id uint32) *DataSegment {\n\tv, f := w.cache[id]\n\tif !f {\n\t\treturn nil\n\t}\n\tdelete(w.cache, id)\n\treturn v\n}\n\ntype AckList struct {\n\twriter     SegmentWriter\n\ttimestamps []uint32\n\tnumbers    []uint32\n\tnextFlush  []uint32\n\n\tflushCandidates []uint32\n\tdirty           bool\n}\n\nfunc NewAckList(writer SegmentWriter) *AckList {\n\treturn &AckList{\n\t\twriter:          writer,\n\t\ttimestamps:      make([]uint32, 0, 128),\n\t\tnumbers:         make([]uint32, 0, 128),\n\t\tnextFlush:       make([]uint32, 0, 128),\n\t\tflushCandidates: make([]uint32, 0, 128),\n\t}\n}\n\nfunc (l *AckList) Add(number uint32, timestamp uint32) {\n\tl.timestamps = append(l.timestamps, timestamp)\n\tl.numbers = append(l.numbers, number)\n\tl.nextFlush = append(l.nextFlush, 0)\n\tl.dirty = true\n}\n\nfunc (l *AckList) Clear(una uint32) {\n\tcount := 0\n\tfor i := 0; i < len(l.numbers); i++ {\n\t\tif l.numbers[i] < una {\n\t\t\tcontinue\n\t\t}\n\t\tif i != count {\n\t\t\tl.numbers[count] = l.numbers[i]\n\t\t\tl.timestamps[count] = l.timestamps[i]\n\t\t\tl.nextFlush[count] = l.nextFlush[i]\n\t\t}\n\t\tcount++\n\t}\n\tif count < len(l.numbers) {\n\t\tl.numbers = l.numbers[:count]\n\t\tl.timestamps = l.timestamps[:count]\n\t\tl.nextFlush = l.nextFlush[:count]\n\t\tl.dirty = true\n\t}\n}\n\nfunc (l *AckList) Flush(current uint32, rto uint32) {\n\tl.flushCandidates = l.flushCandidates[:0]\n\n\tseg := NewAckSegment()\n\tfor i := 0; i < len(l.numbers); i++ {\n\t\tif l.nextFlush[i] > current {\n\t\t\tif len(l.flushCandidates) < cap(l.flushCandidates) {\n\t\t\t\tl.flushCandidates = append(l.flushCandidates, l.numbers[i])\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tseg.PutNumber(l.numbers[i])\n\t\tseg.PutTimestamp(l.timestamps[i])\n\t\ttimeout := rto / 2\n\t\tif timeout < 20 {\n\t\t\ttimeout = 20\n\t\t}\n\t\tl.nextFlush[i] = current + timeout\n\n\t\tif seg.IsFull() {\n\t\t\tl.writer.Write(seg)\n\t\t\tseg.Release()\n\t\t\tseg = NewAckSegment()\n\t\t\tl.dirty = false\n\t\t}\n\t}\n\n\tif l.dirty || !seg.IsEmpty() {\n\t\tfor _, number := range l.flushCandidates {\n\t\t\tif seg.IsFull() {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tseg.PutNumber(number)\n\t\t}\n\t\tl.writer.Write(seg)\n\t\tl.dirty = false\n\t}\n\n\tseg.Release()\n}\n\ntype ReceivingWorker struct {\n\tsync.RWMutex\n\tconn       *Connection\n\tleftOver   buf.MultiBuffer\n\twindow     *ReceivingWindow\n\tacklist    *AckList\n\tnextNumber uint32\n\twindowSize uint32\n}\n\nfunc NewReceivingWorker(kcp *Connection) *ReceivingWorker {\n\tworker := &ReceivingWorker{\n\t\tconn:       kcp,\n\t\twindow:     NewReceivingWindow(),\n\t\twindowSize: kcp.Config.GetReceivingInFlightSize(),\n\t}\n\tworker.acklist = NewAckList(worker)\n\treturn worker\n}\n\nfunc (w *ReceivingWorker) Release() {\n\tw.Lock()\n\tbuf.ReleaseMulti(w.leftOver)\n\tw.leftOver = nil\n\tw.Unlock()\n}\n\nfunc (w *ReceivingWorker) ProcessSendingNext(number uint32) {\n\tw.Lock()\n\tdefer w.Unlock()\n\n\tw.acklist.Clear(number)\n}\n\nfunc (w *ReceivingWorker) ProcessSegment(seg *DataSegment) {\n\tw.Lock()\n\tdefer w.Unlock()\n\n\tnumber := seg.Number\n\tidx := number - w.nextNumber\n\tif idx >= w.windowSize {\n\t\treturn\n\t}\n\tw.acklist.Clear(seg.SendingNext)\n\tw.acklist.Add(number, seg.Timestamp)\n\n\tif !w.window.Set(seg.Number, seg) {\n\t\tseg.Release()\n\t}\n}\n\nfunc (w *ReceivingWorker) ReadMultiBuffer() buf.MultiBuffer {\n\tif w.leftOver != nil {\n\t\tmb := w.leftOver\n\t\tw.leftOver = nil\n\t\treturn mb\n\t}\n\n\tmb := make(buf.MultiBuffer, 0, 32)\n\n\tw.Lock()\n\tdefer w.Unlock()\n\tfor {\n\t\tseg := w.window.Remove(w.nextNumber)\n\t\tif seg == nil {\n\t\t\tbreak\n\t\t}\n\t\tw.nextNumber++\n\t\tmb = append(mb, seg.Detach())\n\t\tseg.Release()\n\t}\n\n\treturn mb\n}\n\nfunc (w *ReceivingWorker) Read(b []byte) int {\n\tmb := w.ReadMultiBuffer()\n\tif mb.IsEmpty() {\n\t\treturn 0\n\t}\n\tmb, nBytes := buf.SplitBytes(mb, b)\n\tif !mb.IsEmpty() {\n\t\tw.leftOver = mb\n\t}\n\treturn nBytes\n}\n\nfunc (w *ReceivingWorker) IsDataAvailable() bool {\n\tw.RLock()\n\tdefer w.RUnlock()\n\treturn w.window.Has(w.nextNumber)\n}\n\nfunc (w *ReceivingWorker) NextNumber() uint32 {\n\tw.RLock()\n\tdefer w.RUnlock()\n\n\treturn w.nextNumber\n}\n\nfunc (w *ReceivingWorker) Flush(current uint32) {\n\tw.Lock()\n\tdefer w.Unlock()\n\n\tw.acklist.Flush(current, w.conn.roundTrip.Timeout())\n}\n\nfunc (w *ReceivingWorker) Write(seg Segment) error {\n\tackSeg := seg.(*AckSegment)\n\tackSeg.Conv = w.conn.meta.Conversation\n\tackSeg.ReceivingNext = w.nextNumber\n\tackSeg.ReceivingWindow = w.nextNumber + w.windowSize\n\tackSeg.Option = 0\n\tif w.conn.State() == StateReadyToClose {\n\t\tackSeg.Option = SegmentOptionClose\n\t}\n\treturn w.conn.output.Write(ackSeg)\n}\n\nfunc (*ReceivingWorker) CloseRead() {\n}\n\nfunc (w *ReceivingWorker) UpdateNecessary() bool {\n\tw.RLock()\n\tdefer w.RUnlock()\n\n\treturn len(w.acklist.numbers) > 0\n}\n"
  },
  {
    "path": "transport/internet/kcp/segment.go",
    "content": "// +build !confonly\n\npackage kcp\n\nimport (\n\t\"encoding/binary\"\n\n\t\"v2ray.com/core/common/buf\"\n)\n\n// Command is a KCP command that indicate the purpose of a Segment.\ntype Command byte\n\nconst (\n\t// CommandACK indicates an AckSegment.\n\tCommandACK Command = 0\n\t// CommandData indicates a DataSegment.\n\tCommandData Command = 1\n\t// CommandTerminate indicates that peer terminates the connection.\n\tCommandTerminate Command = 2\n\t// CommandPing indicates a ping.\n\tCommandPing Command = 3\n)\n\ntype SegmentOption byte\n\nconst (\n\tSegmentOptionClose SegmentOption = 1\n)\n\ntype Segment interface {\n\tRelease()\n\tConversation() uint16\n\tCommand() Command\n\tByteSize() int32\n\tSerialize([]byte)\n\tparse(conv uint16, cmd Command, opt SegmentOption, buf []byte) (bool, []byte)\n}\n\nconst (\n\tDataSegmentOverhead = 18\n)\n\ntype DataSegment struct {\n\tConv        uint16\n\tOption      SegmentOption\n\tTimestamp   uint32\n\tNumber      uint32\n\tSendingNext uint32\n\n\tpayload  *buf.Buffer\n\ttimeout  uint32\n\ttransmit uint32\n}\n\nfunc NewDataSegment() *DataSegment {\n\treturn new(DataSegment)\n}\n\nfunc (s *DataSegment) parse(conv uint16, cmd Command, opt SegmentOption, buf []byte) (bool, []byte) {\n\ts.Conv = conv\n\ts.Option = opt\n\tif len(buf) < 15 {\n\t\treturn false, nil\n\t}\n\ts.Timestamp = binary.BigEndian.Uint32(buf)\n\tbuf = buf[4:]\n\n\ts.Number = binary.BigEndian.Uint32(buf)\n\tbuf = buf[4:]\n\n\ts.SendingNext = binary.BigEndian.Uint32(buf)\n\tbuf = buf[4:]\n\n\tdataLen := int(binary.BigEndian.Uint16(buf))\n\tbuf = buf[2:]\n\n\tif len(buf) < dataLen {\n\t\treturn false, nil\n\t}\n\ts.Data().Clear()\n\ts.Data().Write(buf[:dataLen])\n\tbuf = buf[dataLen:]\n\n\treturn true, buf\n}\n\nfunc (s *DataSegment) Conversation() uint16 {\n\treturn s.Conv\n}\n\nfunc (*DataSegment) Command() Command {\n\treturn CommandData\n}\n\nfunc (s *DataSegment) Detach() *buf.Buffer {\n\tr := s.payload\n\ts.payload = nil\n\treturn r\n}\n\nfunc (s *DataSegment) Data() *buf.Buffer {\n\tif s.payload == nil {\n\t\ts.payload = buf.New()\n\t}\n\treturn s.payload\n}\n\nfunc (s *DataSegment) Serialize(b []byte) {\n\tbinary.BigEndian.PutUint16(b, s.Conv)\n\tb[2] = byte(CommandData)\n\tb[3] = byte(s.Option)\n\tbinary.BigEndian.PutUint32(b[4:], s.Timestamp)\n\tbinary.BigEndian.PutUint32(b[8:], s.Number)\n\tbinary.BigEndian.PutUint32(b[12:], s.SendingNext)\n\tbinary.BigEndian.PutUint16(b[16:], uint16(s.payload.Len()))\n\tcopy(b[18:], s.payload.Bytes())\n}\n\nfunc (s *DataSegment) ByteSize() int32 {\n\treturn 2 + 1 + 1 + 4 + 4 + 4 + 2 + s.payload.Len()\n}\n\nfunc (s *DataSegment) Release() {\n\ts.payload.Release()\n\ts.payload = nil\n}\n\ntype AckSegment struct {\n\tConv            uint16\n\tOption          SegmentOption\n\tReceivingWindow uint32\n\tReceivingNext   uint32\n\tTimestamp       uint32\n\tNumberList      []uint32\n}\n\nconst ackNumberLimit = 128\n\nfunc NewAckSegment() *AckSegment {\n\treturn new(AckSegment)\n}\n\nfunc (s *AckSegment) parse(conv uint16, cmd Command, opt SegmentOption, buf []byte) (bool, []byte) {\n\ts.Conv = conv\n\ts.Option = opt\n\tif len(buf) < 13 {\n\t\treturn false, nil\n\t}\n\n\ts.ReceivingWindow = binary.BigEndian.Uint32(buf)\n\tbuf = buf[4:]\n\n\ts.ReceivingNext = binary.BigEndian.Uint32(buf)\n\tbuf = buf[4:]\n\n\ts.Timestamp = binary.BigEndian.Uint32(buf)\n\tbuf = buf[4:]\n\n\tcount := int(buf[0])\n\tbuf = buf[1:]\n\n\tif len(buf) < count*4 {\n\t\treturn false, nil\n\t}\n\tfor i := 0; i < count; i++ {\n\t\ts.PutNumber(binary.BigEndian.Uint32(buf))\n\t\tbuf = buf[4:]\n\t}\n\n\treturn true, buf\n}\n\nfunc (s *AckSegment) Conversation() uint16 {\n\treturn s.Conv\n}\n\nfunc (*AckSegment) Command() Command {\n\treturn CommandACK\n}\n\nfunc (s *AckSegment) PutTimestamp(timestamp uint32) {\n\tif timestamp-s.Timestamp < 0x7FFFFFFF {\n\t\ts.Timestamp = timestamp\n\t}\n}\n\nfunc (s *AckSegment) PutNumber(number uint32) {\n\ts.NumberList = append(s.NumberList, number)\n}\n\nfunc (s *AckSegment) IsFull() bool {\n\treturn len(s.NumberList) == ackNumberLimit\n}\n\nfunc (s *AckSegment) IsEmpty() bool {\n\treturn len(s.NumberList) == 0\n}\n\nfunc (s *AckSegment) ByteSize() int32 {\n\treturn 2 + 1 + 1 + 4 + 4 + 4 + 1 + int32(len(s.NumberList)*4)\n}\n\nfunc (s *AckSegment) Serialize(b []byte) {\n\tbinary.BigEndian.PutUint16(b, s.Conv)\n\tb[2] = byte(CommandACK)\n\tb[3] = byte(s.Option)\n\tbinary.BigEndian.PutUint32(b[4:], s.ReceivingWindow)\n\tbinary.BigEndian.PutUint32(b[8:], s.ReceivingNext)\n\tbinary.BigEndian.PutUint32(b[12:], s.Timestamp)\n\tb[16] = byte(len(s.NumberList))\n\tn := 17\n\tfor _, number := range s.NumberList {\n\t\tbinary.BigEndian.PutUint32(b[n:], number)\n\t\tn += 4\n\t}\n}\n\nfunc (s *AckSegment) Release() {}\n\ntype CmdOnlySegment struct {\n\tConv          uint16\n\tCmd           Command\n\tOption        SegmentOption\n\tSendingNext   uint32\n\tReceivingNext uint32\n\tPeerRTO       uint32\n}\n\nfunc NewCmdOnlySegment() *CmdOnlySegment {\n\treturn new(CmdOnlySegment)\n}\n\nfunc (s *CmdOnlySegment) parse(conv uint16, cmd Command, opt SegmentOption, buf []byte) (bool, []byte) {\n\ts.Conv = conv\n\ts.Cmd = cmd\n\ts.Option = opt\n\n\tif len(buf) < 12 {\n\t\treturn false, nil\n\t}\n\n\ts.SendingNext = binary.BigEndian.Uint32(buf)\n\tbuf = buf[4:]\n\n\ts.ReceivingNext = binary.BigEndian.Uint32(buf)\n\tbuf = buf[4:]\n\n\ts.PeerRTO = binary.BigEndian.Uint32(buf)\n\tbuf = buf[4:]\n\n\treturn true, buf\n}\n\nfunc (s *CmdOnlySegment) Conversation() uint16 {\n\treturn s.Conv\n}\n\nfunc (s *CmdOnlySegment) Command() Command {\n\treturn s.Cmd\n}\n\nfunc (*CmdOnlySegment) ByteSize() int32 {\n\treturn 2 + 1 + 1 + 4 + 4 + 4\n}\n\nfunc (s *CmdOnlySegment) Serialize(b []byte) {\n\tbinary.BigEndian.PutUint16(b, s.Conv)\n\tb[2] = byte(s.Cmd)\n\tb[3] = byte(s.Option)\n\tbinary.BigEndian.PutUint32(b[4:], s.SendingNext)\n\tbinary.BigEndian.PutUint32(b[8:], s.ReceivingNext)\n\tbinary.BigEndian.PutUint32(b[12:], s.PeerRTO)\n}\n\nfunc (*CmdOnlySegment) Release() {}\n\nfunc ReadSegment(buf []byte) (Segment, []byte) {\n\tif len(buf) < 4 {\n\t\treturn nil, nil\n\t}\n\n\tconv := binary.BigEndian.Uint16(buf)\n\tbuf = buf[2:]\n\n\tcmd := Command(buf[0])\n\topt := SegmentOption(buf[1])\n\tbuf = buf[2:]\n\n\tvar seg Segment\n\tswitch cmd {\n\tcase CommandData:\n\t\tseg = NewDataSegment()\n\tcase CommandACK:\n\t\tseg = NewAckSegment()\n\tdefault:\n\t\tseg = NewCmdOnlySegment()\n\t}\n\n\tvalid, extra := seg.parse(conv, cmd, opt, buf)\n\tif !valid {\n\t\treturn nil, nil\n\t}\n\treturn seg, extra\n}\n"
  },
  {
    "path": "transport/internet/kcp/segment_test.go",
    "content": "package kcp_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/google/go-cmp/cmp/cmpopts\"\n\n\t. \"v2ray.com/core/transport/internet/kcp\"\n)\n\nfunc TestBadSegment(t *testing.T) {\n\tseg, buf := ReadSegment(nil)\n\tif seg != nil {\n\t\tt.Error(\"non-nil seg\")\n\t}\n\tif len(buf) != 0 {\n\t\tt.Error(\"buf len: \", len(buf))\n\t}\n}\n\nfunc TestDataSegment(t *testing.T) {\n\tseg := &DataSegment{\n\t\tConv:        1,\n\t\tTimestamp:   3,\n\t\tNumber:      4,\n\t\tSendingNext: 5,\n\t}\n\tseg.Data().Write([]byte{'a', 'b', 'c', 'd'})\n\n\tnBytes := seg.ByteSize()\n\tbytes := make([]byte, nBytes)\n\tseg.Serialize(bytes)\n\n\tiseg, _ := ReadSegment(bytes)\n\tseg2 := iseg.(*DataSegment)\n\tif r := cmp.Diff(seg2, seg, cmpopts.IgnoreUnexported(DataSegment{})); r != \"\" {\n\t\tt.Error(r)\n\t}\n\tif r := cmp.Diff(seg2.Data().Bytes(), seg.Data().Bytes()); r != \"\" {\n\t\tt.Error(r)\n\t}\n}\n\nfunc Test1ByteDataSegment(t *testing.T) {\n\tseg := &DataSegment{\n\t\tConv:        1,\n\t\tTimestamp:   3,\n\t\tNumber:      4,\n\t\tSendingNext: 5,\n\t}\n\tseg.Data().WriteByte('a')\n\n\tnBytes := seg.ByteSize()\n\tbytes := make([]byte, nBytes)\n\tseg.Serialize(bytes)\n\n\tiseg, _ := ReadSegment(bytes)\n\tseg2 := iseg.(*DataSegment)\n\tif r := cmp.Diff(seg2, seg, cmpopts.IgnoreUnexported(DataSegment{})); r != \"\" {\n\t\tt.Error(r)\n\t}\n\tif r := cmp.Diff(seg2.Data().Bytes(), seg.Data().Bytes()); r != \"\" {\n\t\tt.Error(r)\n\t}\n}\n\nfunc TestACKSegment(t *testing.T) {\n\tseg := &AckSegment{\n\t\tConv:            1,\n\t\tReceivingWindow: 2,\n\t\tReceivingNext:   3,\n\t\tTimestamp:       10,\n\t\tNumberList:      []uint32{1, 3, 5, 7, 9},\n\t}\n\n\tnBytes := seg.ByteSize()\n\tbytes := make([]byte, nBytes)\n\tseg.Serialize(bytes)\n\n\tiseg, _ := ReadSegment(bytes)\n\tseg2 := iseg.(*AckSegment)\n\tif r := cmp.Diff(seg2, seg); r != \"\" {\n\t\tt.Error(r)\n\t}\n}\n\nfunc TestCmdSegment(t *testing.T) {\n\tseg := &CmdOnlySegment{\n\t\tConv:          1,\n\t\tCmd:           CommandPing,\n\t\tOption:        SegmentOptionClose,\n\t\tSendingNext:   11,\n\t\tReceivingNext: 13,\n\t\tPeerRTO:       15,\n\t}\n\n\tnBytes := seg.ByteSize()\n\tbytes := make([]byte, nBytes)\n\tseg.Serialize(bytes)\n\n\tiseg, _ := ReadSegment(bytes)\n\tseg2 := iseg.(*CmdOnlySegment)\n\tif r := cmp.Diff(seg2, seg); r != \"\" {\n\t\tt.Error(r)\n\t}\n}\n"
  },
  {
    "path": "transport/internet/kcp/sending.go",
    "content": "// +build !confonly\n\npackage kcp\n\nimport (\n\t\"container/list\"\n\t\"sync\"\n\n\t\"v2ray.com/core/common/buf\"\n)\n\ntype SendingWindow struct {\n\tcache             *list.List\n\ttotalInFlightSize uint32\n\twriter            SegmentWriter\n\tonPacketLoss      func(uint32)\n}\n\nfunc NewSendingWindow(writer SegmentWriter, onPacketLoss func(uint32)) *SendingWindow {\n\twindow := &SendingWindow{\n\t\tcache:        list.New(),\n\t\twriter:       writer,\n\t\tonPacketLoss: onPacketLoss,\n\t}\n\treturn window\n}\n\nfunc (sw *SendingWindow) Release() {\n\tif sw == nil {\n\t\treturn\n\t}\n\tfor sw.cache.Len() > 0 {\n\t\tseg := sw.cache.Front().Value.(*DataSegment)\n\t\tseg.Release()\n\t\tsw.cache.Remove(sw.cache.Front())\n\t}\n}\n\nfunc (sw *SendingWindow) Len() uint32 {\n\treturn uint32(sw.cache.Len())\n}\n\nfunc (sw *SendingWindow) IsEmpty() bool {\n\treturn sw.cache.Len() == 0\n}\n\nfunc (sw *SendingWindow) Push(number uint32, b *buf.Buffer) {\n\tseg := NewDataSegment()\n\tseg.Number = number\n\tseg.payload = b\n\n\tsw.cache.PushBack(seg)\n}\n\nfunc (sw *SendingWindow) FirstNumber() uint32 {\n\treturn sw.cache.Front().Value.(*DataSegment).Number\n}\n\nfunc (sw *SendingWindow) Clear(una uint32) {\n\tfor !sw.IsEmpty() {\n\t\tseg := sw.cache.Front().Value.(*DataSegment)\n\t\tif seg.Number >= una {\n\t\t\tbreak\n\t\t}\n\t\tseg.Release()\n\t\tsw.cache.Remove(sw.cache.Front())\n\t}\n}\n\nfunc (sw *SendingWindow) HandleFastAck(number uint32, rto uint32) {\n\tif sw.IsEmpty() {\n\t\treturn\n\t}\n\n\tsw.Visit(func(seg *DataSegment) bool {\n\t\tif number == seg.Number || number-seg.Number > 0x7FFFFFFF {\n\t\t\treturn false\n\t\t}\n\n\t\tif seg.transmit > 0 && seg.timeout > rto/3 {\n\t\t\tseg.timeout -= rto / 3\n\t\t}\n\t\treturn true\n\t})\n}\n\nfunc (sw *SendingWindow) Visit(visitor func(seg *DataSegment) bool) {\n\tif sw.IsEmpty() {\n\t\treturn\n\t}\n\n\tfor e := sw.cache.Front(); e != nil; e = e.Next() {\n\t\tseg := e.Value.(*DataSegment)\n\t\tif !visitor(seg) {\n\t\t\tbreak\n\t\t}\n\t}\n}\n\nfunc (sw *SendingWindow) Flush(current uint32, rto uint32, maxInFlightSize uint32) {\n\tif sw.IsEmpty() {\n\t\treturn\n\t}\n\n\tvar lost uint32\n\tvar inFlightSize uint32\n\n\tsw.Visit(func(segment *DataSegment) bool {\n\t\tif current-segment.timeout >= 0x7FFFFFFF {\n\t\t\treturn true\n\t\t}\n\t\tif segment.transmit == 0 {\n\t\t\t// First time\n\t\t\tsw.totalInFlightSize++\n\t\t} else {\n\t\t\tlost++\n\t\t}\n\t\tsegment.timeout = current + rto\n\n\t\tsegment.Timestamp = current\n\t\tsegment.transmit++\n\t\tsw.writer.Write(segment)\n\t\tinFlightSize++\n\t\treturn inFlightSize < maxInFlightSize\n\t})\n\n\tif sw.onPacketLoss != nil && inFlightSize > 0 && sw.totalInFlightSize != 0 {\n\t\trate := lost * 100 / sw.totalInFlightSize\n\t\tsw.onPacketLoss(rate)\n\t}\n}\n\nfunc (sw *SendingWindow) Remove(number uint32) bool {\n\tif sw.IsEmpty() {\n\t\treturn false\n\t}\n\n\tfor e := sw.cache.Front(); e != nil; e = e.Next() {\n\t\tseg := e.Value.(*DataSegment)\n\t\tif seg.Number > number {\n\t\t\treturn false\n\t\t} else if seg.Number == number {\n\t\t\tif sw.totalInFlightSize > 0 {\n\t\t\t\tsw.totalInFlightSize--\n\t\t\t}\n\t\t\tseg.Release()\n\t\t\tsw.cache.Remove(e)\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\ntype SendingWorker struct {\n\tsync.RWMutex\n\tconn                       *Connection\n\twindow                     *SendingWindow\n\tfirstUnacknowledged        uint32\n\tnextNumber                 uint32\n\tremoteNextNumber           uint32\n\tcontrolWindow              uint32\n\tfastResend                 uint32\n\twindowSize                 uint32\n\tfirstUnacknowledgedUpdated bool\n\tclosed                     bool\n}\n\nfunc NewSendingWorker(kcp *Connection) *SendingWorker {\n\tworker := &SendingWorker{\n\t\tconn:             kcp,\n\t\tfastResend:       2,\n\t\tremoteNextNumber: 32,\n\t\tcontrolWindow:    kcp.Config.GetSendingInFlightSize(),\n\t\twindowSize:       kcp.Config.GetSendingBufferSize(),\n\t}\n\tworker.window = NewSendingWindow(worker, worker.OnPacketLoss)\n\treturn worker\n}\n\nfunc (w *SendingWorker) Release() {\n\tw.Lock()\n\tw.window.Release()\n\tw.closed = true\n\tw.Unlock()\n}\n\nfunc (w *SendingWorker) ProcessReceivingNext(nextNumber uint32) {\n\tw.Lock()\n\tdefer w.Unlock()\n\n\tw.ProcessReceivingNextWithoutLock(nextNumber)\n}\n\nfunc (w *SendingWorker) ProcessReceivingNextWithoutLock(nextNumber uint32) {\n\tw.window.Clear(nextNumber)\n\tw.FindFirstUnacknowledged()\n}\n\nfunc (w *SendingWorker) FindFirstUnacknowledged() {\n\tfirst := w.firstUnacknowledged\n\tif !w.window.IsEmpty() {\n\t\tw.firstUnacknowledged = w.window.FirstNumber()\n\t} else {\n\t\tw.firstUnacknowledged = w.nextNumber\n\t}\n\tif first != w.firstUnacknowledged {\n\t\tw.firstUnacknowledgedUpdated = true\n\t}\n}\n\nfunc (w *SendingWorker) processAck(number uint32) bool {\n\t// number < v.firstUnacknowledged || number >= v.nextNumber\n\tif number-w.firstUnacknowledged > 0x7FFFFFFF || number-w.nextNumber < 0x7FFFFFFF {\n\t\treturn false\n\t}\n\n\tremoved := w.window.Remove(number)\n\tif removed {\n\t\tw.FindFirstUnacknowledged()\n\t}\n\treturn removed\n}\n\nfunc (w *SendingWorker) ProcessSegment(current uint32, seg *AckSegment, rto uint32) {\n\tdefer seg.Release()\n\n\tw.Lock()\n\tdefer w.Unlock()\n\n\tif w.closed {\n\t\treturn\n\t}\n\n\tif w.remoteNextNumber < seg.ReceivingWindow {\n\t\tw.remoteNextNumber = seg.ReceivingWindow\n\t}\n\tw.ProcessReceivingNextWithoutLock(seg.ReceivingNext)\n\n\tif seg.IsEmpty() {\n\t\treturn\n\t}\n\n\tvar maxack uint32\n\tvar maxackRemoved bool\n\tfor _, number := range seg.NumberList {\n\t\tremoved := w.processAck(number)\n\t\tif maxack < number {\n\t\t\tmaxack = number\n\t\t\tmaxackRemoved = removed\n\t\t}\n\t}\n\n\tif maxackRemoved {\n\t\tw.window.HandleFastAck(maxack, rto)\n\t\tif current-seg.Timestamp < 10000 {\n\t\t\tw.conn.roundTrip.Update(current-seg.Timestamp, current)\n\t\t}\n\t}\n}\n\nfunc (w *SendingWorker) Push(b *buf.Buffer) bool {\n\tw.Lock()\n\tdefer w.Unlock()\n\n\tif w.closed {\n\t\treturn false\n\t}\n\n\tif w.window.Len() > w.windowSize {\n\t\treturn false\n\t}\n\n\tw.window.Push(w.nextNumber, b)\n\tw.nextNumber++\n\treturn true\n}\n\nfunc (w *SendingWorker) Write(seg Segment) error {\n\tdataSeg := seg.(*DataSegment)\n\n\tdataSeg.Conv = w.conn.meta.Conversation\n\tdataSeg.SendingNext = w.firstUnacknowledged\n\tdataSeg.Option = 0\n\tif w.conn.State() == StateReadyToClose {\n\t\tdataSeg.Option = SegmentOptionClose\n\t}\n\n\treturn w.conn.output.Write(dataSeg)\n}\n\nfunc (w *SendingWorker) OnPacketLoss(lossRate uint32) {\n\tif !w.conn.Config.Congestion || w.conn.roundTrip.Timeout() == 0 {\n\t\treturn\n\t}\n\n\tif lossRate >= 15 {\n\t\tw.controlWindow = 3 * w.controlWindow / 4\n\t} else if lossRate <= 5 {\n\t\tw.controlWindow += w.controlWindow / 4\n\t}\n\tif w.controlWindow < 16 {\n\t\tw.controlWindow = 16\n\t}\n\tif w.controlWindow > 2*w.conn.Config.GetSendingInFlightSize() {\n\t\tw.controlWindow = 2 * w.conn.Config.GetSendingInFlightSize()\n\t}\n}\n\nfunc (w *SendingWorker) Flush(current uint32) {\n\tw.Lock()\n\n\tif w.closed {\n\t\tw.Unlock()\n\t\treturn\n\t}\n\n\tcwnd := w.firstUnacknowledged + w.conn.Config.GetSendingInFlightSize()\n\tif cwnd > w.remoteNextNumber {\n\t\tcwnd = w.remoteNextNumber\n\t}\n\tif w.conn.Config.Congestion && cwnd > w.firstUnacknowledged+w.controlWindow {\n\t\tcwnd = w.firstUnacknowledged + w.controlWindow\n\t}\n\n\tif !w.window.IsEmpty() {\n\t\tw.window.Flush(current, w.conn.roundTrip.Timeout(), cwnd)\n\t\tw.firstUnacknowledgedUpdated = false\n\t}\n\n\tupdated := w.firstUnacknowledgedUpdated\n\tw.firstUnacknowledgedUpdated = false\n\n\tw.Unlock()\n\n\tif updated {\n\t\tw.conn.Ping(current, CommandPing)\n\t}\n}\n\nfunc (w *SendingWorker) CloseWrite() {\n\tw.Lock()\n\tdefer w.Unlock()\n\n\tw.window.Clear(0xFFFFFFFF)\n}\n\nfunc (w *SendingWorker) IsEmpty() bool {\n\tw.RLock()\n\tdefer w.RUnlock()\n\n\treturn w.window.IsEmpty()\n}\n\nfunc (w *SendingWorker) UpdateNecessary() bool {\n\treturn !w.IsEmpty()\n}\n\nfunc (w *SendingWorker) FirstUnacknowledged() uint32 {\n\tw.RLock()\n\tdefer w.RUnlock()\n\n\treturn w.firstUnacknowledged\n}\n"
  },
  {
    "path": "transport/internet/kcp/xor.go",
    "content": "// +build !amd64\n\npackage kcp\n\n// xorfwd performs XOR forwards in words, x[i] ^= x[i-4], i from 0 to len\nfunc xorfwd(x []byte) {\n\tfor i := 4; i < len(x); i++ {\n\t\tx[i] ^= x[i-4]\n\t}\n}\n\n// xorbkd performs XOR backwords in words, x[i] ^= x[i-4], i from len to 0\nfunc xorbkd(x []byte) {\n\tfor i := len(x) - 1; i >= 4; i-- {\n\t\tx[i] ^= x[i-4]\n\t}\n}\n"
  },
  {
    "path": "transport/internet/kcp/xor_amd64.go",
    "content": "package kcp\n\n//go:noescape\nfunc xorfwd(x []byte)\n\n//go:noescape\nfunc xorbkd(x []byte)\n"
  },
  {
    "path": "transport/internet/kcp/xor_amd64.s",
    "content": "#include \"textflag.h\"\n\n// func xorfwd(x []byte)\nTEXT ·xorfwd(SB),NOSPLIT,$0\n  MOVQ x+0(FP), SI  // x[i]\n  MOVQ x_len+8(FP), CX  // x.len\n  MOVQ x+0(FP), DI\n  ADDQ $4, DI       // x[i+4]\n  SUBQ $4, CX\nxorfwdloop:\n  MOVL (SI), AX\n  XORL AX, (DI)\n  ADDQ $4, SI\n  ADDQ $4, DI\n  SUBQ $4, CX\n\n  CMPL CX, $0\n  JE xorfwddone\n\n  JMP xorfwdloop\nxorfwddone:        \n  RET\n\n// func xorbkd(x []byte)\nTEXT ·xorbkd(SB),NOSPLIT,$0\n  MOVQ x+0(FP), SI\n  MOVQ x_len+8(FP), CX  // x.len\n  MOVQ x+0(FP), DI\n  ADDQ CX, SI       // x[-8]\n  SUBQ $8, SI\n  ADDQ CX, DI       // x[-4]\n  SUBQ $4, DI\n  SUBQ $4, CX\nxorbkdloop:\n  MOVL (SI), AX\n  XORL AX, (DI)\n  SUBQ $4, SI\n  SUBQ $4, DI\n  SUBQ $4, CX\n\n  CMPL CX, $0\n  JE xorbkddone\n  \n  JMP xorbkdloop\n\nxorbkddone:        \n  RET\n"
  },
  {
    "path": "transport/internet/memory_settings.go",
    "content": "package internet\n\n// MemoryStreamConfig is a parsed form of StreamConfig. This is used to reduce number of Protobuf parsing.\ntype MemoryStreamConfig struct {\n\tProtocolName     string\n\tProtocolSettings interface{}\n\tSecurityType     string\n\tSecuritySettings interface{}\n\tSocketSettings   *SocketConfig\n}\n\n// ToMemoryStreamConfig converts a StreamConfig to MemoryStreamConfig. It returns a default non-nil MemoryStreamConfig for nil input.\nfunc ToMemoryStreamConfig(s *StreamConfig) (*MemoryStreamConfig, error) {\n\tets, err := s.GetEffectiveTransportSettings()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tmss := &MemoryStreamConfig{\n\t\tProtocolName:     s.GetEffectiveProtocol(),\n\t\tProtocolSettings: ets,\n\t}\n\n\tif s != nil {\n\t\tmss.SocketSettings = s.SocketSettings\n\t}\n\n\tif s != nil && s.HasSecuritySettings() {\n\t\tess, err := s.GetEffectiveSecuritySettings()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tmss.SecurityType = s.SecurityType\n\t\tmss.SecuritySettings = ess\n\t}\n\n\treturn mss, nil\n}\n"
  },
  {
    "path": "transport/internet/quic/config.go",
    "content": "// +build !confonly\n\npackage quic\n\nimport (\n\t\"crypto/aes\"\n\t\"crypto/cipher\"\n\t\"crypto/sha256\"\n\n\t\"golang.org/x/crypto/chacha20poly1305\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/transport/internet\"\n)\n\nfunc getAuth(config *Config) (cipher.AEAD, error) {\n\tsecurity := config.Security.GetSecurityType()\n\tif security == protocol.SecurityType_NONE {\n\t\treturn nil, nil\n\t}\n\n\tsalted := []byte(config.Key + \"v2ray-quic-salt\")\n\tkey := sha256.Sum256(salted)\n\n\tif security == protocol.SecurityType_AES128_GCM {\n\t\tblock, err := aes.NewCipher(key[:16])\n\t\tcommon.Must(err)\n\t\treturn cipher.NewGCM(block)\n\t}\n\n\tif security == protocol.SecurityType_CHACHA20_POLY1305 {\n\t\treturn chacha20poly1305.New(key[:])\n\t}\n\n\treturn nil, newError(\"unsupported security type\")\n}\n\nfunc getHeader(config *Config) (internet.PacketHeader, error) {\n\tif config.Header == nil {\n\t\treturn nil, nil\n\t}\n\n\tmsg, err := config.Header.GetInstance()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn internet.CreatePacketHeader(msg)\n}\n"
  },
  {
    "path": "transport/internet/quic/config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: transport/internet/quic/config.proto\n\npackage quic\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n\tprotocol \"v2ray.com/core/common/protocol\"\n\tserial \"v2ray.com/core/common/serial\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype Config struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tKey      string                   `protobuf:\"bytes,1,opt,name=key,proto3\" json:\"key,omitempty\"`\n\tSecurity *protocol.SecurityConfig `protobuf:\"bytes,2,opt,name=security,proto3\" json:\"security,omitempty\"`\n\tHeader   *serial.TypedMessage     `protobuf:\"bytes,3,opt,name=header,proto3\" json:\"header,omitempty\"`\n}\n\nfunc (x *Config) Reset() {\n\t*x = Config{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_transport_internet_quic_config_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Config) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Config) ProtoMessage() {}\n\nfunc (x *Config) ProtoReflect() protoreflect.Message {\n\tmi := &file_transport_internet_quic_config_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Config.ProtoReflect.Descriptor instead.\nfunc (*Config) Descriptor() ([]byte, []int) {\n\treturn file_transport_internet_quic_config_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *Config) GetKey() string {\n\tif x != nil {\n\t\treturn x.Key\n\t}\n\treturn \"\"\n}\n\nfunc (x *Config) GetSecurity() *protocol.SecurityConfig {\n\tif x != nil {\n\t\treturn x.Security\n\t}\n\treturn nil\n}\n\nfunc (x *Config) GetHeader() *serial.TypedMessage {\n\tif x != nil {\n\t\treturn x.Header\n\t}\n\treturn nil\n}\n\nvar File_transport_internet_quic_config_proto protoreflect.FileDescriptor\n\nvar file_transport_internet_quic_config_proto_rawDesc = []byte{\n\t0x0a, 0x24, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65,\n\t0x72, 0x6e, 0x65, 0x74, 0x2f, 0x71, 0x75, 0x69, 0x63, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,\n\t0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x22, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,\n\t0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74,\n\t0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x71, 0x75, 0x69, 0x63, 0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d,\n\t0x6f, 0x6e, 0x2f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x64, 0x5f,\n\t0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1d, 0x63,\n\t0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x68,\n\t0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xa2, 0x01, 0x0a,\n\t0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01,\n\t0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x46, 0x0a, 0x08, 0x73, 0x65, 0x63,\n\t0x75, 0x72, 0x69, 0x74, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x76, 0x32,\n\t0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e,\n\t0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74,\n\t0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74,\n\t0x79, 0x12, 0x3e, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28,\n\t0x0b, 0x32, 0x26, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63,\n\t0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70,\n\t0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65,\n\t0x72, 0x42, 0x77, 0x0a, 0x26, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,\n\t0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e,\n\t0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x71, 0x75, 0x69, 0x63, 0x50, 0x01, 0x5a, 0x26, 0x76,\n\t0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72,\n\t0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74,\n\t0x2f, 0x71, 0x75, 0x69, 0x63, 0xaa, 0x02, 0x22, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f,\n\t0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74,\n\t0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x51, 0x75, 0x69, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,\n\t0x6f, 0x33,\n}\n\nvar (\n\tfile_transport_internet_quic_config_proto_rawDescOnce sync.Once\n\tfile_transport_internet_quic_config_proto_rawDescData = file_transport_internet_quic_config_proto_rawDesc\n)\n\nfunc file_transport_internet_quic_config_proto_rawDescGZIP() []byte {\n\tfile_transport_internet_quic_config_proto_rawDescOnce.Do(func() {\n\t\tfile_transport_internet_quic_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_transport_internet_quic_config_proto_rawDescData)\n\t})\n\treturn file_transport_internet_quic_config_proto_rawDescData\n}\n\nvar file_transport_internet_quic_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)\nvar file_transport_internet_quic_config_proto_goTypes = []interface{}{\n\t(*Config)(nil),                  // 0: v2ray.core.transport.internet.quic.Config\n\t(*protocol.SecurityConfig)(nil), // 1: v2ray.core.common.protocol.SecurityConfig\n\t(*serial.TypedMessage)(nil),     // 2: v2ray.core.common.serial.TypedMessage\n}\nvar file_transport_internet_quic_config_proto_depIdxs = []int32{\n\t1, // 0: v2ray.core.transport.internet.quic.Config.security:type_name -> v2ray.core.common.protocol.SecurityConfig\n\t2, // 1: v2ray.core.transport.internet.quic.Config.header:type_name -> v2ray.core.common.serial.TypedMessage\n\t2, // [2:2] is the sub-list for method output_type\n\t2, // [2:2] is the sub-list for method input_type\n\t2, // [2:2] is the sub-list for extension type_name\n\t2, // [2:2] is the sub-list for extension extendee\n\t0, // [0:2] is the sub-list for field type_name\n}\n\nfunc init() { file_transport_internet_quic_config_proto_init() }\nfunc file_transport_internet_quic_config_proto_init() {\n\tif File_transport_internet_quic_config_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_transport_internet_quic_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Config); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_transport_internet_quic_config_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   1,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_transport_internet_quic_config_proto_goTypes,\n\t\tDependencyIndexes: file_transport_internet_quic_config_proto_depIdxs,\n\t\tMessageInfos:      file_transport_internet_quic_config_proto_msgTypes,\n\t}.Build()\n\tFile_transport_internet_quic_config_proto = out.File\n\tfile_transport_internet_quic_config_proto_rawDesc = nil\n\tfile_transport_internet_quic_config_proto_goTypes = nil\n\tfile_transport_internet_quic_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "transport/internet/quic/config.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.transport.internet.quic;\noption csharp_namespace = \"V2Ray.Core.Transport.Internet.Quic\";\noption go_package = \"v2ray.com/core/transport/internet/quic\";\noption java_package = \"com.v2ray.core.transport.internet.quic\";\noption java_multiple_files = true;\n\nimport \"common/serial/typed_message.proto\";\nimport \"common/protocol/headers.proto\";\n\nmessage Config {\n  string key = 1;\n  v2ray.core.common.protocol.SecurityConfig security = 2;\n  v2ray.core.common.serial.TypedMessage header = 3;\n}\n"
  },
  {
    "path": "transport/internet/quic/conn.go",
    "content": "// +build !confonly\n\npackage quic\n\nimport (\n\t\"crypto/cipher\"\n\t\"crypto/rand\"\n\t\"errors\"\n\t\"time\"\n\n\t\"github.com/lucas-clemente/quic-go\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/transport/internet\"\n)\n\ntype sysConn struct {\n\tconn   net.PacketConn\n\theader internet.PacketHeader\n\tauth   cipher.AEAD\n}\n\nfunc wrapSysConn(rawConn net.PacketConn, config *Config) (*sysConn, error) {\n\theader, err := getHeader(config)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tauth, err := getAuth(config)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &sysConn{\n\t\tconn:   rawConn,\n\t\theader: header,\n\t\tauth:   auth,\n\t}, nil\n}\n\nvar errInvalidPacket = errors.New(\"invalid packet\")\n\nfunc (c *sysConn) readFromInternal(p []byte) (int, net.Addr, error) {\n\tbuffer := getBuffer()\n\tdefer putBuffer(buffer)\n\n\tnBytes, addr, err := c.conn.ReadFrom(buffer)\n\tif err != nil {\n\t\treturn 0, nil, err\n\t}\n\n\tpayload := buffer[:nBytes]\n\tif c.header != nil {\n\t\tif len(payload) <= int(c.header.Size()) {\n\t\t\treturn 0, nil, errInvalidPacket\n\t\t}\n\t\tpayload = payload[c.header.Size():]\n\t}\n\n\tif c.auth == nil {\n\t\tn := copy(p, payload)\n\t\treturn n, addr, nil\n\t}\n\n\tif len(payload) <= c.auth.NonceSize() {\n\t\treturn 0, nil, errInvalidPacket\n\t}\n\n\tnonce := payload[:c.auth.NonceSize()]\n\tpayload = payload[c.auth.NonceSize():]\n\n\tp, err = c.auth.Open(p[:0], nonce, payload, nil)\n\tif err != nil {\n\t\treturn 0, nil, errInvalidPacket\n\t}\n\n\treturn len(p), addr, nil\n}\n\nfunc (c *sysConn) ReadFrom(p []byte) (int, net.Addr, error) {\n\tif c.header == nil && c.auth == nil {\n\t\treturn c.conn.ReadFrom(p)\n\t}\n\n\tfor {\n\t\tn, addr, err := c.readFromInternal(p)\n\t\tif err != nil && err != errInvalidPacket {\n\t\t\treturn 0, nil, err\n\t\t}\n\t\tif err == nil {\n\t\t\treturn n, addr, nil\n\t\t}\n\t}\n}\n\nfunc (c *sysConn) WriteTo(p []byte, addr net.Addr) (int, error) {\n\tif c.header == nil && c.auth == nil {\n\t\treturn c.conn.WriteTo(p, addr)\n\t}\n\n\tbuffer := getBuffer()\n\tdefer putBuffer(buffer)\n\n\tpayload := buffer\n\tn := 0\n\tif c.header != nil {\n\t\tc.header.Serialize(payload)\n\t\tn = int(c.header.Size())\n\t}\n\n\tif c.auth == nil {\n\t\tnBytes := copy(payload[n:], p)\n\t\tn += nBytes\n\t} else {\n\t\tnounce := payload[n : n+c.auth.NonceSize()]\n\t\tcommon.Must2(rand.Read(nounce))\n\t\tn += c.auth.NonceSize()\n\t\tpp := c.auth.Seal(payload[:n], nounce, p, nil)\n\t\tn = len(pp)\n\t}\n\n\treturn c.conn.WriteTo(payload[:n], addr)\n}\n\nfunc (c *sysConn) Close() error {\n\treturn c.conn.Close()\n}\n\nfunc (c *sysConn) LocalAddr() net.Addr {\n\treturn c.conn.LocalAddr()\n}\n\nfunc (c *sysConn) SetDeadline(t time.Time) error {\n\treturn c.conn.SetDeadline(t)\n}\n\nfunc (c *sysConn) SetReadDeadline(t time.Time) error {\n\treturn c.conn.SetReadDeadline(t)\n}\n\nfunc (c *sysConn) SetWriteDeadline(t time.Time) error {\n\treturn c.conn.SetWriteDeadline(t)\n}\n\ntype interConn struct {\n\tstream quic.Stream\n\tlocal  net.Addr\n\tremote net.Addr\n}\n\nfunc (c *interConn) Read(b []byte) (int, error) {\n\treturn c.stream.Read(b)\n}\n\nfunc (c *interConn) WriteMultiBuffer(mb buf.MultiBuffer) error {\n\tmb = buf.Compact(mb)\n\tmb, err := buf.WriteMultiBuffer(c, mb)\n\tbuf.ReleaseMulti(mb)\n\treturn err\n}\n\nfunc (c *interConn) Write(b []byte) (int, error) {\n\treturn c.stream.Write(b)\n}\n\nfunc (c *interConn) Close() error {\n\treturn c.stream.Close()\n}\n\nfunc (c *interConn) LocalAddr() net.Addr {\n\treturn c.local\n}\n\nfunc (c *interConn) RemoteAddr() net.Addr {\n\treturn c.remote\n}\n\nfunc (c *interConn) SetDeadline(t time.Time) error {\n\treturn c.stream.SetDeadline(t)\n}\n\nfunc (c *interConn) SetReadDeadline(t time.Time) error {\n\treturn c.stream.SetReadDeadline(t)\n}\n\nfunc (c *interConn) SetWriteDeadline(t time.Time) error {\n\treturn c.stream.SetWriteDeadline(t)\n}\n"
  },
  {
    "path": "transport/internet/quic/dialer.go",
    "content": "// +build !confonly\n\npackage quic\n\nimport (\n\t\"context\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/lucas-clemente/quic-go\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/task\"\n\t\"v2ray.com/core/transport/internet\"\n\t\"v2ray.com/core/transport/internet/tls\"\n)\n\ntype sessionContext struct {\n\trawConn *sysConn\n\tsession quic.Session\n}\n\nvar errSessionClosed = newError(\"session closed\")\n\nfunc (c *sessionContext) openStream(destAddr net.Addr) (*interConn, error) {\n\tif !isActive(c.session) {\n\t\treturn nil, errSessionClosed\n\t}\n\n\tstream, err := c.session.OpenStream()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tconn := &interConn{\n\t\tstream: stream,\n\t\tlocal:  c.session.LocalAddr(),\n\t\tremote: destAddr,\n\t}\n\n\treturn conn, nil\n}\n\ntype clientSessions struct {\n\taccess   sync.Mutex\n\tsessions map[net.Destination][]*sessionContext\n\tcleanup  *task.Periodic\n}\n\nfunc isActive(s quic.Session) bool {\n\tselect {\n\tcase <-s.Context().Done():\n\t\treturn false\n\tdefault:\n\t\treturn true\n\t}\n}\n\nfunc removeInactiveSessions(sessions []*sessionContext) []*sessionContext {\n\tactiveSessions := make([]*sessionContext, 0, len(sessions))\n\tfor _, s := range sessions {\n\t\tif isActive(s.session) {\n\t\t\tactiveSessions = append(activeSessions, s)\n\t\t\tcontinue\n\t\t}\n\t\tif err := s.session.CloseWithError(0, \"\"); err != nil {\n\t\t\tnewError(\"failed to close session\").Base(err).WriteToLog()\n\t\t}\n\t\tif err := s.rawConn.Close(); err != nil {\n\t\t\tnewError(\"failed to close raw connection\").Base(err).WriteToLog()\n\t\t}\n\t}\n\n\tif len(activeSessions) < len(sessions) {\n\t\treturn activeSessions\n\t}\n\n\treturn sessions\n}\n\nfunc openStream(sessions []*sessionContext, destAddr net.Addr) *interConn {\n\tfor _, s := range sessions {\n\t\tif !isActive(s.session) {\n\t\t\tcontinue\n\t\t}\n\n\t\tconn, err := s.openStream(destAddr)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\treturn conn\n\t}\n\n\treturn nil\n}\n\nfunc (s *clientSessions) cleanSessions() error {\n\ts.access.Lock()\n\tdefer s.access.Unlock()\n\n\tif len(s.sessions) == 0 {\n\t\treturn nil\n\t}\n\n\tnewSessionMap := make(map[net.Destination][]*sessionContext)\n\n\tfor dest, sessions := range s.sessions {\n\t\tsessions = removeInactiveSessions(sessions)\n\t\tif len(sessions) > 0 {\n\t\t\tnewSessionMap[dest] = sessions\n\t\t}\n\t}\n\n\ts.sessions = newSessionMap\n\treturn nil\n}\n\nfunc (s *clientSessions) openConnection(destAddr net.Addr, config *Config, tlsConfig *tls.Config, sockopt *internet.SocketConfig) (internet.Connection, error) {\n\ts.access.Lock()\n\tdefer s.access.Unlock()\n\n\tif s.sessions == nil {\n\t\ts.sessions = make(map[net.Destination][]*sessionContext)\n\t}\n\n\tdest := net.DestinationFromAddr(destAddr)\n\n\tvar sessions []*sessionContext\n\tif s, found := s.sessions[dest]; found {\n\t\tsessions = s\n\t}\n\n\tif true {\n\t\tconn := openStream(sessions, destAddr)\n\t\tif conn != nil {\n\t\t\treturn conn, nil\n\t\t}\n\t}\n\n\tsessions = removeInactiveSessions(sessions)\n\n\trawConn, err := internet.ListenSystemPacket(context.Background(), &net.UDPAddr{\n\t\tIP:   []byte{0, 0, 0, 0},\n\t\tPort: 0,\n\t}, sockopt)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tquicConfig := &quic.Config{\n\t\tConnectionIDLength: 12,\n\t\tHandshakeTimeout:   time.Second * 8,\n\t\tMaxIdleTimeout:     time.Second * 30,\n\t}\n\n\tconn, err := wrapSysConn(rawConn, config)\n\tif err != nil {\n\t\trawConn.Close()\n\t\treturn nil, err\n\t}\n\n\tsession, err := quic.DialContext(context.Background(), conn, destAddr, \"\", tlsConfig.GetTLSConfig(tls.WithDestination(dest)), quicConfig)\n\tif err != nil {\n\t\tconn.Close()\n\t\treturn nil, err\n\t}\n\n\tcontext := &sessionContext{\n\t\tsession: session,\n\t\trawConn: conn,\n\t}\n\ts.sessions[dest] = append(sessions, context)\n\treturn context.openStream(destAddr)\n}\n\nvar client clientSessions\n\nfunc init() {\n\tclient.sessions = make(map[net.Destination][]*sessionContext)\n\tclient.cleanup = &task.Periodic{\n\t\tInterval: time.Minute,\n\t\tExecute:  client.cleanSessions,\n\t}\n\tcommon.Must(client.cleanup.Start())\n}\n\nfunc Dial(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (internet.Connection, error) {\n\ttlsConfig := tls.ConfigFromStreamSettings(streamSettings)\n\tif tlsConfig == nil {\n\t\ttlsConfig = &tls.Config{\n\t\t\tServerName:    internalDomain,\n\t\t\tAllowInsecure: true,\n\t\t}\n\t}\n\n\tvar destAddr *net.UDPAddr\n\tif dest.Address.Family().IsIP() {\n\t\tdestAddr = &net.UDPAddr{\n\t\t\tIP:   dest.Address.IP(),\n\t\t\tPort: int(dest.Port),\n\t\t}\n\t} else {\n\t\taddr, err := net.ResolveUDPAddr(\"udp\", dest.NetAddr())\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tdestAddr = addr\n\t}\n\n\tconfig := streamSettings.ProtocolSettings.(*Config)\n\n\treturn client.openConnection(destAddr, config, tlsConfig, streamSettings.SocketSettings)\n}\n\nfunc init() {\n\tcommon.Must(internet.RegisterTransportDialer(protocolName, Dial))\n}\n"
  },
  {
    "path": "transport/internet/quic/errors.generated.go",
    "content": "package quic\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "transport/internet/quic/hub.go",
    "content": "// +build !confonly\n\npackage quic\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/lucas-clemente/quic-go\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol/tls/cert\"\n\t\"v2ray.com/core/common/signal/done\"\n\t\"v2ray.com/core/transport/internet\"\n\t\"v2ray.com/core/transport/internet/tls\"\n)\n\n// Listener is an internet.Listener that listens for TCP connections.\ntype Listener struct {\n\trawConn  *sysConn\n\tlistener quic.Listener\n\tdone     *done.Instance\n\taddConn  internet.ConnHandler\n}\n\nfunc (l *Listener) acceptStreams(session quic.Session) {\n\tfor {\n\t\tstream, err := session.AcceptStream(context.Background())\n\t\tif err != nil {\n\t\t\tnewError(\"failed to accept stream\").Base(err).WriteToLog()\n\t\t\tselect {\n\t\t\tcase <-session.Context().Done():\n\t\t\t\treturn\n\t\t\tcase <-l.done.Wait():\n\t\t\t\tif err := session.CloseWithError(0, \"\"); err != nil {\n\t\t\t\t\tnewError(\"failed to close session\").Base(err).WriteToLog()\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\tdefault:\n\t\t\t\ttime.Sleep(time.Second)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\tconn := &interConn{\n\t\t\tstream: stream,\n\t\t\tlocal:  session.LocalAddr(),\n\t\t\tremote: session.RemoteAddr(),\n\t\t}\n\n\t\tl.addConn(conn)\n\t}\n\n}\n\nfunc (l *Listener) keepAccepting() {\n\tfor {\n\t\tconn, err := l.listener.Accept(context.Background())\n\t\tif err != nil {\n\t\t\tnewError(\"failed to accept QUIC sessions\").Base(err).WriteToLog()\n\t\t\tif l.done.Done() {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\ttime.Sleep(time.Second)\n\t\t\tcontinue\n\t\t}\n\t\tgo l.acceptStreams(conn)\n\t}\n}\n\n// Addr implements internet.Listener.Addr.\nfunc (l *Listener) Addr() net.Addr {\n\treturn l.listener.Addr()\n}\n\n// Close implements internet.Listener.Close.\nfunc (l *Listener) Close() error {\n\tl.done.Close()\n\tl.listener.Close()\n\tl.rawConn.Close()\n\treturn nil\n}\n\n// Listen creates a new Listener based on configurations.\nfunc Listen(ctx context.Context, address net.Address, port net.Port, streamSettings *internet.MemoryStreamConfig, handler internet.ConnHandler) (internet.Listener, error) {\n\tif address.Family().IsDomain() {\n\t\treturn nil, newError(\"domain address is not allows for listening quic\")\n\t}\n\n\ttlsConfig := tls.ConfigFromStreamSettings(streamSettings)\n\tif tlsConfig == nil {\n\t\ttlsConfig = &tls.Config{\n\t\t\tCertificate: []*tls.Certificate{tls.ParseCertificate(cert.MustGenerate(nil, cert.DNSNames(internalDomain), cert.CommonName(internalDomain)))},\n\t\t}\n\t}\n\n\tconfig := streamSettings.ProtocolSettings.(*Config)\n\trawConn, err := internet.ListenSystemPacket(context.Background(), &net.UDPAddr{\n\t\tIP:   address.IP(),\n\t\tPort: int(port),\n\t}, streamSettings.SocketSettings)\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tquicConfig := &quic.Config{\n\t\tConnectionIDLength:    12,\n\t\tHandshakeTimeout:      time.Second * 8,\n\t\tMaxIdleTimeout:        time.Second * 45,\n\t\tMaxIncomingStreams:    32,\n\t\tMaxIncomingUniStreams: -1,\n\t}\n\n\tconn, err := wrapSysConn(rawConn, config)\n\tif err != nil {\n\t\tconn.Close()\n\t\treturn nil, err\n\t}\n\n\tqListener, err := quic.Listen(conn, tlsConfig.GetTLSConfig(), quicConfig)\n\tif err != nil {\n\t\tconn.Close()\n\t\treturn nil, err\n\t}\n\n\tlistener := &Listener{\n\t\tdone:     done.New(),\n\t\trawConn:  conn,\n\t\tlistener: qListener,\n\t\taddConn:  handler,\n\t}\n\n\tgo listener.keepAccepting()\n\n\treturn listener, nil\n}\n\nfunc init() {\n\tcommon.Must(internet.RegisterTransportListener(protocolName, Listen))\n}\n"
  },
  {
    "path": "transport/internet/quic/pool.go",
    "content": "// +build !confonly\n\npackage quic\n\nimport (\n\t\"sync\"\n\n\t\"v2ray.com/core/common/bytespool\"\n)\n\nvar pool *sync.Pool\n\nfunc init() {\n\tpool = bytespool.GetPool(2048)\n}\n\nfunc getBuffer() []byte {\n\treturn pool.Get().([]byte)\n}\n\nfunc putBuffer(p []byte) {\n\tpool.Put(p)\n}\n"
  },
  {
    "path": "transport/internet/quic/quic.go",
    "content": "// +build !confonly\n\npackage quic\n\nimport (\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/transport/internet\"\n)\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n\n// Here is some modification needs to be done before update quic vendor.\n// * use bytespool in buffer_pool.go\n// * set MaxReceivePacketSize to 1452 - 32 (16 bytes auth, 16 bytes head)\n//\n//\n\nconst protocolName = \"quic\"\nconst internalDomain = \"quic.internal.v2ray.com\"\n\nfunc init() {\n\tcommon.Must(internet.RegisterProtocolConfigCreator(protocolName, func() interface{} {\n\t\treturn new(Config)\n\t}))\n}\n"
  },
  {
    "path": "transport/internet/quic/quic_test.go",
    "content": "package quic_test\n\nimport (\n\t\"context\"\n\t\"crypto/rand\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/protocol/tls/cert\"\n\t\"v2ray.com/core/common/serial\"\n\t\"v2ray.com/core/testing/servers/udp\"\n\t\"v2ray.com/core/transport/internet\"\n\t\"v2ray.com/core/transport/internet/headers/wireguard\"\n\t\"v2ray.com/core/transport/internet/quic\"\n\t\"v2ray.com/core/transport/internet/tls\"\n)\n\nfunc TestQuicConnection(t *testing.T) {\n\tport := udp.PickPort()\n\n\tlistener, err := quic.Listen(context.Background(), net.LocalHostIP, port, &internet.MemoryStreamConfig{\n\t\tProtocolName:     \"quic\",\n\t\tProtocolSettings: &quic.Config{},\n\t\tSecurityType:     \"tls\",\n\t\tSecuritySettings: &tls.Config{\n\t\t\tCertificate: []*tls.Certificate{\n\t\t\t\ttls.ParseCertificate(\n\t\t\t\t\tcert.MustGenerate(nil,\n\t\t\t\t\t\tcert.DNSNames(\"www.v2fly.org\"),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t}, func(conn internet.Connection) {\n\t\tgo func() {\n\t\t\tdefer conn.Close()\n\n\t\t\tb := buf.New()\n\t\t\tdefer b.Release()\n\n\t\t\tfor {\n\t\t\t\tb.Clear()\n\t\t\t\tif _, err := b.ReadFrom(conn); err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tcommon.Must2(conn.Write(b.Bytes()))\n\t\t\t}\n\t\t}()\n\t})\n\tcommon.Must(err)\n\n\tdefer listener.Close()\n\n\ttime.Sleep(time.Second)\n\n\tdctx := context.Background()\n\tconn, err := quic.Dial(dctx, net.TCPDestination(net.LocalHostIP, port), &internet.MemoryStreamConfig{\n\t\tProtocolName:     \"quic\",\n\t\tProtocolSettings: &quic.Config{},\n\t\tSecurityType:     \"tls\",\n\t\tSecuritySettings: &tls.Config{\n\t\t\tServerName:    \"www.v2fly.org\",\n\t\t\tAllowInsecure: true,\n\t\t},\n\t})\n\tcommon.Must(err)\n\tdefer conn.Close()\n\n\tconst N = 1024\n\tb1 := make([]byte, N)\n\tcommon.Must2(rand.Read(b1))\n\tb2 := buf.New()\n\n\tcommon.Must2(conn.Write(b1))\n\n\tb2.Clear()\n\tcommon.Must2(b2.ReadFullFrom(conn, N))\n\tif r := cmp.Diff(b2.Bytes(), b1); r != \"\" {\n\t\tt.Error(r)\n\t}\n\n\tcommon.Must2(conn.Write(b1))\n\n\tb2.Clear()\n\tcommon.Must2(b2.ReadFullFrom(conn, N))\n\tif r := cmp.Diff(b2.Bytes(), b1); r != \"\" {\n\t\tt.Error(r)\n\t}\n}\n\nfunc TestQuicConnectionWithoutTLS(t *testing.T) {\n\tport := udp.PickPort()\n\n\tlistener, err := quic.Listen(context.Background(), net.LocalHostIP, port, &internet.MemoryStreamConfig{\n\t\tProtocolName:     \"quic\",\n\t\tProtocolSettings: &quic.Config{},\n\t}, func(conn internet.Connection) {\n\t\tgo func() {\n\t\t\tdefer conn.Close()\n\n\t\t\tb := buf.New()\n\t\t\tdefer b.Release()\n\n\t\t\tfor {\n\t\t\t\tb.Clear()\n\t\t\t\tif _, err := b.ReadFrom(conn); err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tcommon.Must2(conn.Write(b.Bytes()))\n\t\t\t}\n\t\t}()\n\t})\n\tcommon.Must(err)\n\n\tdefer listener.Close()\n\n\ttime.Sleep(time.Second)\n\n\tdctx := context.Background()\n\tconn, err := quic.Dial(dctx, net.TCPDestination(net.LocalHostIP, port), &internet.MemoryStreamConfig{\n\t\tProtocolName:     \"quic\",\n\t\tProtocolSettings: &quic.Config{},\n\t})\n\tcommon.Must(err)\n\tdefer conn.Close()\n\n\tconst N = 1024\n\tb1 := make([]byte, N)\n\tcommon.Must2(rand.Read(b1))\n\tb2 := buf.New()\n\n\tcommon.Must2(conn.Write(b1))\n\n\tb2.Clear()\n\tcommon.Must2(b2.ReadFullFrom(conn, N))\n\tif r := cmp.Diff(b2.Bytes(), b1); r != \"\" {\n\t\tt.Error(r)\n\t}\n\n\tcommon.Must2(conn.Write(b1))\n\n\tb2.Clear()\n\tcommon.Must2(b2.ReadFullFrom(conn, N))\n\tif r := cmp.Diff(b2.Bytes(), b1); r != \"\" {\n\t\tt.Error(r)\n\t}\n}\n\nfunc TestQuicConnectionAuthHeader(t *testing.T) {\n\tport := udp.PickPort()\n\n\tlistener, err := quic.Listen(context.Background(), net.LocalHostIP, port, &internet.MemoryStreamConfig{\n\t\tProtocolName: \"quic\",\n\t\tProtocolSettings: &quic.Config{\n\t\t\tHeader: serial.ToTypedMessage(&wireguard.WireguardConfig{}),\n\t\t\tKey:    \"abcd\",\n\t\t\tSecurity: &protocol.SecurityConfig{\n\t\t\t\tType: protocol.SecurityType_AES128_GCM,\n\t\t\t},\n\t\t},\n\t}, func(conn internet.Connection) {\n\t\tgo func() {\n\t\t\tdefer conn.Close()\n\n\t\t\tb := buf.New()\n\t\t\tdefer b.Release()\n\n\t\t\tfor {\n\t\t\t\tb.Clear()\n\t\t\t\tif _, err := b.ReadFrom(conn); err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tcommon.Must2(conn.Write(b.Bytes()))\n\t\t\t}\n\t\t}()\n\t})\n\tcommon.Must(err)\n\n\tdefer listener.Close()\n\n\ttime.Sleep(time.Second)\n\n\tdctx := context.Background()\n\tconn, err := quic.Dial(dctx, net.TCPDestination(net.LocalHostIP, port), &internet.MemoryStreamConfig{\n\t\tProtocolName: \"quic\",\n\t\tProtocolSettings: &quic.Config{\n\t\t\tHeader: serial.ToTypedMessage(&wireguard.WireguardConfig{}),\n\t\t\tKey:    \"abcd\",\n\t\t\tSecurity: &protocol.SecurityConfig{\n\t\t\t\tType: protocol.SecurityType_AES128_GCM,\n\t\t\t},\n\t\t},\n\t})\n\tcommon.Must(err)\n\tdefer conn.Close()\n\n\tconst N = 1024\n\tb1 := make([]byte, N)\n\tcommon.Must2(rand.Read(b1))\n\tb2 := buf.New()\n\n\tcommon.Must2(conn.Write(b1))\n\n\tb2.Clear()\n\tcommon.Must2(b2.ReadFullFrom(conn, N))\n\tif r := cmp.Diff(b2.Bytes(), b1); r != \"\" {\n\t\tt.Error(r)\n\t}\n\n\tcommon.Must2(conn.Write(b1))\n\n\tb2.Clear()\n\tcommon.Must2(b2.ReadFullFrom(conn, N))\n\tif r := cmp.Diff(b2.Bytes(), b1); r != \"\" {\n\t\tt.Error(r)\n\t}\n}\n"
  },
  {
    "path": "transport/internet/sockopt.go",
    "content": "package internet\n\nfunc isTCPSocket(network string) bool {\n\tswitch network {\n\tcase \"tcp\", \"tcp4\", \"tcp6\":\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\n\nfunc isUDPSocket(network string) bool {\n\tswitch network {\n\tcase \"udp\", \"udp4\", \"udp6\":\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\n"
  },
  {
    "path": "transport/internet/sockopt_darwin.go",
    "content": "package internet\n\nimport (\n\t\"syscall\"\n)\n\nconst (\n\t// TCP_FASTOPEN is the socket option on darwin for TCP fast open.\n\tTCP_FASTOPEN = 0x105\n\t// TCP_FASTOPEN_SERVER is the value to enable TCP fast open on darwin for server connections.\n\tTCP_FASTOPEN_SERVER = 0x01\n\t// TCP_FASTOPEN_CLIENT is the value to enable TCP fast open on darwin for client connections.\n\tTCP_FASTOPEN_CLIENT = 0x02\n)\n\nfunc applyOutboundSocketOptions(network string, address string, fd uintptr, config *SocketConfig) error {\n\tif isTCPSocket(network) {\n\t\tswitch config.Tfo {\n\t\tcase SocketConfig_Enable:\n\t\t\tif err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, TCP_FASTOPEN, TCP_FASTOPEN_CLIENT); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tcase SocketConfig_Disable:\n\t\t\tif err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, TCP_FASTOPEN, 0); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig) error {\n\tif isTCPSocket(network) {\n\t\tswitch config.Tfo {\n\t\tcase SocketConfig_Enable:\n\t\t\tif err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, TCP_FASTOPEN, TCP_FASTOPEN_SERVER); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tcase SocketConfig_Disable:\n\t\t\tif err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, TCP_FASTOPEN, 0); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc bindAddr(fd uintptr, address []byte, port uint32) error {\n\treturn nil\n}\n\nfunc setReuseAddr(fd uintptr) error {\n\treturn nil\n}\n\nfunc setReusePort(fd uintptr) error {\n\treturn nil\n}\n"
  },
  {
    "path": "transport/internet/sockopt_freebsd.go",
    "content": "package internet\n\nimport (\n\t\"encoding/binary\"\n\t\"net\"\n\t\"os\"\n\t\"syscall\"\n\t\"unsafe\"\n\n\t\"golang.org/x/sys/unix\"\n)\n\nconst (\n\tsysPFINOUT     = 0x0\n\tsysPFIN        = 0x1\n\tsysPFOUT       = 0x2\n\tsysPFFWD       = 0x3\n\tsysDIOCNATLOOK = 0xc04c4417\n)\n\ntype pfiocNatlook struct {\n\tSaddr     [16]byte /* pf_addr */\n\tDaddr     [16]byte /* pf_addr */\n\tRsaddr    [16]byte /* pf_addr */\n\tRdaddr    [16]byte /* pf_addr */\n\tSport     uint16\n\tDport     uint16\n\tRsport    uint16\n\tRdport    uint16\n\tAf        uint8\n\tProto     uint8\n\tDirection uint8\n\tPad       [1]byte\n}\n\nconst (\n\tsizeofPfiocNatlook = 0x4c\n\tsoReUsePort        = 0x00000200\n\tsoReUsePortLB      = 0x00010000\n)\n\nfunc ioctl(s uintptr, ioc int, b []byte) error {\n\tif _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, s, uintptr(ioc), uintptr(unsafe.Pointer(&b[0]))); errno != 0 {\n\t\treturn error(errno)\n\t}\n\treturn nil\n}\nfunc (nl *pfiocNatlook) rdPort() int {\n\treturn int(binary.BigEndian.Uint16((*[2]byte)(unsafe.Pointer(&nl.Rdport))[:]))\n}\n\nfunc (nl *pfiocNatlook) setPort(remote, local int) {\n\tbinary.BigEndian.PutUint16((*[2]byte)(unsafe.Pointer(&nl.Sport))[:], uint16(remote))\n\tbinary.BigEndian.PutUint16((*[2]byte)(unsafe.Pointer(&nl.Dport))[:], uint16(local))\n}\n\n// OriginalDst uses ioctl to read original destination from /dev/pf\nfunc OriginalDst(la, ra net.Addr) (net.IP, int, error) {\n\tf, err := os.Open(\"/dev/pf\")\n\tif err != nil {\n\t\treturn net.IP{}, -1, newError(\"failed to open device /dev/pf\").Base(err)\n\t}\n\tdefer f.Close()\n\tfd := f.Fd()\n\tb := make([]byte, sizeofPfiocNatlook)\n\tnl := (*pfiocNatlook)(unsafe.Pointer(&b[0]))\n\tvar raIP, laIP net.IP\n\tvar raPort, laPort int\n\tswitch la.(type) {\n\tcase *net.TCPAddr:\n\t\traIP = ra.(*net.TCPAddr).IP\n\t\tlaIP = la.(*net.TCPAddr).IP\n\t\traPort = ra.(*net.TCPAddr).Port\n\t\tlaPort = la.(*net.TCPAddr).Port\n\t\tnl.Proto = syscall.IPPROTO_TCP\n\tcase *net.UDPAddr:\n\t\traIP = ra.(*net.UDPAddr).IP\n\t\tlaIP = la.(*net.UDPAddr).IP\n\t\traPort = ra.(*net.UDPAddr).Port\n\t\tlaPort = la.(*net.UDPAddr).Port\n\t\tnl.Proto = syscall.IPPROTO_UDP\n\t}\n\tif raIP.To4() != nil {\n\t\tif laIP.IsUnspecified() {\n\t\t\tlaIP = net.ParseIP(\"127.0.0.1\")\n\t\t}\n\t\tcopy(nl.Saddr[:net.IPv4len], raIP.To4())\n\t\tcopy(nl.Daddr[:net.IPv4len], laIP.To4())\n\t\tnl.Af = syscall.AF_INET\n\t}\n\tif raIP.To16() != nil && raIP.To4() == nil {\n\t\tif laIP.IsUnspecified() {\n\t\t\tlaIP = net.ParseIP(\"::1\")\n\t\t}\n\t\tcopy(nl.Saddr[:], raIP)\n\t\tcopy(nl.Daddr[:], laIP)\n\t\tnl.Af = syscall.AF_INET6\n\t}\n\tnl.setPort(raPort, laPort)\n\tioc := uintptr(sysDIOCNATLOOK)\n\tfor _, dir := range []byte{sysPFOUT, sysPFIN} {\n\t\tnl.Direction = dir\n\t\terr = ioctl(fd, int(ioc), b)\n\t\tif err == nil || err != syscall.ENOENT {\n\t\t\tbreak\n\t\t}\n\t}\n\tif err != nil {\n\t\treturn net.IP{}, -1, os.NewSyscallError(\"ioctl\", err)\n\t}\n\n\todPort := nl.rdPort()\n\tvar odIP net.IP\n\tswitch nl.Af {\n\tcase syscall.AF_INET:\n\t\todIP = make(net.IP, net.IPv4len)\n\t\tcopy(odIP, nl.Rdaddr[:net.IPv4len])\n\tcase syscall.AF_INET6:\n\t\todIP = make(net.IP, net.IPv6len)\n\t\tcopy(odIP, nl.Rdaddr[:])\n\t}\n\treturn odIP, odPort, nil\n}\n\nfunc applyOutboundSocketOptions(network string, address string, fd uintptr, config *SocketConfig) error {\n\tif config.Mark != 0 {\n\t\tif err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_USER_COOKIE, int(config.Mark)); err != nil {\n\t\t\treturn newError(\"failed to set SO_USER_COOKIE\").Base(err)\n\t\t}\n\t}\n\n\tif isTCPSocket(network) {\n\t\tswitch config.Tfo {\n\t\tcase SocketConfig_Enable:\n\t\t\tif err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_FASTOPEN, 1); err != nil {\n\t\t\t\treturn newError(\"failed to set TCP_FASTOPEN_CONNECT=1\").Base(err)\n\t\t\t}\n\t\tcase SocketConfig_Disable:\n\t\t\tif err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_FASTOPEN, 0); err != nil {\n\t\t\t\treturn newError(\"failed to set TCP_FASTOPEN_CONNECT=0\").Base(err)\n\t\t\t}\n\t\t}\n\t}\n\n\tif config.Tproxy.IsEnabled() {\n\t\tip, _, _ := net.SplitHostPort(address)\n\t\tif net.ParseIP(ip).To4() != nil {\n\t\t\tif err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_BINDANY, 1); err != nil {\n\t\t\t\treturn newError(\"failed to set outbound IP_BINDANY\").Base(err)\n\t\t\t}\n\t\t} else {\n\t\t\tif err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IPV6, syscall.IPV6_BINDANY, 1); err != nil {\n\t\t\t\treturn newError(\"failed to set outbound IPV6_BINDANY\").Base(err)\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig) error {\n\tif config.Mark != 0 {\n\t\tif err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_USER_COOKIE, int(config.Mark)); err != nil {\n\t\t\treturn newError(\"failed to set SO_USER_COOKIE\").Base(err)\n\t\t}\n\t}\n\tif isTCPSocket(network) {\n\t\tswitch config.Tfo {\n\t\tcase SocketConfig_Enable:\n\t\t\tif err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_FASTOPEN, 1); err != nil {\n\t\t\t\treturn newError(\"failed to set TCP_FASTOPEN=1\").Base(err)\n\t\t\t}\n\t\tcase SocketConfig_Disable:\n\t\t\tif err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_FASTOPEN, 0); err != nil {\n\t\t\t\treturn newError(\"failed to set TCP_FASTOPEN=0\").Base(err)\n\t\t\t}\n\t\t}\n\t}\n\n\tif config.Tproxy.IsEnabled() {\n\t\tif err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IPV6, syscall.IPV6_BINDANY, 1); err != nil {\n\t\t\tif err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_BINDANY, 1); err != nil {\n\t\t\t\treturn newError(\"failed to set inbound IP_BINDANY\").Base(err)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc bindAddr(fd uintptr, ip []byte, port uint32) error {\n\tsetReuseAddr(fd)\n\tsetReusePort(fd)\n\n\tvar sockaddr syscall.Sockaddr\n\n\tswitch len(ip) {\n\tcase net.IPv4len:\n\t\ta4 := &syscall.SockaddrInet4{\n\t\t\tPort: int(port),\n\t\t}\n\t\tcopy(a4.Addr[:], ip)\n\t\tsockaddr = a4\n\tcase net.IPv6len:\n\t\ta6 := &syscall.SockaddrInet6{\n\t\t\tPort: int(port),\n\t\t}\n\t\tcopy(a6.Addr[:], ip)\n\t\tsockaddr = a6\n\tdefault:\n\t\treturn newError(\"unexpected length of ip\")\n\t}\n\n\treturn syscall.Bind(int(fd), sockaddr)\n}\n\nfunc setReuseAddr(fd uintptr) error {\n\tif err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); err != nil {\n\t\treturn newError(\"failed to set SO_REUSEADDR\").Base(err).AtWarning()\n\t}\n\treturn nil\n}\n\nfunc setReusePort(fd uintptr) error {\n\tif err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, soReUsePortLB, 1); err != nil {\n\t\tif err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, soReUsePort, 1); err != nil {\n\t\t\treturn newError(\"failed to set SO_REUSEPORT\").Base(err).AtWarning()\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "transport/internet/sockopt_linux.go",
    "content": "package internet\n\nimport (\n\t\"net\"\n\t\"syscall\"\n\n\t\"golang.org/x/sys/unix\"\n)\n\nconst (\n\t// For incoming connections.\n\tTCP_FASTOPEN = 23\n\t// For out-going connections.\n\tTCP_FASTOPEN_CONNECT = 30\n)\n\nfunc bindAddr(fd uintptr, ip []byte, port uint32) error {\n\tsetReuseAddr(fd)\n\tsetReusePort(fd)\n\n\tvar sockaddr syscall.Sockaddr\n\n\tswitch len(ip) {\n\tcase net.IPv4len:\n\t\ta4 := &syscall.SockaddrInet4{\n\t\t\tPort: int(port),\n\t\t}\n\t\tcopy(a4.Addr[:], ip)\n\t\tsockaddr = a4\n\tcase net.IPv6len:\n\t\ta6 := &syscall.SockaddrInet6{\n\t\t\tPort: int(port),\n\t\t}\n\t\tcopy(a6.Addr[:], ip)\n\t\tsockaddr = a6\n\tdefault:\n\t\treturn newError(\"unexpected length of ip\")\n\t}\n\n\treturn syscall.Bind(int(fd), sockaddr)\n}\n\nfunc applyOutboundSocketOptions(network string, address string, fd uintptr, config *SocketConfig) error {\n\tif config.Mark != 0 {\n\t\tif err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_MARK, int(config.Mark)); err != nil {\n\t\t\treturn newError(\"failed to set SO_MARK\").Base(err)\n\t\t}\n\t}\n\n\tif isTCPSocket(network) {\n\t\tswitch config.Tfo {\n\t\tcase SocketConfig_Enable:\n\t\t\tif err := syscall.SetsockoptInt(int(fd), syscall.SOL_TCP, TCP_FASTOPEN_CONNECT, 1); err != nil {\n\t\t\t\treturn newError(\"failed to set TCP_FASTOPEN_CONNECT=1\").Base(err)\n\t\t\t}\n\t\tcase SocketConfig_Disable:\n\t\t\tif err := syscall.SetsockoptInt(int(fd), syscall.SOL_TCP, TCP_FASTOPEN_CONNECT, 0); err != nil {\n\t\t\t\treturn newError(\"failed to set TCP_FASTOPEN_CONNECT=0\").Base(err)\n\t\t\t}\n\t\t}\n\t}\n\n\tif config.Tproxy.IsEnabled() {\n\t\tif err := syscall.SetsockoptInt(int(fd), syscall.SOL_IP, syscall.IP_TRANSPARENT, 1); err != nil {\n\t\t\treturn newError(\"failed to set IP_TRANSPARENT\").Base(err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig) error {\n\tif config.Mark != 0 {\n\t\tif err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_MARK, int(config.Mark)); err != nil {\n\t\t\treturn newError(\"failed to set SO_MARK\").Base(err)\n\t\t}\n\t}\n\tif isTCPSocket(network) {\n\t\tswitch config.Tfo {\n\t\tcase SocketConfig_Enable:\n\t\t\tif err := syscall.SetsockoptInt(int(fd), syscall.SOL_TCP, TCP_FASTOPEN, 1); err != nil {\n\t\t\t\treturn newError(\"failed to set TCP_FASTOPEN=1\").Base(err)\n\t\t\t}\n\t\tcase SocketConfig_Disable:\n\t\t\tif err := syscall.SetsockoptInt(int(fd), syscall.SOL_TCP, TCP_FASTOPEN, 0); err != nil {\n\t\t\t\treturn newError(\"failed to set TCP_FASTOPEN=0\").Base(err)\n\t\t\t}\n\t\t}\n\t}\n\n\tif config.Tproxy.IsEnabled() {\n\t\tif err := syscall.SetsockoptInt(int(fd), syscall.SOL_IP, syscall.IP_TRANSPARENT, 1); err != nil {\n\t\t\treturn newError(\"failed to set IP_TRANSPARENT\").Base(err)\n\t\t}\n\t}\n\n\tif config.ReceiveOriginalDestAddress && isUDPSocket(network) {\n\t\terr1 := syscall.SetsockoptInt(int(fd), syscall.SOL_IPV6, unix.IPV6_RECVORIGDSTADDR, 1)\n\t\terr2 := syscall.SetsockoptInt(int(fd), syscall.SOL_IP, syscall.IP_RECVORIGDSTADDR, 1)\n\t\tif err1 != nil && err2 != nil {\n\t\t\treturn err1\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc setReuseAddr(fd uintptr) error {\n\tif err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); err != nil {\n\t\treturn newError(\"failed to set SO_REUSEADDR\").Base(err).AtWarning()\n\t}\n\treturn nil\n}\n\nfunc setReusePort(fd uintptr) error {\n\tif err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, unix.SO_REUSEPORT, 1); err != nil {\n\t\treturn newError(\"failed to set SO_REUSEPORT\").Base(err).AtWarning()\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "transport/internet/sockopt_linux_test.go",
    "content": "package internet_test\n\nimport (\n\t\"context\"\n\t\"syscall\"\n\t\"testing\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/testing/servers/tcp\"\n\t. \"v2ray.com/core/transport/internet\"\n)\n\nfunc TestSockOptMark(t *testing.T) {\n\tt.Skip(\"requires CAP_NET_ADMIN\")\n\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: func(b []byte) []byte {\n\t\t\treturn b\n\t\t},\n\t}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\tdefer tcpServer.Close()\n\n\tconst mark = 1\n\tdialer := DefaultSystemDialer{}\n\tconn, err := dialer.Dial(context.Background(), nil, dest, &SocketConfig{Mark: mark})\n\tcommon.Must(err)\n\tdefer conn.Close()\n\n\trawConn, err := conn.(*net.TCPConn).SyscallConn()\n\tcommon.Must(err)\n\terr = rawConn.Control(func(fd uintptr) {\n\t\tm, err := syscall.GetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_MARK)\n\t\tcommon.Must(err)\n\t\tif mark != m {\n\t\t\tt.Fatal(\"unexpected connection mark\", m, \" want \", mark)\n\t\t}\n\t})\n\tcommon.Must(err)\n}\n"
  },
  {
    "path": "transport/internet/sockopt_other.go",
    "content": "// +build js dragonfly netbsd openbsd solaris\n\npackage internet\n\nfunc applyOutboundSocketOptions(network string, address string, fd uintptr, config *SocketConfig) error {\n\treturn nil\n}\n\nfunc applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig) error {\n\treturn nil\n}\n\nfunc bindAddr(fd uintptr, ip []byte, port uint32) error {\n\treturn nil\n}\n\nfunc setReuseAddr(fd uintptr) error {\n\treturn nil\n}\n\nfunc setReusePort(fd uintptr) error {\n\treturn nil\n}\n"
  },
  {
    "path": "transport/internet/sockopt_test.go",
    "content": "package internet_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/testing/servers/tcp\"\n\t. \"v2ray.com/core/transport/internet\"\n)\n\nfunc TestTCPFastOpen(t *testing.T) {\n\ttcpServer := tcp.Server{\n\t\tMsgProcessor: func(b []byte) []byte {\n\t\t\treturn b\n\t\t},\n\t}\n\tdest, err := tcpServer.StartContext(context.Background(), &SocketConfig{Tfo: SocketConfig_Enable})\n\tcommon.Must(err)\n\tdefer tcpServer.Close()\n\n\tctx := context.Background()\n\tdialer := DefaultSystemDialer{}\n\tconn, err := dialer.Dial(ctx, nil, dest, &SocketConfig{\n\t\tTfo: SocketConfig_Enable,\n\t})\n\tcommon.Must(err)\n\tdefer conn.Close()\n\n\t_, err = conn.Write([]byte(\"abcd\"))\n\tcommon.Must(err)\n\n\tb := buf.New()\n\tcommon.Must2(b.ReadFrom(conn))\n\tif r := cmp.Diff(b.Bytes(), []byte(\"abcd\")); r != \"\" {\n\t\tt.Fatal(r)\n\t}\n}\n"
  },
  {
    "path": "transport/internet/sockopt_windows.go",
    "content": "package internet\n\nimport (\n\t\"syscall\"\n)\n\nconst (\n\tTCP_FASTOPEN = 15\n)\n\nfunc setTFO(fd syscall.Handle, settings SocketConfig_TCPFastOpenState) error {\n\tswitch settings {\n\tcase SocketConfig_Enable:\n\t\tif err := syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, TCP_FASTOPEN, 1); err != nil {\n\t\t\treturn err\n\t\t}\n\tcase SocketConfig_Disable:\n\t\tif err := syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, TCP_FASTOPEN, 0); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc applyOutboundSocketOptions(network string, address string, fd uintptr, config *SocketConfig) error {\n\tif isTCPSocket(network) {\n\t\tif err := setTFO(syscall.Handle(fd), config.Tfo); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t}\n\n\treturn nil\n}\n\nfunc applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig) error {\n\tif isTCPSocket(network) {\n\t\tif err := setTFO(syscall.Handle(fd), config.Tfo); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc bindAddr(fd uintptr, ip []byte, port uint32) error {\n\treturn nil\n}\n\nfunc setReuseAddr(fd uintptr) error {\n\treturn nil\n}\n\nfunc setReusePort(fd uintptr) error {\n\treturn nil\n}\n"
  },
  {
    "path": "transport/internet/system_dialer.go",
    "content": "package internet\n\nimport (\n\t\"context\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/session\"\n)\n\nvar (\n\teffectiveSystemDialer SystemDialer = &DefaultSystemDialer{}\n)\n\ntype SystemDialer interface {\n\tDial(ctx context.Context, source net.Address, destination net.Destination, sockopt *SocketConfig) (net.Conn, error)\n}\n\ntype DefaultSystemDialer struct {\n\tcontrollers []controller\n}\n\nfunc resolveSrcAddr(network net.Network, src net.Address) net.Addr {\n\tif src == nil || src == net.AnyIP {\n\t\treturn nil\n\t}\n\n\tif network == net.Network_TCP {\n\t\treturn &net.TCPAddr{\n\t\t\tIP:   src.IP(),\n\t\t\tPort: 0,\n\t\t}\n\t}\n\n\treturn &net.UDPAddr{\n\t\tIP:   src.IP(),\n\t\tPort: 0,\n\t}\n}\n\nfunc hasBindAddr(sockopt *SocketConfig) bool {\n\treturn sockopt != nil && len(sockopt.BindAddress) > 0 && sockopt.BindPort > 0\n}\n\nfunc (d *DefaultSystemDialer) Dial(ctx context.Context, src net.Address, dest net.Destination, sockopt *SocketConfig) (net.Conn, error) {\n\tif dest.Network == net.Network_UDP && !hasBindAddr(sockopt) {\n\t\tsrcAddr := resolveSrcAddr(net.Network_UDP, src)\n\t\tif srcAddr == nil {\n\t\t\tsrcAddr = &net.UDPAddr{\n\t\t\t\tIP:   []byte{0, 0, 0, 0},\n\t\t\t\tPort: 0,\n\t\t\t}\n\t\t}\n\t\tpacketConn, err := ListenSystemPacket(ctx, srcAddr, sockopt)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tdestAddr, err := net.ResolveUDPAddr(\"udp\", dest.NetAddr())\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn &packetConnWrapper{\n\t\t\tconn: packetConn,\n\t\t\tdest: destAddr,\n\t\t}, nil\n\t}\n\n\tdialer := &net.Dialer{\n\t\tTimeout:   time.Second * 16,\n\t\tDualStack: true,\n\t\tLocalAddr: resolveSrcAddr(dest.Network, src),\n\t}\n\n\tif sockopt != nil || len(d.controllers) > 0 {\n\t\tdialer.Control = func(network, address string, c syscall.RawConn) error {\n\t\t\treturn c.Control(func(fd uintptr) {\n\t\t\t\tif sockopt != nil {\n\t\t\t\t\tif err := applyOutboundSocketOptions(network, address, fd, sockopt); err != nil {\n\t\t\t\t\t\tnewError(\"failed to apply socket options\").Base(err).WriteToLog(session.ExportIDToError(ctx))\n\t\t\t\t\t}\n\t\t\t\t\tif dest.Network == net.Network_UDP && hasBindAddr(sockopt) {\n\t\t\t\t\t\tif err := bindAddr(fd, sockopt.BindAddress, sockopt.BindPort); err != nil {\n\t\t\t\t\t\t\tnewError(\"failed to bind source address to \", sockopt.BindAddress).Base(err).WriteToLog(session.ExportIDToError(ctx))\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfor _, ctl := range d.controllers {\n\t\t\t\t\tif err := ctl(network, address, fd); err != nil {\n\t\t\t\t\t\tnewError(\"failed to apply external controller\").Base(err).WriteToLog(session.ExportIDToError(ctx))\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t}\n\n\treturn dialer.DialContext(ctx, dest.Network.SystemString(), dest.NetAddr())\n}\n\ntype packetConnWrapper struct {\n\tconn net.PacketConn\n\tdest net.Addr\n}\n\nfunc (c *packetConnWrapper) Close() error {\n\treturn c.conn.Close()\n}\n\nfunc (c *packetConnWrapper) LocalAddr() net.Addr {\n\treturn c.conn.LocalAddr()\n}\n\nfunc (c *packetConnWrapper) RemoteAddr() net.Addr {\n\treturn c.dest\n}\n\nfunc (c *packetConnWrapper) Write(p []byte) (int, error) {\n\treturn c.conn.WriteTo(p, c.dest)\n}\n\nfunc (c *packetConnWrapper) Read(p []byte) (int, error) {\n\tn, _, err := c.conn.ReadFrom(p)\n\treturn n, err\n}\n\nfunc (c *packetConnWrapper) SetDeadline(t time.Time) error {\n\treturn c.conn.SetDeadline(t)\n}\n\nfunc (c *packetConnWrapper) SetReadDeadline(t time.Time) error {\n\treturn c.conn.SetReadDeadline(t)\n}\n\nfunc (c *packetConnWrapper) SetWriteDeadline(t time.Time) error {\n\treturn c.conn.SetWriteDeadline(t)\n}\n\ntype SystemDialerAdapter interface {\n\tDial(network string, address string) (net.Conn, error)\n}\n\ntype SimpleSystemDialer struct {\n\tadapter SystemDialerAdapter\n}\n\nfunc WithAdapter(dialer SystemDialerAdapter) SystemDialer {\n\treturn &SimpleSystemDialer{\n\t\tadapter: dialer,\n\t}\n}\n\nfunc (v *SimpleSystemDialer) Dial(ctx context.Context, src net.Address, dest net.Destination, sockopt *SocketConfig) (net.Conn, error) {\n\treturn v.adapter.Dial(dest.Network.SystemString(), dest.NetAddr())\n}\n\n// UseAlternativeSystemDialer replaces the current system dialer with a given one.\n// Caller must ensure there is no race condition.\n//\n// v2ray:api:stable\nfunc UseAlternativeSystemDialer(dialer SystemDialer) {\n\tif dialer == nil {\n\t\teffectiveSystemDialer = &DefaultSystemDialer{}\n\t}\n\teffectiveSystemDialer = dialer\n}\n\n// RegisterDialerController adds a controller to the effective system dialer.\n// The controller can be used to operate on file descriptors before they are put into use.\n// It only works when effective dialer is the default dialer.\n//\n// v2ray:api:beta\nfunc RegisterDialerController(ctl func(network, address string, fd uintptr) error) error {\n\tif ctl == nil {\n\t\treturn newError(\"nil listener controller\")\n\t}\n\n\tdialer, ok := effectiveSystemDialer.(*DefaultSystemDialer)\n\tif !ok {\n\t\treturn newError(\"RegisterListenerController not supported in custom dialer\")\n\t}\n\n\tdialer.controllers = append(dialer.controllers, ctl)\n\treturn nil\n}\n"
  },
  {
    "path": "transport/internet/system_listener.go",
    "content": "package internet\n\nimport (\n\t\"context\"\n\t\"syscall\"\n\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/session\"\n)\n\nvar (\n\teffectiveListener = DefaultListener{}\n)\n\ntype controller func(network, address string, fd uintptr) error\n\ntype DefaultListener struct {\n\tcontrollers []controller\n}\n\nfunc getControlFunc(ctx context.Context, sockopt *SocketConfig, controllers []controller) func(network, address string, c syscall.RawConn) error {\n\treturn func(network, address string, c syscall.RawConn) error {\n\t\treturn c.Control(func(fd uintptr) {\n\t\t\tif sockopt != nil {\n\t\t\t\tif err := applyInboundSocketOptions(network, fd, sockopt); err != nil {\n\t\t\t\t\tnewError(\"failed to apply socket options to incoming connection\").Base(err).WriteToLog(session.ExportIDToError(ctx))\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tsetReusePort(fd)\n\n\t\t\tfor _, controller := range controllers {\n\t\t\t\tif err := controller(network, address, fd); err != nil {\n\t\t\t\t\tnewError(\"failed to apply external controller\").Base(err).WriteToLog(session.ExportIDToError(ctx))\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc (dl *DefaultListener) Listen(ctx context.Context, addr net.Addr, sockopt *SocketConfig) (net.Listener, error) {\n\tvar lc net.ListenConfig\n\n\tlc.Control = getControlFunc(ctx, sockopt, dl.controllers)\n\n\treturn lc.Listen(ctx, addr.Network(), addr.String())\n}\n\nfunc (dl *DefaultListener) ListenPacket(ctx context.Context, addr net.Addr, sockopt *SocketConfig) (net.PacketConn, error) {\n\tvar lc net.ListenConfig\n\n\tlc.Control = getControlFunc(ctx, sockopt, dl.controllers)\n\n\treturn lc.ListenPacket(ctx, addr.Network(), addr.String())\n}\n\n// RegisterListenerController adds a controller to the effective system listener.\n// The controller can be used to operate on file descriptors before they are put into use.\n//\n// v2ray:api:beta\nfunc RegisterListenerController(controller func(network, address string, fd uintptr) error) error {\n\tif controller == nil {\n\t\treturn newError(\"nil listener controller\")\n\t}\n\n\teffectiveListener.controllers = append(effectiveListener.controllers, controller)\n\treturn nil\n}\n"
  },
  {
    "path": "transport/internet/system_listener_test.go",
    "content": "package internet_test\n\nimport (\n\t\"context\"\n\t\"net\"\n\t\"testing\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/transport/internet\"\n)\n\nfunc TestRegisterListenerController(t *testing.T) {\n\tvar gotFd uintptr\n\n\tcommon.Must(internet.RegisterListenerController(func(network string, addr string, fd uintptr) error {\n\t\tgotFd = fd\n\t\treturn nil\n\t}))\n\n\tconn, err := internet.ListenSystemPacket(context.Background(), &net.UDPAddr{\n\t\tIP: net.IPv4zero,\n\t}, nil)\n\tcommon.Must(err)\n\tcommon.Must(conn.Close())\n\n\tif gotFd == 0 {\n\t\tt.Error(\"expected none-zero fd, but actually 0\")\n\t}\n}\n"
  },
  {
    "path": "transport/internet/tcp/config.go",
    "content": "// +build !confonly\n\npackage tcp\n\nimport (\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/transport/internet\"\n)\n\nconst protocolName = \"tcp\"\n\nfunc init() {\n\tcommon.Must(internet.RegisterProtocolConfigCreator(protocolName, func() interface{} {\n\t\treturn new(Config)\n\t}))\n}\n"
  },
  {
    "path": "transport/internet/tcp/config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: transport/internet/tcp/config.proto\n\npackage tcp\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n\tserial \"v2ray.com/core/common/serial\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype Config struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tHeaderSettings      *serial.TypedMessage `protobuf:\"bytes,2,opt,name=header_settings,json=headerSettings,proto3\" json:\"header_settings,omitempty\"`\n\tAcceptProxyProtocol bool                 `protobuf:\"varint,3,opt,name=accept_proxy_protocol,json=acceptProxyProtocol,proto3\" json:\"accept_proxy_protocol,omitempty\"`\n}\n\nfunc (x *Config) Reset() {\n\t*x = Config{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_transport_internet_tcp_config_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Config) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Config) ProtoMessage() {}\n\nfunc (x *Config) ProtoReflect() protoreflect.Message {\n\tmi := &file_transport_internet_tcp_config_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Config.ProtoReflect.Descriptor instead.\nfunc (*Config) Descriptor() ([]byte, []int) {\n\treturn file_transport_internet_tcp_config_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *Config) GetHeaderSettings() *serial.TypedMessage {\n\tif x != nil {\n\t\treturn x.HeaderSettings\n\t}\n\treturn nil\n}\n\nfunc (x *Config) GetAcceptProxyProtocol() bool {\n\tif x != nil {\n\t\treturn x.AcceptProxyProtocol\n\t}\n\treturn false\n}\n\nvar File_transport_internet_tcp_config_proto protoreflect.FileDescriptor\n\nvar file_transport_internet_tcp_config_proto_rawDesc = []byte{\n\t0x0a, 0x23, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65,\n\t0x72, 0x6e, 0x65, 0x74, 0x2f, 0x74, 0x63, 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e,\n\t0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x21, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72,\n\t0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65,\n\t0x72, 0x6e, 0x65, 0x74, 0x2e, 0x74, 0x63, 0x70, 0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,\n\t0x2f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x6d, 0x65,\n\t0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x93, 0x01, 0x0a, 0x06,\n\t0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x4f, 0x0a, 0x0f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72,\n\t0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,\n\t0x26, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d,\n\t0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64,\n\t0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x53,\n\t0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x32, 0x0a, 0x15, 0x61, 0x63, 0x63, 0x65, 0x70,\n\t0x74, 0x5f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c,\n\t0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x50, 0x72,\n\t0x6f, 0x78, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x4a, 0x04, 0x08, 0x01, 0x10,\n\t0x02, 0x42, 0x74, 0x0a, 0x25, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,\n\t0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e,\n\t0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x74, 0x63, 0x70, 0x50, 0x01, 0x5a, 0x25, 0x76, 0x32,\n\t0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72, 0x61,\n\t0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2f,\n\t0x74, 0x63, 0x70, 0xaa, 0x02, 0x21, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65,\n\t0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72,\n\t0x6e, 0x65, 0x74, 0x2e, 0x54, 0x63, 0x70, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_transport_internet_tcp_config_proto_rawDescOnce sync.Once\n\tfile_transport_internet_tcp_config_proto_rawDescData = file_transport_internet_tcp_config_proto_rawDesc\n)\n\nfunc file_transport_internet_tcp_config_proto_rawDescGZIP() []byte {\n\tfile_transport_internet_tcp_config_proto_rawDescOnce.Do(func() {\n\t\tfile_transport_internet_tcp_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_transport_internet_tcp_config_proto_rawDescData)\n\t})\n\treturn file_transport_internet_tcp_config_proto_rawDescData\n}\n\nvar file_transport_internet_tcp_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)\nvar file_transport_internet_tcp_config_proto_goTypes = []interface{}{\n\t(*Config)(nil),              // 0: v2ray.core.transport.internet.tcp.Config\n\t(*serial.TypedMessage)(nil), // 1: v2ray.core.common.serial.TypedMessage\n}\nvar file_transport_internet_tcp_config_proto_depIdxs = []int32{\n\t1, // 0: v2ray.core.transport.internet.tcp.Config.header_settings:type_name -> v2ray.core.common.serial.TypedMessage\n\t1, // [1:1] is the sub-list for method output_type\n\t1, // [1:1] is the sub-list for method input_type\n\t1, // [1:1] is the sub-list for extension type_name\n\t1, // [1:1] is the sub-list for extension extendee\n\t0, // [0:1] is the sub-list for field type_name\n}\n\nfunc init() { file_transport_internet_tcp_config_proto_init() }\nfunc file_transport_internet_tcp_config_proto_init() {\n\tif File_transport_internet_tcp_config_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_transport_internet_tcp_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Config); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_transport_internet_tcp_config_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   1,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_transport_internet_tcp_config_proto_goTypes,\n\t\tDependencyIndexes: file_transport_internet_tcp_config_proto_depIdxs,\n\t\tMessageInfos:      file_transport_internet_tcp_config_proto_msgTypes,\n\t}.Build()\n\tFile_transport_internet_tcp_config_proto = out.File\n\tfile_transport_internet_tcp_config_proto_rawDesc = nil\n\tfile_transport_internet_tcp_config_proto_goTypes = nil\n\tfile_transport_internet_tcp_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "transport/internet/tcp/config.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.transport.internet.tcp;\noption csharp_namespace = \"V2Ray.Core.Transport.Internet.Tcp\";\noption go_package = \"v2ray.com/core/transport/internet/tcp\";\noption java_package = \"com.v2ray.core.transport.internet.tcp\";\noption java_multiple_files = true;\n\nimport \"common/serial/typed_message.proto\";\n\nmessage Config {\n  reserved 1;\n  v2ray.core.common.serial.TypedMessage header_settings = 2;\n  bool accept_proxy_protocol = 3;\n}\n"
  },
  {
    "path": "transport/internet/tcp/dialer.go",
    "content": "// +build !confonly\n\npackage tcp\n\nimport (\n\t\"context\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/session\"\n\t\"v2ray.com/core/transport/internet\"\n\t\"v2ray.com/core/transport/internet/tls\"\n\t\"v2ray.com/core/transport/internet/xtls\"\n)\n\n// Dial dials a new TCP connection to the given destination.\nfunc Dial(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (internet.Connection, error) {\n\tnewError(\"dialing TCP to \", dest).WriteToLog(session.ExportIDToError(ctx))\n\tconn, err := internet.DialSystem(ctx, dest, streamSettings.SocketSettings)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif config := tls.ConfigFromStreamSettings(streamSettings); config != nil {\n\t\ttlsConfig := config.GetTLSConfig(tls.WithDestination(dest))\n\t\t/*\n\t\t\tif config.IsExperiment8357() {\n\t\t\t\tconn = tls.UClient(conn, tlsConfig)\n\t\t\t} else {\n\t\t\t\tconn = tls.Client(conn, tlsConfig)\n\t\t\t}\n\t\t*/\n\t\tconn = tls.Client(conn, tlsConfig)\n\t} else if config := xtls.ConfigFromStreamSettings(streamSettings); config != nil {\n\t\txtlsConfig := config.GetXTLSConfig(xtls.WithDestination(dest))\n\t\tconn = xtls.Client(conn, xtlsConfig)\n\t}\n\n\ttcpSettings := streamSettings.ProtocolSettings.(*Config)\n\tif tcpSettings.HeaderSettings != nil {\n\t\theaderConfig, err := tcpSettings.HeaderSettings.GetInstance()\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"failed to get header settings\").Base(err).AtError()\n\t\t}\n\t\tauth, err := internet.CreateConnectionAuthenticator(headerConfig)\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"failed to create header authenticator\").Base(err).AtError()\n\t\t}\n\t\tconn = auth.Client(conn)\n\t}\n\treturn internet.Connection(conn), nil\n}\n\nfunc init() {\n\tcommon.Must(internet.RegisterTransportDialer(protocolName, Dial))\n}\n"
  },
  {
    "path": "transport/internet/tcp/errors.generated.go",
    "content": "package tcp\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "transport/internet/tcp/hub.go",
    "content": "// +build !confonly\n\npackage tcp\n\nimport (\n\t\"context\"\n\tgotls \"crypto/tls\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/pires/go-proxyproto\"\n\tgoxtls \"github.com/xtls/go\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/session\"\n\t\"v2ray.com/core/transport/internet\"\n\t\"v2ray.com/core/transport/internet/tls\"\n\t\"v2ray.com/core/transport/internet/xtls\"\n)\n\n// Listener is an internet.Listener that listens for TCP connections.\ntype Listener struct {\n\tlistener   net.Listener\n\ttlsConfig  *gotls.Config\n\txtlsConfig *goxtls.Config\n\tauthConfig internet.ConnectionAuthenticator\n\tconfig     *Config\n\taddConn    internet.ConnHandler\n}\n\n// ListenTCP creates a new Listener based on configurations.\nfunc ListenTCP(ctx context.Context, address net.Address, port net.Port, streamSettings *internet.MemoryStreamConfig, handler internet.ConnHandler) (internet.Listener, error) {\n\tlistener, err := internet.ListenSystem(ctx, &net.TCPAddr{\n\t\tIP:   address.IP(),\n\t\tPort: int(port),\n\t}, streamSettings.SocketSettings)\n\tif err != nil {\n\t\treturn nil, newError(\"failed to listen TCP on\", address, \":\", port).Base(err)\n\t}\n\tnewError(\"listening TCP on \", address, \":\", port).WriteToLog(session.ExportIDToError(ctx))\n\n\ttcpSettings := streamSettings.ProtocolSettings.(*Config)\n\tvar l *Listener\n\n\tif tcpSettings.AcceptProxyProtocol {\n\t\tpolicyFunc := func(upstream net.Addr) (proxyproto.Policy, error) { return proxyproto.REQUIRE, nil }\n\t\tl = &Listener{\n\t\t\tlistener: &proxyproto.Listener{Listener: listener, Policy: policyFunc},\n\t\t\tconfig:   tcpSettings,\n\t\t\taddConn:  handler,\n\t\t}\n\t\tnewError(\"accepting PROXY protocol\").AtWarning().WriteToLog(session.ExportIDToError(ctx))\n\t} else {\n\t\tl = &Listener{\n\t\t\tlistener: listener,\n\t\t\tconfig:   tcpSettings,\n\t\t\taddConn:  handler,\n\t\t}\n\t}\n\n\tif config := tls.ConfigFromStreamSettings(streamSettings); config != nil {\n\t\tl.tlsConfig = config.GetTLSConfig(tls.WithNextProto(\"h2\"))\n\t}\n\tif config := xtls.ConfigFromStreamSettings(streamSettings); config != nil {\n\t\tl.xtlsConfig = config.GetXTLSConfig(xtls.WithNextProto(\"h2\"))\n\t}\n\n\tif tcpSettings.HeaderSettings != nil {\n\t\theaderConfig, err := tcpSettings.HeaderSettings.GetInstance()\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"invalid header settings\").Base(err).AtError()\n\t\t}\n\t\tauth, err := internet.CreateConnectionAuthenticator(headerConfig)\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"invalid header settings.\").Base(err).AtError()\n\t\t}\n\t\tl.authConfig = auth\n\t}\n\n\tgo l.keepAccepting()\n\treturn l, nil\n}\n\nfunc (v *Listener) keepAccepting() {\n\tfor {\n\t\tconn, err := v.listener.Accept()\n\t\tif err != nil {\n\t\t\terrStr := err.Error()\n\t\t\tif strings.Contains(errStr, \"closed\") {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tnewError(\"failed to accepted raw connections\").Base(err).AtWarning().WriteToLog()\n\t\t\tif strings.Contains(errStr, \"too many\") {\n\t\t\t\ttime.Sleep(time.Millisecond * 500)\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\tif v.tlsConfig != nil {\n\t\t\tconn = tls.Server(conn, v.tlsConfig)\n\t\t} else if v.xtlsConfig != nil {\n\t\t\tconn = xtls.Server(conn, v.xtlsConfig)\n\t\t}\n\t\tif v.authConfig != nil {\n\t\t\tconn = v.authConfig.Server(conn)\n\t\t}\n\n\t\tv.addConn(internet.Connection(conn))\n\t}\n}\n\n// Addr implements internet.Listener.Addr.\nfunc (v *Listener) Addr() net.Addr {\n\treturn v.listener.Addr()\n}\n\n// Close implements internet.Listener.Close.\nfunc (v *Listener) Close() error {\n\treturn v.listener.Close()\n}\n\nfunc init() {\n\tcommon.Must(internet.RegisterTransportListener(protocolName, ListenTCP))\n}\n"
  },
  {
    "path": "transport/internet/tcp/sockopt_freebsd.go",
    "content": "// +build freebsd\n// +build !confonly\n\npackage tcp\n\nimport (\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/transport/internet\"\n)\n\n// GetOriginalDestination from tcp conn\nfunc GetOriginalDestination(conn internet.Connection) (net.Destination, error) {\n\tla := conn.LocalAddr()\n\tra := conn.RemoteAddr()\n\tip, port, err := internet.OriginalDst(la, ra)\n\tif err != nil {\n\t\treturn net.Destination{}, newError(\"failed to get destination\").Base(err)\n\t}\n\tdest := net.TCPDestination(net.IPAddress(ip), net.Port(port))\n\tif !dest.IsValid() {\n\t\treturn net.Destination{}, newError(\"failed to parse destination.\")\n\t}\n\treturn dest, nil\n}\n"
  },
  {
    "path": "transport/internet/tcp/sockopt_linux.go",
    "content": "// +build linux\n// +build !confonly\n\npackage tcp\n\nimport (\n\t\"syscall\"\n\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/transport/internet\"\n)\n\nconst SO_ORIGINAL_DST = 80\n\nfunc GetOriginalDestination(conn internet.Connection) (net.Destination, error) {\n\tsysrawconn, f := conn.(syscall.Conn)\n\tif !f {\n\t\treturn net.Destination{}, newError(\"unable to get syscall.Conn\")\n\t}\n\trawConn, err := sysrawconn.SyscallConn()\n\tif err != nil {\n\t\treturn net.Destination{}, newError(\"failed to get sys fd\").Base(err)\n\t}\n\tvar dest net.Destination\n\terr = rawConn.Control(func(fd uintptr) {\n\t\taddr, err := syscall.GetsockoptIPv6Mreq(int(fd), syscall.IPPROTO_IP, SO_ORIGINAL_DST)\n\t\tif err != nil {\n\t\t\tnewError(\"failed to call getsockopt\").Base(err).WriteToLog()\n\t\t\treturn\n\t\t}\n\t\tip := net.IPAddress(addr.Multiaddr[4:8])\n\t\tport := uint16(addr.Multiaddr[2])<<8 + uint16(addr.Multiaddr[3])\n\t\tdest = net.TCPDestination(ip, net.Port(port))\n\t})\n\tif err != nil {\n\t\treturn net.Destination{}, newError(\"failed to control connection\").Base(err)\n\t}\n\tif !dest.IsValid() {\n\t\treturn net.Destination{}, newError(\"failed to call getsockopt\")\n\t}\n\treturn dest, nil\n}\n"
  },
  {
    "path": "transport/internet/tcp/sockopt_linux_test.go",
    "content": "// +build linux\n\npackage tcp_test\n\nimport (\n\t\"context\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/testing/servers/tcp\"\n\t\"v2ray.com/core/transport/internet\"\n\t. \"v2ray.com/core/transport/internet/tcp\"\n)\n\nfunc TestGetOriginalDestination(t *testing.T) {\n\ttcpServer := tcp.Server{}\n\tdest, err := tcpServer.Start()\n\tcommon.Must(err)\n\tdefer tcpServer.Close()\n\n\tconfig, err := internet.ToMemoryStreamConfig(nil)\n\tcommon.Must(err)\n\tconn, err := Dial(context.Background(), dest, config)\n\tcommon.Must(err)\n\tdefer conn.Close()\n\n\toriginalDest, err := GetOriginalDestination(conn)\n\tif !(dest == originalDest || strings.Contains(err.Error(), \"failed to call getsockopt\")) {\n\t\tt.Error(\"unexpected state\")\n\t}\n}\n"
  },
  {
    "path": "transport/internet/tcp/sockopt_other.go",
    "content": "// +build !linux,!freebsd\n// +build !confonly\n\npackage tcp\n\nimport (\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/transport/internet\"\n)\n\nfunc GetOriginalDestination(conn internet.Connection) (net.Destination, error) {\n\treturn net.Destination{}, nil\n}\n"
  },
  {
    "path": "transport/internet/tcp/tcp.go",
    "content": "package tcp\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n"
  },
  {
    "path": "transport/internet/tcp_hub.go",
    "content": "package internet\n\nimport (\n\t\"context\"\n\n\t\"v2ray.com/core/common/net\"\n)\n\nvar (\n\ttransportListenerCache = make(map[string]ListenFunc)\n)\n\nfunc RegisterTransportListener(protocol string, listener ListenFunc) error {\n\tif _, found := transportListenerCache[protocol]; found {\n\t\treturn newError(protocol, \" listener already registered.\").AtError()\n\t}\n\ttransportListenerCache[protocol] = listener\n\treturn nil\n}\n\ntype ConnHandler func(Connection)\n\ntype ListenFunc func(ctx context.Context, address net.Address, port net.Port, settings *MemoryStreamConfig, handler ConnHandler) (Listener, error)\n\ntype Listener interface {\n\tClose() error\n\tAddr() net.Addr\n}\n\nfunc ListenTCP(ctx context.Context, address net.Address, port net.Port, settings *MemoryStreamConfig, handler ConnHandler) (Listener, error) {\n\tif settings == nil {\n\t\ts, err := ToMemoryStreamConfig(nil)\n\t\tif err != nil {\n\t\t\treturn nil, newError(\"failed to create default stream settings\").Base(err)\n\t\t}\n\t\tsettings = s\n\t}\n\n\tif address.Family().IsDomain() && address.Domain() == \"localhost\" {\n\t\taddress = net.LocalHostIP\n\t}\n\n\tif address.Family().IsDomain() {\n\t\treturn nil, newError(\"domain address is not allowed for listening: \", address.Domain())\n\t}\n\n\tprotocol := settings.ProtocolName\n\tlistenFunc := transportListenerCache[protocol]\n\tif listenFunc == nil {\n\t\treturn nil, newError(protocol, \" listener not registered.\").AtError()\n\t}\n\tlistener, err := listenFunc(ctx, address, port, settings, handler)\n\tif err != nil {\n\t\treturn nil, newError(\"failed to listen on address: \", address, \":\", port).Base(err)\n\t}\n\treturn listener, nil\n}\n\n// ListenSystem listens on a local address for incoming TCP connections.\n//\n// v2ray:api:beta\nfunc ListenSystem(ctx context.Context, addr net.Addr, sockopt *SocketConfig) (net.Listener, error) {\n\treturn effectiveListener.Listen(ctx, addr, sockopt)\n}\n\n// ListenSystemPacket listens on a local address for incoming UDP connections.\n//\n// v2ray:api:beta\nfunc ListenSystemPacket(ctx context.Context, addr net.Addr, sockopt *SocketConfig) (net.PacketConn, error) {\n\treturn effectiveListener.ListenPacket(ctx, addr, sockopt)\n}\n"
  },
  {
    "path": "transport/internet/tls/config.go",
    "content": "// +build !confonly\n\npackage tls\n\nimport (\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol/tls/cert\"\n\t\"v2ray.com/core/transport/internet\"\n)\n\nvar (\n\tglobalSessionCache = tls.NewLRUClientSessionCache(128)\n)\n\nconst exp8357 = \"experiment:8357\"\n\n// ParseCertificate converts a cert.Certificate to Certificate.\nfunc ParseCertificate(c *cert.Certificate) *Certificate {\n\tcertPEM, keyPEM := c.ToPEM()\n\treturn &Certificate{\n\t\tCertificate: certPEM,\n\t\tKey:         keyPEM,\n\t}\n}\n\nfunc (c *Config) loadSelfCertPool() (*x509.CertPool, error) {\n\troot := x509.NewCertPool()\n\tfor _, cert := range c.Certificate {\n\t\tif !root.AppendCertsFromPEM(cert.Certificate) {\n\t\t\treturn nil, newError(\"failed to append cert\").AtWarning()\n\t\t}\n\t}\n\treturn root, nil\n}\n\n// BuildCertificates builds a list of TLS certificates from proto definition.\nfunc (c *Config) BuildCertificates() []tls.Certificate {\n\tcerts := make([]tls.Certificate, 0, len(c.Certificate))\n\tfor _, entry := range c.Certificate {\n\t\tif entry.Usage != Certificate_ENCIPHERMENT {\n\t\t\tcontinue\n\t\t}\n\t\tkeyPair, err := tls.X509KeyPair(entry.Certificate, entry.Key)\n\t\tif err != nil {\n\t\t\tnewError(\"ignoring invalid X509 key pair\").Base(err).AtWarning().WriteToLog()\n\t\t\tcontinue\n\t\t}\n\t\tcerts = append(certs, keyPair)\n\t}\n\treturn certs\n}\n\nfunc isCertificateExpired(c *tls.Certificate) bool {\n\tif c.Leaf == nil && len(c.Certificate) > 0 {\n\t\tif pc, err := x509.ParseCertificate(c.Certificate[0]); err == nil {\n\t\t\tc.Leaf = pc\n\t\t}\n\t}\n\n\t// If leaf is not there, the certificate is probably not used yet. We trust user to provide a valid certificate.\n\treturn c.Leaf != nil && c.Leaf.NotAfter.Before(time.Now().Add(-time.Minute))\n}\n\nfunc issueCertificate(rawCA *Certificate, domain string) (*tls.Certificate, error) {\n\tparent, err := cert.ParseCertificate(rawCA.Certificate, rawCA.Key)\n\tif err != nil {\n\t\treturn nil, newError(\"failed to parse raw certificate\").Base(err)\n\t}\n\tnewCert, err := cert.Generate(parent, cert.CommonName(domain), cert.DNSNames(domain))\n\tif err != nil {\n\t\treturn nil, newError(\"failed to generate new certificate for \", domain).Base(err)\n\t}\n\tnewCertPEM, newKeyPEM := newCert.ToPEM()\n\tcert, err := tls.X509KeyPair(newCertPEM, newKeyPEM)\n\treturn &cert, err\n}\n\nfunc (c *Config) getCustomCA() []*Certificate {\n\tcerts := make([]*Certificate, 0, len(c.Certificate))\n\tfor _, certificate := range c.Certificate {\n\t\tif certificate.Usage == Certificate_AUTHORITY_ISSUE {\n\t\t\tcerts = append(certs, certificate)\n\t\t}\n\t}\n\treturn certs\n}\n\nfunc getGetCertificateFunc(c *tls.Config, ca []*Certificate) func(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {\n\tvar access sync.RWMutex\n\n\treturn func(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {\n\t\tdomain := hello.ServerName\n\t\tcertExpired := false\n\n\t\taccess.RLock()\n\t\tcertificate, found := c.NameToCertificate[domain]\n\t\taccess.RUnlock()\n\n\t\tif found {\n\t\t\tif !isCertificateExpired(certificate) {\n\t\t\t\treturn certificate, nil\n\t\t\t}\n\t\t\tcertExpired = true\n\t\t}\n\n\t\tif certExpired {\n\t\t\tnewCerts := make([]tls.Certificate, 0, len(c.Certificates))\n\n\t\t\taccess.Lock()\n\t\t\tfor _, certificate := range c.Certificates {\n\t\t\t\tif !isCertificateExpired(&certificate) {\n\t\t\t\t\tnewCerts = append(newCerts, certificate)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tc.Certificates = newCerts\n\t\t\taccess.Unlock()\n\t\t}\n\n\t\tvar issuedCertificate *tls.Certificate\n\n\t\t// Create a new certificate from existing CA if possible\n\t\tfor _, rawCert := range ca {\n\t\t\tif rawCert.Usage == Certificate_AUTHORITY_ISSUE {\n\t\t\t\tnewCert, err := issueCertificate(rawCert, domain)\n\t\t\t\tif err != nil {\n\t\t\t\t\tnewError(\"failed to issue new certificate for \", domain).Base(err).WriteToLog()\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\taccess.Lock()\n\t\t\t\tc.Certificates = append(c.Certificates, *newCert)\n\t\t\t\tissuedCertificate = &c.Certificates[len(c.Certificates)-1]\n\t\t\t\taccess.Unlock()\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif issuedCertificate == nil {\n\t\t\treturn nil, newError(\"failed to create a new certificate for \", domain)\n\t\t}\n\n\t\taccess.Lock()\n\t\tc.BuildNameToCertificate()\n\t\taccess.Unlock()\n\n\t\treturn issuedCertificate, nil\n\t}\n}\n\nfunc (c *Config) IsExperiment8357() bool {\n\treturn strings.HasPrefix(c.ServerName, exp8357)\n}\n\nfunc (c *Config) parseServerName() string {\n\tif c.IsExperiment8357() {\n\t\treturn c.ServerName[len(exp8357):]\n\t}\n\n\treturn c.ServerName\n}\n\n// GetTLSConfig converts this Config into tls.Config.\nfunc (c *Config) GetTLSConfig(opts ...Option) *tls.Config {\n\troot, err := c.getCertPool()\n\tif err != nil {\n\t\tnewError(\"failed to load system root certificate\").AtError().Base(err).WriteToLog()\n\t}\n\n\tconfig := &tls.Config{\n\t\tClientSessionCache:     globalSessionCache,\n\t\tRootCAs:                root,\n\t\tInsecureSkipVerify:     c.AllowInsecure,\n\t\tNextProtos:             c.NextProtocol,\n\t\tSessionTicketsDisabled: c.DisableSessionResumption,\n\t}\n\tif c == nil {\n\t\treturn config\n\t}\n\n\tfor _, opt := range opts {\n\t\topt(config)\n\t}\n\n\tconfig.Certificates = c.BuildCertificates()\n\tconfig.BuildNameToCertificate()\n\n\tcaCerts := c.getCustomCA()\n\tif len(caCerts) > 0 {\n\t\tconfig.GetCertificate = getGetCertificateFunc(config, caCerts)\n\t}\n\n\tif sn := c.parseServerName(); len(sn) > 0 {\n\t\tconfig.ServerName = sn\n\t}\n\n\tif len(config.NextProtos) == 0 {\n\t\tconfig.NextProtos = []string{\"h2\", \"http/1.1\"}\n\t}\n\n\treturn config\n}\n\n// Option for building TLS config.\ntype Option func(*tls.Config)\n\n// WithDestination sets the server name in TLS config.\nfunc WithDestination(dest net.Destination) Option {\n\treturn func(config *tls.Config) {\n\t\tif dest.Address.Family().IsDomain() && config.ServerName == \"\" {\n\t\t\tconfig.ServerName = dest.Address.Domain()\n\t\t}\n\t}\n}\n\n// WithNextProto sets the ALPN values in TLS config.\nfunc WithNextProto(protocol ...string) Option {\n\treturn func(config *tls.Config) {\n\t\tif len(config.NextProtos) == 0 {\n\t\t\tconfig.NextProtos = protocol\n\t\t}\n\t}\n}\n\n// ConfigFromStreamSettings fetches Config from stream settings. Nil if not found.\nfunc ConfigFromStreamSettings(settings *internet.MemoryStreamConfig) *Config {\n\tif settings == nil {\n\t\treturn nil\n\t}\n\tconfig, ok := settings.SecuritySettings.(*Config)\n\tif !ok {\n\t\treturn nil\n\t}\n\treturn config\n}\n"
  },
  {
    "path": "transport/internet/tls/config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: transport/internet/tls/config.proto\n\npackage tls\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype Certificate_Usage int32\n\nconst (\n\tCertificate_ENCIPHERMENT     Certificate_Usage = 0\n\tCertificate_AUTHORITY_VERIFY Certificate_Usage = 1\n\tCertificate_AUTHORITY_ISSUE  Certificate_Usage = 2\n)\n\n// Enum value maps for Certificate_Usage.\nvar (\n\tCertificate_Usage_name = map[int32]string{\n\t\t0: \"ENCIPHERMENT\",\n\t\t1: \"AUTHORITY_VERIFY\",\n\t\t2: \"AUTHORITY_ISSUE\",\n\t}\n\tCertificate_Usage_value = map[string]int32{\n\t\t\"ENCIPHERMENT\":     0,\n\t\t\"AUTHORITY_VERIFY\": 1,\n\t\t\"AUTHORITY_ISSUE\":  2,\n\t}\n)\n\nfunc (x Certificate_Usage) Enum() *Certificate_Usage {\n\tp := new(Certificate_Usage)\n\t*p = x\n\treturn p\n}\n\nfunc (x Certificate_Usage) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (Certificate_Usage) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_transport_internet_tls_config_proto_enumTypes[0].Descriptor()\n}\n\nfunc (Certificate_Usage) Type() protoreflect.EnumType {\n\treturn &file_transport_internet_tls_config_proto_enumTypes[0]\n}\n\nfunc (x Certificate_Usage) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use Certificate_Usage.Descriptor instead.\nfunc (Certificate_Usage) EnumDescriptor() ([]byte, []int) {\n\treturn file_transport_internet_tls_config_proto_rawDescGZIP(), []int{0, 0}\n}\n\ntype Certificate struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// TLS certificate in x509 format.\n\tCertificate []byte `protobuf:\"bytes,1,opt,name=Certificate,proto3\" json:\"Certificate,omitempty\"`\n\t// TLS key in x509 format.\n\tKey   []byte            `protobuf:\"bytes,2,opt,name=Key,proto3\" json:\"Key,omitempty\"`\n\tUsage Certificate_Usage `protobuf:\"varint,3,opt,name=usage,proto3,enum=v2ray.core.transport.internet.tls.Certificate_Usage\" json:\"usage,omitempty\"`\n}\n\nfunc (x *Certificate) Reset() {\n\t*x = Certificate{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_transport_internet_tls_config_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Certificate) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Certificate) ProtoMessage() {}\n\nfunc (x *Certificate) ProtoReflect() protoreflect.Message {\n\tmi := &file_transport_internet_tls_config_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Certificate.ProtoReflect.Descriptor instead.\nfunc (*Certificate) Descriptor() ([]byte, []int) {\n\treturn file_transport_internet_tls_config_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *Certificate) GetCertificate() []byte {\n\tif x != nil {\n\t\treturn x.Certificate\n\t}\n\treturn nil\n}\n\nfunc (x *Certificate) GetKey() []byte {\n\tif x != nil {\n\t\treturn x.Key\n\t}\n\treturn nil\n}\n\nfunc (x *Certificate) GetUsage() Certificate_Usage {\n\tif x != nil {\n\t\treturn x.Usage\n\t}\n\treturn Certificate_ENCIPHERMENT\n}\n\ntype Config struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Whether or not to allow self-signed certificates.\n\tAllowInsecure bool `protobuf:\"varint,1,opt,name=allow_insecure,json=allowInsecure,proto3\" json:\"allow_insecure,omitempty\"`\n\t// Whether or not to allow insecure cipher suites.\n\tAllowInsecureCiphers bool `protobuf:\"varint,5,opt,name=allow_insecure_ciphers,json=allowInsecureCiphers,proto3\" json:\"allow_insecure_ciphers,omitempty\"`\n\t// List of certificates to be served on server.\n\tCertificate []*Certificate `protobuf:\"bytes,2,rep,name=certificate,proto3\" json:\"certificate,omitempty\"`\n\t// Override server name.\n\tServerName string `protobuf:\"bytes,3,opt,name=server_name,json=serverName,proto3\" json:\"server_name,omitempty\"`\n\t// Lists of string as ALPN values.\n\tNextProtocol []string `protobuf:\"bytes,4,rep,name=next_protocol,json=nextProtocol,proto3\" json:\"next_protocol,omitempty\"`\n\t// Whether or not to disable session (ticket) resumption.\n\tDisableSessionResumption bool `protobuf:\"varint,6,opt,name=disable_session_resumption,json=disableSessionResumption,proto3\" json:\"disable_session_resumption,omitempty\"`\n\t// If true, root certificates on the system will not be loaded for\n\t// verification.\n\tDisableSystemRoot bool `protobuf:\"varint,7,opt,name=disable_system_root,json=disableSystemRoot,proto3\" json:\"disable_system_root,omitempty\"`\n}\n\nfunc (x *Config) Reset() {\n\t*x = Config{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_transport_internet_tls_config_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Config) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Config) ProtoMessage() {}\n\nfunc (x *Config) ProtoReflect() protoreflect.Message {\n\tmi := &file_transport_internet_tls_config_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Config.ProtoReflect.Descriptor instead.\nfunc (*Config) Descriptor() ([]byte, []int) {\n\treturn file_transport_internet_tls_config_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *Config) GetAllowInsecure() bool {\n\tif x != nil {\n\t\treturn x.AllowInsecure\n\t}\n\treturn false\n}\n\nfunc (x *Config) GetAllowInsecureCiphers() bool {\n\tif x != nil {\n\t\treturn x.AllowInsecureCiphers\n\t}\n\treturn false\n}\n\nfunc (x *Config) GetCertificate() []*Certificate {\n\tif x != nil {\n\t\treturn x.Certificate\n\t}\n\treturn nil\n}\n\nfunc (x *Config) GetServerName() string {\n\tif x != nil {\n\t\treturn x.ServerName\n\t}\n\treturn \"\"\n}\n\nfunc (x *Config) GetNextProtocol() []string {\n\tif x != nil {\n\t\treturn x.NextProtocol\n\t}\n\treturn nil\n}\n\nfunc (x *Config) GetDisableSessionResumption() bool {\n\tif x != nil {\n\t\treturn x.DisableSessionResumption\n\t}\n\treturn false\n}\n\nfunc (x *Config) GetDisableSystemRoot() bool {\n\tif x != nil {\n\t\treturn x.DisableSystemRoot\n\t}\n\treturn false\n}\n\nvar File_transport_internet_tls_config_proto protoreflect.FileDescriptor\n\nvar file_transport_internet_tls_config_proto_rawDesc = []byte{\n\t0x0a, 0x23, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65,\n\t0x72, 0x6e, 0x65, 0x74, 0x2f, 0x74, 0x6c, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e,\n\t0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x21, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72,\n\t0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65,\n\t0x72, 0x6e, 0x65, 0x74, 0x2e, 0x74, 0x6c, 0x73, 0x22, 0xd3, 0x01, 0x0a, 0x0b, 0x43, 0x65, 0x72,\n\t0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x43, 0x65, 0x72, 0x74,\n\t0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x43,\n\t0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x4b, 0x65,\n\t0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x4b, 0x65, 0x79, 0x12, 0x4a, 0x0a, 0x05,\n\t0x75, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x34, 0x2e, 0x76, 0x32,\n\t0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f,\n\t0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x74, 0x6c, 0x73, 0x2e,\n\t0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x2e, 0x55, 0x73, 0x61, 0x67,\n\t0x65, 0x52, 0x05, 0x75, 0x73, 0x61, 0x67, 0x65, 0x22, 0x44, 0x0a, 0x05, 0x55, 0x73, 0x61, 0x67,\n\t0x65, 0x12, 0x10, 0x0a, 0x0c, 0x45, 0x4e, 0x43, 0x49, 0x50, 0x48, 0x45, 0x52, 0x4d, 0x45, 0x4e,\n\t0x54, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x41, 0x55, 0x54, 0x48, 0x4f, 0x52, 0x49, 0x54, 0x59,\n\t0x5f, 0x56, 0x45, 0x52, 0x49, 0x46, 0x59, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x41, 0x55, 0x54,\n\t0x48, 0x4f, 0x52, 0x49, 0x54, 0x59, 0x5f, 0x49, 0x53, 0x53, 0x55, 0x45, 0x10, 0x02, 0x22, 0xeb,\n\t0x02, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x6c, 0x6c,\n\t0x6f, 0x77, 0x5f, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,\n\t0x08, 0x52, 0x0d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x49, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65,\n\t0x12, 0x34, 0x0a, 0x16, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75,\n\t0x72, 0x65, 0x5f, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08,\n\t0x52, 0x14, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x49, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x43,\n\t0x69, 0x70, 0x68, 0x65, 0x72, 0x73, 0x12, 0x50, 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66,\n\t0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x76, 0x32,\n\t0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f,\n\t0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x74, 0x6c, 0x73, 0x2e,\n\t0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x0b, 0x63, 0x65, 0x72,\n\t0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x76,\n\t0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73,\n\t0x65, 0x72, 0x76, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x6e, 0x65, 0x78,\n\t0x74, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09,\n\t0x52, 0x0c, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x3c,\n\t0x0a, 0x1a, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f,\n\t0x6e, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6d, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01,\n\t0x28, 0x08, 0x52, 0x18, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69,\n\t0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2e, 0x0a, 0x13,\n\t0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x72,\n\t0x6f, 0x6f, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x64, 0x69, 0x73, 0x61, 0x62,\n\t0x6c, 0x65, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x52, 0x6f, 0x6f, 0x74, 0x42, 0x74, 0x0a, 0x25,\n\t0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74,\n\t0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,\n\t0x74, 0x2e, 0x74, 0x6c, 0x73, 0x50, 0x01, 0x5a, 0x25, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,\n\t0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72,\n\t0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x74, 0x6c, 0x73, 0xaa, 0x02,\n\t0x21, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e,\n\t0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x54,\n\t0x6c, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_transport_internet_tls_config_proto_rawDescOnce sync.Once\n\tfile_transport_internet_tls_config_proto_rawDescData = file_transport_internet_tls_config_proto_rawDesc\n)\n\nfunc file_transport_internet_tls_config_proto_rawDescGZIP() []byte {\n\tfile_transport_internet_tls_config_proto_rawDescOnce.Do(func() {\n\t\tfile_transport_internet_tls_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_transport_internet_tls_config_proto_rawDescData)\n\t})\n\treturn file_transport_internet_tls_config_proto_rawDescData\n}\n\nvar file_transport_internet_tls_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1)\nvar file_transport_internet_tls_config_proto_msgTypes = make([]protoimpl.MessageInfo, 2)\nvar file_transport_internet_tls_config_proto_goTypes = []interface{}{\n\t(Certificate_Usage)(0), // 0: v2ray.core.transport.internet.tls.Certificate.Usage\n\t(*Certificate)(nil),    // 1: v2ray.core.transport.internet.tls.Certificate\n\t(*Config)(nil),         // 2: v2ray.core.transport.internet.tls.Config\n}\nvar file_transport_internet_tls_config_proto_depIdxs = []int32{\n\t0, // 0: v2ray.core.transport.internet.tls.Certificate.usage:type_name -> v2ray.core.transport.internet.tls.Certificate.Usage\n\t1, // 1: v2ray.core.transport.internet.tls.Config.certificate:type_name -> v2ray.core.transport.internet.tls.Certificate\n\t2, // [2:2] is the sub-list for method output_type\n\t2, // [2:2] is the sub-list for method input_type\n\t2, // [2:2] is the sub-list for extension type_name\n\t2, // [2:2] is the sub-list for extension extendee\n\t0, // [0:2] is the sub-list for field type_name\n}\n\nfunc init() { file_transport_internet_tls_config_proto_init() }\nfunc file_transport_internet_tls_config_proto_init() {\n\tif File_transport_internet_tls_config_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_transport_internet_tls_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Certificate); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_transport_internet_tls_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Config); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_transport_internet_tls_config_proto_rawDesc,\n\t\t\tNumEnums:      1,\n\t\t\tNumMessages:   2,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_transport_internet_tls_config_proto_goTypes,\n\t\tDependencyIndexes: file_transport_internet_tls_config_proto_depIdxs,\n\t\tEnumInfos:         file_transport_internet_tls_config_proto_enumTypes,\n\t\tMessageInfos:      file_transport_internet_tls_config_proto_msgTypes,\n\t}.Build()\n\tFile_transport_internet_tls_config_proto = out.File\n\tfile_transport_internet_tls_config_proto_rawDesc = nil\n\tfile_transport_internet_tls_config_proto_goTypes = nil\n\tfile_transport_internet_tls_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "transport/internet/tls/config.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.transport.internet.tls;\noption csharp_namespace = \"V2Ray.Core.Transport.Internet.Tls\";\noption go_package = \"v2ray.com/core/transport/internet/tls\";\noption java_package = \"com.v2ray.core.transport.internet.tls\";\noption java_multiple_files = true;\n\nmessage Certificate {\n  // TLS certificate in x509 format.\n  bytes Certificate = 1;\n\n  // TLS key in x509 format.\n  bytes Key = 2;\n\n  enum Usage {\n    ENCIPHERMENT = 0;\n    AUTHORITY_VERIFY = 1;\n    AUTHORITY_ISSUE = 2;\n  }\n\n  Usage usage = 3;\n}\n\nmessage Config {\n  // Whether or not to allow self-signed certificates.\n  bool allow_insecure = 1;\n\n  // Whether or not to allow insecure cipher suites.\n  bool allow_insecure_ciphers = 5;\n\n  // List of certificates to be served on server.\n  repeated Certificate certificate = 2;\n\n  // Override server name.\n  string server_name = 3;\n\n  // Lists of string as ALPN values.\n  repeated string next_protocol = 4;\n\n  // Whether or not to disable session (ticket) resumption.\n  bool disable_session_resumption = 6;\n\n  // If true, root certificates on the system will not be loaded for\n  // verification.\n  bool disable_system_root = 7;\n}\n"
  },
  {
    "path": "transport/internet/tls/config_other.go",
    "content": "// +build !windows\n// +build !confonly\n\npackage tls\n\nimport (\n\t\"crypto/x509\"\n\t\"sync\"\n)\n\ntype rootCertsCache struct {\n\tsync.Mutex\n\tpool *x509.CertPool\n}\n\nfunc (c *rootCertsCache) load() (*x509.CertPool, error) {\n\tc.Lock()\n\tdefer c.Unlock()\n\n\tif c.pool != nil {\n\t\treturn c.pool, nil\n\t}\n\n\tpool, err := x509.SystemCertPool()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tc.pool = pool\n\treturn pool, nil\n}\n\nvar rootCerts rootCertsCache\n\nfunc (c *Config) getCertPool() (*x509.CertPool, error) {\n\tif c.DisableSystemRoot {\n\t\treturn c.loadSelfCertPool()\n\t}\n\n\tif len(c.Certificate) == 0 {\n\t\treturn rootCerts.load()\n\t}\n\n\tpool, err := x509.SystemCertPool()\n\tif err != nil {\n\t\treturn nil, newError(\"system root\").AtWarning().Base(err)\n\t}\n\tfor _, cert := range c.Certificate {\n\t\tif !pool.AppendCertsFromPEM(cert.Certificate) {\n\t\t\treturn nil, newError(\"append cert to root\").AtWarning().Base(err)\n\t\t}\n\t}\n\treturn pool, err\n}\n"
  },
  {
    "path": "transport/internet/tls/config_test.go",
    "content": "package tls_test\n\nimport (\n\tgotls \"crypto/tls\"\n\t\"crypto/x509\"\n\t\"testing\"\n\t\"time\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/protocol/tls/cert\"\n\t. \"v2ray.com/core/transport/internet/tls\"\n)\n\nfunc TestCertificateIssuing(t *testing.T) {\n\tcertificate := ParseCertificate(cert.MustGenerate(nil, cert.Authority(true), cert.KeyUsage(x509.KeyUsageCertSign)))\n\tcertificate.Usage = Certificate_AUTHORITY_ISSUE\n\n\tc := &Config{\n\t\tCertificate: []*Certificate{\n\t\t\tcertificate,\n\t\t},\n\t}\n\n\ttlsConfig := c.GetTLSConfig()\n\tv2rayCert, err := tlsConfig.GetCertificate(&gotls.ClientHelloInfo{\n\t\tServerName: \"www.v2ray.com\",\n\t})\n\tcommon.Must(err)\n\n\tx509Cert, err := x509.ParseCertificate(v2rayCert.Certificate[0])\n\tcommon.Must(err)\n\tif !x509Cert.NotAfter.After(time.Now()) {\n\t\tt.Error(\"NotAfter: \", x509Cert.NotAfter)\n\t}\n}\n\nfunc TestExpiredCertificate(t *testing.T) {\n\tcaCert := cert.MustGenerate(nil, cert.Authority(true), cert.KeyUsage(x509.KeyUsageCertSign))\n\texpiredCert := cert.MustGenerate(caCert, cert.NotAfter(time.Now().Add(time.Minute*-2)), cert.CommonName(\"www.v2ray.com\"), cert.DNSNames(\"www.v2ray.com\"))\n\n\tcertificate := ParseCertificate(caCert)\n\tcertificate.Usage = Certificate_AUTHORITY_ISSUE\n\n\tcertificate2 := ParseCertificate(expiredCert)\n\n\tc := &Config{\n\t\tCertificate: []*Certificate{\n\t\t\tcertificate,\n\t\t\tcertificate2,\n\t\t},\n\t}\n\n\ttlsConfig := c.GetTLSConfig()\n\tv2rayCert, err := tlsConfig.GetCertificate(&gotls.ClientHelloInfo{\n\t\tServerName: \"www.v2ray.com\",\n\t})\n\tcommon.Must(err)\n\n\tx509Cert, err := x509.ParseCertificate(v2rayCert.Certificate[0])\n\tcommon.Must(err)\n\tif !x509Cert.NotAfter.After(time.Now()) {\n\t\tt.Error(\"NotAfter: \", x509Cert.NotAfter)\n\t}\n}\n\nfunc TestInsecureCertificates(t *testing.T) {\n\tc := &Config{\n\t\tAllowInsecureCiphers: true,\n\t}\n\n\ttlsConfig := c.GetTLSConfig()\n\tif len(tlsConfig.CipherSuites) > 0 {\n\t\tt.Fatal(\"Unexpected tls cipher suites list: \", tlsConfig.CipherSuites)\n\t}\n}\n\nfunc BenchmarkCertificateIssuing(b *testing.B) {\n\tcertificate := ParseCertificate(cert.MustGenerate(nil, cert.Authority(true), cert.KeyUsage(x509.KeyUsageCertSign)))\n\tcertificate.Usage = Certificate_AUTHORITY_ISSUE\n\n\tc := &Config{\n\t\tCertificate: []*Certificate{\n\t\t\tcertificate,\n\t\t},\n\t}\n\n\ttlsConfig := c.GetTLSConfig()\n\tlenCerts := len(tlsConfig.Certificates)\n\n\tb.ResetTimer()\n\n\tfor i := 0; i < b.N; i++ {\n\t\t_, _ = tlsConfig.GetCertificate(&gotls.ClientHelloInfo{\n\t\t\tServerName: \"www.v2ray.com\",\n\t\t})\n\t\tdelete(tlsConfig.NameToCertificate, \"www.v2ray.com\")\n\t\ttlsConfig.Certificates = tlsConfig.Certificates[:lenCerts]\n\t}\n}\n"
  },
  {
    "path": "transport/internet/tls/config_windows.go",
    "content": "// +build windows\n// +build !confonly\n\npackage tls\n\nimport \"crypto/x509\"\n\nfunc (c *Config) getCertPool() (*x509.CertPool, error) {\n\tif c.DisableSystemRoot {\n\t\treturn c.loadSelfCertPool()\n\t}\n\n\treturn nil, nil\n}\n"
  },
  {
    "path": "transport/internet/tls/errors.generated.go",
    "content": "package tls\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "transport/internet/tls/tls.go",
    "content": "// +build !confonly\n\npackage tls\n\nimport (\n\t\"crypto/tls\"\n\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/net\"\n)\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n\nvar (\n\t_ buf.Writer = (*Conn)(nil)\n)\n\ntype Conn struct {\n\t*tls.Conn\n}\n\nfunc (c *Conn) WriteMultiBuffer(mb buf.MultiBuffer) error {\n\tmb = buf.Compact(mb)\n\tmb, err := buf.WriteMultiBuffer(c, mb)\n\tbuf.ReleaseMulti(mb)\n\treturn err\n}\n\nfunc (c *Conn) HandshakeAddress() net.Address {\n\tif err := c.Handshake(); err != nil {\n\t\treturn nil\n\t}\n\tstate := c.ConnectionState()\n\tif state.ServerName == \"\" {\n\t\treturn nil\n\t}\n\treturn net.ParseAddress(state.ServerName)\n}\n\n// Client initiates a TLS client handshake on the given connection.\nfunc Client(c net.Conn, config *tls.Config) net.Conn {\n\ttlsConn := tls.Client(c, config)\n\treturn &Conn{Conn: tlsConn}\n}\n\n/*\nfunc copyConfig(c *tls.Config) *utls.Config {\n\treturn &utls.Config{\n\t\tNextProtos:         c.NextProtos,\n\t\tServerName:         c.ServerName,\n\t\tInsecureSkipVerify: c.InsecureSkipVerify,\n\t\tMinVersion:         utls.VersionTLS12,\n\t\tMaxVersion:         utls.VersionTLS12,\n\t}\n}\n\nfunc UClient(c net.Conn, config *tls.Config) net.Conn {\n\tuConfig := copyConfig(config)\n\treturn utls.Client(c, uConfig)\n}\n*/\n\n// Server initiates a TLS server handshake on the given connection.\nfunc Server(c net.Conn, config *tls.Config) net.Conn {\n\ttlsConn := tls.Server(c, config)\n\treturn &Conn{Conn: tlsConn}\n}\n"
  },
  {
    "path": "transport/internet/udp/config.go",
    "content": "package udp\n\nimport (\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/transport/internet\"\n)\n\nfunc init() {\n\tcommon.Must(internet.RegisterProtocolConfigCreator(protocolName, func() interface{} {\n\t\treturn new(Config)\n\t}))\n}\n"
  },
  {
    "path": "transport/internet/udp/config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: transport/internet/udp/config.proto\n\npackage udp\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype Config struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *Config) Reset() {\n\t*x = Config{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_transport_internet_udp_config_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Config) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Config) ProtoMessage() {}\n\nfunc (x *Config) ProtoReflect() protoreflect.Message {\n\tmi := &file_transport_internet_udp_config_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Config.ProtoReflect.Descriptor instead.\nfunc (*Config) Descriptor() ([]byte, []int) {\n\treturn file_transport_internet_udp_config_proto_rawDescGZIP(), []int{0}\n}\n\nvar File_transport_internet_udp_config_proto protoreflect.FileDescriptor\n\nvar file_transport_internet_udp_config_proto_rawDesc = []byte{\n\t0x0a, 0x23, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65,\n\t0x72, 0x6e, 0x65, 0x74, 0x2f, 0x75, 0x64, 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e,\n\t0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x21, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72,\n\t0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65,\n\t0x72, 0x6e, 0x65, 0x74, 0x2e, 0x75, 0x64, 0x70, 0x22, 0x08, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66,\n\t0x69, 0x67, 0x42, 0x74, 0x0a, 0x25, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,\n\t0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69,\n\t0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x75, 0x64, 0x70, 0x50, 0x01, 0x5a, 0x25, 0x76,\n\t0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72,\n\t0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74,\n\t0x2f, 0x75, 0x64, 0x70, 0xaa, 0x02, 0x21, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72,\n\t0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65,\n\t0x72, 0x6e, 0x65, 0x74, 0x2e, 0x55, 0x64, 0x70, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_transport_internet_udp_config_proto_rawDescOnce sync.Once\n\tfile_transport_internet_udp_config_proto_rawDescData = file_transport_internet_udp_config_proto_rawDesc\n)\n\nfunc file_transport_internet_udp_config_proto_rawDescGZIP() []byte {\n\tfile_transport_internet_udp_config_proto_rawDescOnce.Do(func() {\n\t\tfile_transport_internet_udp_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_transport_internet_udp_config_proto_rawDescData)\n\t})\n\treturn file_transport_internet_udp_config_proto_rawDescData\n}\n\nvar file_transport_internet_udp_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)\nvar file_transport_internet_udp_config_proto_goTypes = []interface{}{\n\t(*Config)(nil), // 0: v2ray.core.transport.internet.udp.Config\n}\nvar file_transport_internet_udp_config_proto_depIdxs = []int32{\n\t0, // [0:0] is the sub-list for method output_type\n\t0, // [0:0] is the sub-list for method input_type\n\t0, // [0:0] is the sub-list for extension type_name\n\t0, // [0:0] is the sub-list for extension extendee\n\t0, // [0:0] is the sub-list for field type_name\n}\n\nfunc init() { file_transport_internet_udp_config_proto_init() }\nfunc file_transport_internet_udp_config_proto_init() {\n\tif File_transport_internet_udp_config_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_transport_internet_udp_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Config); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_transport_internet_udp_config_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   1,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_transport_internet_udp_config_proto_goTypes,\n\t\tDependencyIndexes: file_transport_internet_udp_config_proto_depIdxs,\n\t\tMessageInfos:      file_transport_internet_udp_config_proto_msgTypes,\n\t}.Build()\n\tFile_transport_internet_udp_config_proto = out.File\n\tfile_transport_internet_udp_config_proto_rawDesc = nil\n\tfile_transport_internet_udp_config_proto_goTypes = nil\n\tfile_transport_internet_udp_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "transport/internet/udp/config.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.transport.internet.udp;\noption csharp_namespace = \"V2Ray.Core.Transport.Internet.Udp\";\noption go_package = \"v2ray.com/core/transport/internet/udp\";\noption java_package = \"com.v2ray.core.transport.internet.udp\";\noption java_multiple_files = true;\n\nmessage Config {}\n"
  },
  {
    "path": "transport/internet/udp/dialer.go",
    "content": "package udp\n\nimport (\n\t\"context\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/transport/internet\"\n)\n\nfunc init() {\n\tcommon.Must(internet.RegisterTransportDialer(protocolName,\n\t\tfunc(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (internet.Connection, error) {\n\t\t\tvar sockopt *internet.SocketConfig\n\t\t\tif streamSettings != nil {\n\t\t\t\tsockopt = streamSettings.SocketSettings\n\t\t\t}\n\t\t\tconn, err := internet.DialSystem(ctx, dest, sockopt)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\t// TODO: handle dialer options\n\t\t\treturn internet.Connection(conn), nil\n\t\t}))\n}\n"
  },
  {
    "path": "transport/internet/udp/dispatcher.go",
    "content": "package udp\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"sync\"\n\t\"time\"\n\n\t\"v2ray.com/core/common/signal/done\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol/udp\"\n\t\"v2ray.com/core/common/session\"\n\t\"v2ray.com/core/common/signal\"\n\t\"v2ray.com/core/features/routing\"\n\t\"v2ray.com/core/transport\"\n)\n\ntype ResponseCallback func(ctx context.Context, packet *udp.Packet)\n\ntype connEntry struct {\n\tlink   *transport.Link\n\ttimer  signal.ActivityUpdater\n\tcancel context.CancelFunc\n}\n\ntype Dispatcher struct {\n\tsync.RWMutex\n\tconns      map[net.Destination]*connEntry\n\tdispatcher routing.Dispatcher\n\tcallback   ResponseCallback\n}\n\nfunc NewDispatcher(dispatcher routing.Dispatcher, callback ResponseCallback) *Dispatcher {\n\treturn &Dispatcher{\n\t\tconns:      make(map[net.Destination]*connEntry),\n\t\tdispatcher: dispatcher,\n\t\tcallback:   callback,\n\t}\n}\n\nfunc (v *Dispatcher) RemoveRay(dest net.Destination) {\n\tv.Lock()\n\tdefer v.Unlock()\n\tif conn, found := v.conns[dest]; found {\n\t\tcommon.Close(conn.link.Reader)\n\t\tcommon.Close(conn.link.Writer)\n\t\tdelete(v.conns, dest)\n\t}\n}\n\nfunc (v *Dispatcher) getInboundRay(ctx context.Context, dest net.Destination) *connEntry {\n\tv.Lock()\n\tdefer v.Unlock()\n\n\tif entry, found := v.conns[dest]; found {\n\t\treturn entry\n\t}\n\n\tnewError(\"establishing new connection for \", dest).WriteToLog()\n\n\tctx, cancel := context.WithCancel(ctx)\n\tremoveRay := func() {\n\t\tcancel()\n\t\tv.RemoveRay(dest)\n\t}\n\ttimer := signal.CancelAfterInactivity(ctx, removeRay, time.Second*4)\n\tlink, _ := v.dispatcher.Dispatch(ctx, dest)\n\tentry := &connEntry{\n\t\tlink:   link,\n\t\ttimer:  timer,\n\t\tcancel: removeRay,\n\t}\n\tv.conns[dest] = entry\n\tgo handleInput(ctx, entry, dest, v.callback)\n\treturn entry\n}\n\nfunc (v *Dispatcher) Dispatch(ctx context.Context, destination net.Destination, payload *buf.Buffer) {\n\t// TODO: Add user to destString\n\tnewError(\"dispatch request to: \", destination).AtDebug().WriteToLog(session.ExportIDToError(ctx))\n\n\tconn := v.getInboundRay(ctx, destination)\n\toutputStream := conn.link.Writer\n\tif outputStream != nil {\n\t\tif err := outputStream.WriteMultiBuffer(buf.MultiBuffer{payload}); err != nil {\n\t\t\tnewError(\"failed to write first UDP payload\").Base(err).WriteToLog(session.ExportIDToError(ctx))\n\t\t\tconn.cancel()\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc handleInput(ctx context.Context, conn *connEntry, dest net.Destination, callback ResponseCallback) {\n\tdefer conn.cancel()\n\n\tinput := conn.link.Reader\n\ttimer := conn.timer\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn\n\t\tdefault:\n\t\t}\n\n\t\tmb, err := input.ReadMultiBuffer()\n\t\tif err != nil {\n\t\t\tnewError(\"failed to handle UDP input\").Base(err).WriteToLog(session.ExportIDToError(ctx))\n\t\t\treturn\n\t\t}\n\t\ttimer.Update()\n\t\tfor _, b := range mb {\n\t\t\tcallback(ctx, &udp.Packet{\n\t\t\t\tPayload: b,\n\t\t\t\tSource:  dest,\n\t\t\t})\n\t\t}\n\t}\n}\n\ntype dispatcherConn struct {\n\tdispatcher *Dispatcher\n\tcache      chan *udp.Packet\n\tdone       *done.Instance\n}\n\nfunc DialDispatcher(ctx context.Context, dispatcher routing.Dispatcher) (net.PacketConn, error) {\n\tc := &dispatcherConn{\n\t\tcache: make(chan *udp.Packet, 16),\n\t\tdone:  done.New(),\n\t}\n\n\td := NewDispatcher(dispatcher, c.callback)\n\tc.dispatcher = d\n\treturn c, nil\n}\n\nfunc (c *dispatcherConn) callback(ctx context.Context, packet *udp.Packet) {\n\tselect {\n\tcase <-c.done.Wait():\n\t\tpacket.Payload.Release()\n\t\treturn\n\tcase c.cache <- packet:\n\tdefault:\n\t\tpacket.Payload.Release()\n\t\treturn\n\t}\n}\n\nfunc (c *dispatcherConn) ReadFrom(p []byte) (int, net.Addr, error) {\n\tselect {\n\tcase <-c.done.Wait():\n\t\treturn 0, nil, io.EOF\n\tcase packet := <-c.cache:\n\t\tn := copy(p, packet.Payload.Bytes())\n\t\treturn n, &net.UDPAddr{\n\t\t\tIP:   packet.Source.Address.IP(),\n\t\t\tPort: int(packet.Source.Port),\n\t\t}, nil\n\t}\n}\n\nfunc (c *dispatcherConn) WriteTo(p []byte, addr net.Addr) (int, error) {\n\tbuffer := buf.New()\n\traw := buffer.Extend(buf.Size)\n\tn := copy(raw, p)\n\tbuffer.Resize(0, int32(n))\n\n\tctx := context.Background()\n\tc.dispatcher.Dispatch(ctx, net.DestinationFromAddr(addr), buffer)\n\treturn n, nil\n}\n\nfunc (c *dispatcherConn) Close() error {\n\treturn c.done.Close()\n}\n\nfunc (c *dispatcherConn) LocalAddr() net.Addr {\n\treturn &net.UDPAddr{\n\t\tIP:   []byte{0, 0, 0, 0},\n\t\tPort: 0,\n\t}\n}\n\nfunc (c *dispatcherConn) SetDeadline(t time.Time) error {\n\treturn nil\n}\n\nfunc (c *dispatcherConn) SetReadDeadline(t time.Time) error {\n\treturn nil\n}\n\nfunc (c *dispatcherConn) SetWriteDeadline(t time.Time) error {\n\treturn nil\n}\n"
  },
  {
    "path": "transport/internet/udp/dispatcher_test.go",
    "content": "package udp_test\n\nimport (\n\t\"context\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol/udp\"\n\t\"v2ray.com/core/features/routing\"\n\t\"v2ray.com/core/transport\"\n\t. \"v2ray.com/core/transport/internet/udp\"\n\t\"v2ray.com/core/transport/pipe\"\n)\n\ntype TestDispatcher struct {\n\tOnDispatch func(ctx context.Context, dest net.Destination) (*transport.Link, error)\n}\n\nfunc (d *TestDispatcher) Dispatch(ctx context.Context, dest net.Destination) (*transport.Link, error) {\n\treturn d.OnDispatch(ctx, dest)\n}\n\nfunc (d *TestDispatcher) Start() error {\n\treturn nil\n}\n\nfunc (d *TestDispatcher) Close() error {\n\treturn nil\n}\n\nfunc (*TestDispatcher) Type() interface{} {\n\treturn routing.DispatcherType()\n}\n\nfunc TestSameDestinationDispatching(t *testing.T) {\n\tctx, cancel := context.WithCancel(context.Background())\n\tuplinkReader, uplinkWriter := pipe.New(pipe.WithSizeLimit(1024))\n\tdownlinkReader, downlinkWriter := pipe.New(pipe.WithSizeLimit(1024))\n\n\tgo func() {\n\t\tfor {\n\t\t\tdata, err := uplinkReader.ReadMultiBuffer()\n\t\t\tif err != nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\terr = downlinkWriter.WriteMultiBuffer(data)\n\t\t\tcommon.Must(err)\n\t\t}\n\t}()\n\n\tvar count uint32\n\ttd := &TestDispatcher{\n\t\tOnDispatch: func(ctx context.Context, dest net.Destination) (*transport.Link, error) {\n\t\t\tatomic.AddUint32(&count, 1)\n\t\t\treturn &transport.Link{Reader: downlinkReader, Writer: uplinkWriter}, nil\n\t\t},\n\t}\n\tdest := net.UDPDestination(net.LocalHostIP, 53)\n\n\tb := buf.New()\n\tb.WriteString(\"abcd\")\n\n\tvar msgCount uint32\n\tdispatcher := NewDispatcher(td, func(ctx context.Context, packet *udp.Packet) {\n\t\tatomic.AddUint32(&msgCount, 1)\n\t})\n\n\tdispatcher.Dispatch(ctx, dest, b)\n\tfor i := 0; i < 5; i++ {\n\t\tdispatcher.Dispatch(ctx, dest, b)\n\t}\n\n\ttime.Sleep(time.Second)\n\tcancel()\n\n\tif count != 1 {\n\t\tt.Error(\"count: \", count)\n\t}\n\tif v := atomic.LoadUint32(&msgCount); v != 6 {\n\t\tt.Error(\"msgCount: \", v)\n\t}\n}\n"
  },
  {
    "path": "transport/internet/udp/errors.generated.go",
    "content": "package udp\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "transport/internet/udp/hub.go",
    "content": "package udp\n\nimport (\n\t\"context\"\n\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol/udp\"\n\t\"v2ray.com/core/transport/internet\"\n)\n\ntype HubOption func(h *Hub)\n\nfunc HubCapacity(capacity int) HubOption {\n\treturn func(h *Hub) {\n\t\th.capacity = capacity\n\t}\n}\n\nfunc HubReceiveOriginalDestination(r bool) HubOption {\n\treturn func(h *Hub) {\n\t\th.recvOrigDest = r\n\t}\n}\n\ntype Hub struct {\n\tconn         *net.UDPConn\n\tcache        chan *udp.Packet\n\tcapacity     int\n\trecvOrigDest bool\n}\n\nfunc ListenUDP(ctx context.Context, address net.Address, port net.Port, streamSettings *internet.MemoryStreamConfig, options ...HubOption) (*Hub, error) {\n\thub := &Hub{\n\t\tcapacity:     256,\n\t\trecvOrigDest: false,\n\t}\n\tfor _, opt := range options {\n\t\topt(hub)\n\t}\n\n\tvar sockopt *internet.SocketConfig\n\tif streamSettings != nil {\n\t\tsockopt = streamSettings.SocketSettings\n\t}\n\tif sockopt != nil && sockopt.ReceiveOriginalDestAddress {\n\t\thub.recvOrigDest = true\n\t}\n\n\tudpConn, err := internet.ListenSystemPacket(ctx, &net.UDPAddr{\n\t\tIP:   address.IP(),\n\t\tPort: int(port),\n\t}, sockopt)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tnewError(\"listening UDP on \", address, \":\", port).WriteToLog()\n\thub.conn = udpConn.(*net.UDPConn)\n\thub.cache = make(chan *udp.Packet, hub.capacity)\n\n\tgo hub.start()\n\treturn hub, nil\n}\n\n// Close implements net.Listener.\nfunc (h *Hub) Close() error {\n\th.conn.Close()\n\treturn nil\n}\n\nfunc (h *Hub) WriteTo(payload []byte, dest net.Destination) (int, error) {\n\treturn h.conn.WriteToUDP(payload, &net.UDPAddr{\n\t\tIP:   dest.Address.IP(),\n\t\tPort: int(dest.Port),\n\t})\n}\n\nfunc (h *Hub) start() {\n\tc := h.cache\n\tdefer close(c)\n\n\toobBytes := make([]byte, 256)\n\n\tfor {\n\t\tbuffer := buf.New()\n\t\tvar noob int\n\t\tvar addr *net.UDPAddr\n\t\trawBytes := buffer.Extend(buf.Size)\n\n\t\tn, noob, _, addr, err := ReadUDPMsg(h.conn, rawBytes, oobBytes)\n\t\tif err != nil {\n\t\t\tnewError(\"failed to read UDP msg\").Base(err).WriteToLog()\n\t\t\tbuffer.Release()\n\t\t\tbreak\n\t\t}\n\t\tbuffer.Resize(0, int32(n))\n\n\t\tif buffer.IsEmpty() {\n\t\t\tbuffer.Release()\n\t\t\tcontinue\n\t\t}\n\n\t\tpayload := &udp.Packet{\n\t\t\tPayload: buffer,\n\t\t\tSource:  net.UDPDestination(net.IPAddress(addr.IP), net.Port(addr.Port)),\n\t\t}\n\t\tif h.recvOrigDest && noob > 0 {\n\t\t\tpayload.Target = RetrieveOriginalDest(oobBytes[:noob])\n\t\t\tif payload.Target.IsValid() {\n\t\t\t\tnewError(\"UDP original destination: \", payload.Target).AtDebug().WriteToLog()\n\t\t\t} else {\n\t\t\t\tnewError(\"failed to read UDP original destination\").WriteToLog()\n\t\t\t}\n\t\t}\n\n\t\tselect {\n\t\tcase c <- payload:\n\t\tdefault:\n\t\t\tbuffer.Release()\n\t\t\tpayload.Payload = nil\n\t\t}\n\n\t}\n}\n\n// Addr implements net.Listener.\nfunc (h *Hub) Addr() net.Addr {\n\treturn h.conn.LocalAddr()\n}\n\nfunc (h *Hub) Receive() <-chan *udp.Packet {\n\treturn h.cache\n}\n"
  },
  {
    "path": "transport/internet/udp/hub_freebsd.go",
    "content": "// +build freebsd\n\npackage udp\n\nimport (\n\t\"bytes\"\n\t\"encoding/gob\"\n\t\"io\"\n\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/transport/internet\"\n)\n\n// RetrieveOriginalDest from stored laddr, caddr\nfunc RetrieveOriginalDest(oob []byte) net.Destination {\n\tdec := gob.NewDecoder(bytes.NewBuffer(oob))\n\tvar la, ra net.UDPAddr\n\tdec.Decode(&la)\n\tdec.Decode(&ra)\n\tip, port, err := internet.OriginalDst(&la, &ra)\n\tif err != nil {\n\t\treturn net.Destination{}\n\t}\n\treturn net.UDPDestination(net.IPAddress(ip), net.Port(port))\n}\n\n// ReadUDPMsg stores laddr, caddr for later use\nfunc ReadUDPMsg(conn *net.UDPConn, payload []byte, oob []byte) (int, int, int, *net.UDPAddr, error) {\n\tnBytes, addr, err := conn.ReadFromUDP(payload)\n\tvar buf bytes.Buffer\n\tenc := gob.NewEncoder(&buf)\n\tenc.Encode(conn.LocalAddr().(*net.UDPAddr))\n\tenc.Encode(addr)\n\tvar reader io.Reader = &buf\n\tnoob, _ := reader.Read(oob)\n\treturn nBytes, noob, 0, addr, err\n}\n"
  },
  {
    "path": "transport/internet/udp/hub_linux.go",
    "content": "// +build linux\n\npackage udp\n\nimport (\n\t\"syscall\"\n\n\t\"golang.org/x/sys/unix\"\n\t\"v2ray.com/core/common/net\"\n)\n\nfunc RetrieveOriginalDest(oob []byte) net.Destination {\n\tmsgs, err := syscall.ParseSocketControlMessage(oob)\n\tif err != nil {\n\t\treturn net.Destination{}\n\t}\n\tfor _, msg := range msgs {\n\t\tif msg.Header.Level == syscall.SOL_IP && msg.Header.Type == syscall.IP_RECVORIGDSTADDR {\n\t\t\tip := net.IPAddress(msg.Data[4:8])\n\t\t\tport := net.PortFromBytes(msg.Data[2:4])\n\t\t\treturn net.UDPDestination(ip, port)\n\t\t} else if msg.Header.Level == syscall.SOL_IPV6 && msg.Header.Type == unix.IPV6_RECVORIGDSTADDR {\n\t\t\tip := net.IPAddress(msg.Data[8:24])\n\t\t\tport := net.PortFromBytes(msg.Data[2:4])\n\t\t\treturn net.UDPDestination(ip, port)\n\t\t}\n\t}\n\treturn net.Destination{}\n}\n\nfunc ReadUDPMsg(conn *net.UDPConn, payload []byte, oob []byte) (int, int, int, *net.UDPAddr, error) {\n\treturn conn.ReadMsgUDP(payload, oob)\n}\n"
  },
  {
    "path": "transport/internet/udp/hub_other.go",
    "content": "// +build !linux,!freebsd\n\npackage udp\n\nimport (\n\t\"v2ray.com/core/common/net\"\n)\n\nfunc RetrieveOriginalDest(oob []byte) net.Destination {\n\treturn net.Destination{}\n}\n\nfunc ReadUDPMsg(conn *net.UDPConn, payload []byte, oob []byte) (int, int, int, *net.UDPAddr, error) {\n\tnBytes, addr, err := conn.ReadFromUDP(payload)\n\treturn nBytes, 0, 0, addr, err\n}\n"
  },
  {
    "path": "transport/internet/udp/udp.go",
    "content": "package udp\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n\nconst protocolName = \"udp\"\n"
  },
  {
    "path": "transport/internet/websocket/config.go",
    "content": "// +build !confonly\n\npackage websocket\n\nimport (\n\t\"net/http\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/transport/internet\"\n)\n\nconst protocolName = \"websocket\"\n\nfunc (c *Config) GetNormalizedPath() string {\n\tpath := c.Path\n\tif path == \"\" {\n\t\treturn \"/\"\n\t}\n\tif path[0] != '/' {\n\t\treturn \"/\" + path\n\t}\n\treturn path\n}\n\nfunc (c *Config) GetRequestHeader() http.Header {\n\theader := http.Header{}\n\tfor _, h := range c.Header {\n\t\theader.Add(h.Key, h.Value)\n\t}\n\treturn header\n}\n\nfunc init() {\n\tcommon.Must(internet.RegisterProtocolConfigCreator(protocolName, func() interface{} {\n\t\treturn new(Config)\n\t}))\n}\n"
  },
  {
    "path": "transport/internet/websocket/config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: transport/internet/websocket/config.proto\n\npackage websocket\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype Header struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tKey   string `protobuf:\"bytes,1,opt,name=key,proto3\" json:\"key,omitempty\"`\n\tValue string `protobuf:\"bytes,2,opt,name=value,proto3\" json:\"value,omitempty\"`\n}\n\nfunc (x *Header) Reset() {\n\t*x = Header{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_transport_internet_websocket_config_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Header) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Header) ProtoMessage() {}\n\nfunc (x *Header) ProtoReflect() protoreflect.Message {\n\tmi := &file_transport_internet_websocket_config_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Header.ProtoReflect.Descriptor instead.\nfunc (*Header) Descriptor() ([]byte, []int) {\n\treturn file_transport_internet_websocket_config_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *Header) GetKey() string {\n\tif x != nil {\n\t\treturn x.Key\n\t}\n\treturn \"\"\n}\n\nfunc (x *Header) GetValue() string {\n\tif x != nil {\n\t\treturn x.Value\n\t}\n\treturn \"\"\n}\n\ntype Config struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// URL path to the WebSocket service. Empty value means root(/).\n\tPath                string    `protobuf:\"bytes,2,opt,name=path,proto3\" json:\"path,omitempty\"`\n\tHeader              []*Header `protobuf:\"bytes,3,rep,name=header,proto3\" json:\"header,omitempty\"`\n\tAcceptProxyProtocol bool      `protobuf:\"varint,4,opt,name=accept_proxy_protocol,json=acceptProxyProtocol,proto3\" json:\"accept_proxy_protocol,omitempty\"`\n}\n\nfunc (x *Config) Reset() {\n\t*x = Config{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_transport_internet_websocket_config_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Config) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Config) ProtoMessage() {}\n\nfunc (x *Config) ProtoReflect() protoreflect.Message {\n\tmi := &file_transport_internet_websocket_config_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Config.ProtoReflect.Descriptor instead.\nfunc (*Config) Descriptor() ([]byte, []int) {\n\treturn file_transport_internet_websocket_config_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *Config) GetPath() string {\n\tif x != nil {\n\t\treturn x.Path\n\t}\n\treturn \"\"\n}\n\nfunc (x *Config) GetHeader() []*Header {\n\tif x != nil {\n\t\treturn x.Header\n\t}\n\treturn nil\n}\n\nfunc (x *Config) GetAcceptProxyProtocol() bool {\n\tif x != nil {\n\t\treturn x.AcceptProxyProtocol\n\t}\n\treturn false\n}\n\nvar File_transport_internet_websocket_config_proto protoreflect.FileDescriptor\n\nvar file_transport_internet_websocket_config_proto_rawDesc = []byte{\n\t0x0a, 0x29, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65,\n\t0x72, 0x6e, 0x65, 0x74, 0x2f, 0x77, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2f, 0x63,\n\t0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x27, 0x76, 0x32, 0x72,\n\t0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72,\n\t0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x77, 0x65, 0x62, 0x73, 0x6f,\n\t0x63, 0x6b, 0x65, 0x74, 0x22, 0x30, 0x0a, 0x06, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x10,\n\t0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79,\n\t0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,\n\t0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x9f, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69,\n\t0x67, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,\n\t0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x47, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18,\n\t0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,\n\t0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74,\n\t0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x77, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e,\n\t0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x32,\n\t0x0a, 0x15, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x70,\n\t0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x61,\n\t0x63, 0x63, 0x65, 0x70, 0x74, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63,\n\t0x6f, 0x6c, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x42, 0x86, 0x01, 0x0a, 0x2b, 0x63, 0x6f, 0x6d,\n\t0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e,\n\t0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x77,\n\t0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x50, 0x01, 0x5a, 0x2b, 0x76, 0x32, 0x72, 0x61,\n\t0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73,\n\t0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x77, 0x65,\n\t0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0xaa, 0x02, 0x27, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e,\n\t0x43, 0x6f, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49,\n\t0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x57, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65,\n\t0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_transport_internet_websocket_config_proto_rawDescOnce sync.Once\n\tfile_transport_internet_websocket_config_proto_rawDescData = file_transport_internet_websocket_config_proto_rawDesc\n)\n\nfunc file_transport_internet_websocket_config_proto_rawDescGZIP() []byte {\n\tfile_transport_internet_websocket_config_proto_rawDescOnce.Do(func() {\n\t\tfile_transport_internet_websocket_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_transport_internet_websocket_config_proto_rawDescData)\n\t})\n\treturn file_transport_internet_websocket_config_proto_rawDescData\n}\n\nvar file_transport_internet_websocket_config_proto_msgTypes = make([]protoimpl.MessageInfo, 2)\nvar file_transport_internet_websocket_config_proto_goTypes = []interface{}{\n\t(*Header)(nil), // 0: v2ray.core.transport.internet.websocket.Header\n\t(*Config)(nil), // 1: v2ray.core.transport.internet.websocket.Config\n}\nvar file_transport_internet_websocket_config_proto_depIdxs = []int32{\n\t0, // 0: v2ray.core.transport.internet.websocket.Config.header:type_name -> v2ray.core.transport.internet.websocket.Header\n\t1, // [1:1] is the sub-list for method output_type\n\t1, // [1:1] is the sub-list for method input_type\n\t1, // [1:1] is the sub-list for extension type_name\n\t1, // [1:1] is the sub-list for extension extendee\n\t0, // [0:1] is the sub-list for field type_name\n}\n\nfunc init() { file_transport_internet_websocket_config_proto_init() }\nfunc file_transport_internet_websocket_config_proto_init() {\n\tif File_transport_internet_websocket_config_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_transport_internet_websocket_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Header); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_transport_internet_websocket_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Config); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_transport_internet_websocket_config_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   2,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_transport_internet_websocket_config_proto_goTypes,\n\t\tDependencyIndexes: file_transport_internet_websocket_config_proto_depIdxs,\n\t\tMessageInfos:      file_transport_internet_websocket_config_proto_msgTypes,\n\t}.Build()\n\tFile_transport_internet_websocket_config_proto = out.File\n\tfile_transport_internet_websocket_config_proto_rawDesc = nil\n\tfile_transport_internet_websocket_config_proto_goTypes = nil\n\tfile_transport_internet_websocket_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "transport/internet/websocket/config.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.transport.internet.websocket;\noption csharp_namespace = \"V2Ray.Core.Transport.Internet.Websocket\";\noption go_package = \"v2ray.com/core/transport/internet/websocket\";\noption java_package = \"com.v2ray.core.transport.internet.websocket\";\noption java_multiple_files = true;\n\nmessage Header {\n  string key = 1;\n  string value = 2;\n}\n\nmessage Config {\n  reserved 1;\n\n  // URL path to the WebSocket service. Empty value means root(/).\n  string path = 2;\n\n  repeated Header header = 3;\n\n  bool accept_proxy_protocol = 4;\n}\n"
  },
  {
    "path": "transport/internet/websocket/connection.go",
    "content": "// +build !confonly\n\npackage websocket\n\nimport (\n\t\"io\"\n\t\"net\"\n\t\"time\"\n\n\t\"github.com/gorilla/websocket\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/errors\"\n\t\"v2ray.com/core/common/serial\"\n)\n\nvar (\n\t_ buf.Writer = (*connection)(nil)\n)\n\n// connection is a wrapper for net.Conn over WebSocket connection.\ntype connection struct {\n\tconn       *websocket.Conn\n\treader     io.Reader\n\tremoteAddr net.Addr\n}\n\nfunc newConnection(conn *websocket.Conn, remoteAddr net.Addr) *connection {\n\treturn &connection{\n\t\tconn:       conn,\n\t\tremoteAddr: remoteAddr,\n\t}\n}\n\n// Read implements net.Conn.Read()\nfunc (c *connection) Read(b []byte) (int, error) {\n\tfor {\n\t\treader, err := c.getReader()\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\n\t\tnBytes, err := reader.Read(b)\n\t\tif errors.Cause(err) == io.EOF {\n\t\t\tc.reader = nil\n\t\t\tcontinue\n\t\t}\n\t\treturn nBytes, err\n\t}\n}\n\nfunc (c *connection) getReader() (io.Reader, error) {\n\tif c.reader != nil {\n\t\treturn c.reader, nil\n\t}\n\n\t_, reader, err := c.conn.NextReader()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tc.reader = reader\n\treturn reader, nil\n}\n\n// Write implements io.Writer.\nfunc (c *connection) Write(b []byte) (int, error) {\n\tif err := c.conn.WriteMessage(websocket.BinaryMessage, b); err != nil {\n\t\treturn 0, err\n\t}\n\treturn len(b), nil\n}\n\nfunc (c *connection) WriteMultiBuffer(mb buf.MultiBuffer) error {\n\tmb = buf.Compact(mb)\n\tmb, err := buf.WriteMultiBuffer(c, mb)\n\tbuf.ReleaseMulti(mb)\n\treturn err\n}\n\nfunc (c *connection) Close() error {\n\tvar errors []interface{}\n\tif err := c.conn.WriteControl(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, \"\"), time.Now().Add(time.Second*5)); err != nil {\n\t\terrors = append(errors, err)\n\t}\n\tif err := c.conn.Close(); err != nil {\n\t\terrors = append(errors, err)\n\t}\n\tif len(errors) > 0 {\n\t\treturn newError(\"failed to close connection\").Base(newError(serial.Concat(errors...)))\n\t}\n\treturn nil\n}\n\nfunc (c *connection) LocalAddr() net.Addr {\n\treturn c.conn.LocalAddr()\n}\n\nfunc (c *connection) RemoteAddr() net.Addr {\n\treturn c.remoteAddr\n}\n\nfunc (c *connection) SetDeadline(t time.Time) error {\n\tif err := c.SetReadDeadline(t); err != nil {\n\t\treturn err\n\t}\n\treturn c.SetWriteDeadline(t)\n}\n\nfunc (c *connection) SetReadDeadline(t time.Time) error {\n\treturn c.conn.SetReadDeadline(t)\n}\n\nfunc (c *connection) SetWriteDeadline(t time.Time) error {\n\treturn c.conn.SetWriteDeadline(t)\n}\n"
  },
  {
    "path": "transport/internet/websocket/dialer.go",
    "content": "// +build !confonly\n\npackage websocket\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/gorilla/websocket\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/session\"\n\t\"v2ray.com/core/transport/internet\"\n\t\"v2ray.com/core/transport/internet/tls\"\n)\n\n// Dial dials a WebSocket connection to the given destination.\nfunc Dial(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (internet.Connection, error) {\n\tnewError(\"creating connection to \", dest).WriteToLog(session.ExportIDToError(ctx))\n\n\tconn, err := dialWebsocket(ctx, dest, streamSettings)\n\tif err != nil {\n\t\treturn nil, newError(\"failed to dial WebSocket\").Base(err)\n\t}\n\treturn internet.Connection(conn), nil\n}\n\nfunc init() {\n\tcommon.Must(internet.RegisterTransportDialer(protocolName, Dial))\n}\n\nfunc dialWebsocket(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (net.Conn, error) {\n\twsSettings := streamSettings.ProtocolSettings.(*Config)\n\n\tdialer := &websocket.Dialer{\n\t\tNetDial: func(network, addr string) (net.Conn, error) {\n\t\t\treturn internet.DialSystem(ctx, dest, streamSettings.SocketSettings)\n\t\t},\n\t\tReadBufferSize:   4 * 1024,\n\t\tWriteBufferSize:  4 * 1024,\n\t\tHandshakeTimeout: time.Second * 8,\n\t}\n\n\tprotocol := \"ws\"\n\n\tif config := tls.ConfigFromStreamSettings(streamSettings); config != nil {\n\t\tprotocol = \"wss\"\n\t\tdialer.TLSClientConfig = config.GetTLSConfig(tls.WithDestination(dest), tls.WithNextProto(\"http/1.1\"))\n\t}\n\n\thost := dest.NetAddr()\n\tif (protocol == \"ws\" && dest.Port == 80) || (protocol == \"wss\" && dest.Port == 443) {\n\t\thost = dest.Address.String()\n\t}\n\turi := protocol + \"://\" + host + wsSettings.GetNormalizedPath()\n\n\tconn, resp, err := dialer.Dial(uri, wsSettings.GetRequestHeader())\n\tif err != nil {\n\t\tvar reason string\n\t\tif resp != nil {\n\t\t\treason = resp.Status\n\t\t}\n\t\treturn nil, newError(\"failed to dial to (\", uri, \"): \", reason).Base(err)\n\t}\n\n\treturn newConnection(conn, conn.RemoteAddr()), nil\n}\n"
  },
  {
    "path": "transport/internet/websocket/errors.generated.go",
    "content": "package websocket\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "transport/internet/websocket/hub.go",
    "content": "// +build !confonly\n\npackage websocket\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"net/http\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/gorilla/websocket\"\n\t\"github.com/pires/go-proxyproto\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/net\"\n\thttp_proto \"v2ray.com/core/common/protocol/http\"\n\t\"v2ray.com/core/common/session\"\n\t\"v2ray.com/core/transport/internet\"\n\tv2tls \"v2ray.com/core/transport/internet/tls\"\n)\n\ntype requestHandler struct {\n\tpath string\n\tln   *Listener\n}\n\nvar upgrader = &websocket.Upgrader{\n\tReadBufferSize:   4 * 1024,\n\tWriteBufferSize:  4 * 1024,\n\tHandshakeTimeout: time.Second * 4,\n\tCheckOrigin: func(r *http.Request) bool {\n\t\treturn true\n\t},\n}\n\nfunc (h *requestHandler) ServeHTTP(writer http.ResponseWriter, request *http.Request) {\n\tif request.URL.Path != h.path {\n\t\twriter.WriteHeader(http.StatusNotFound)\n\t\treturn\n\t}\n\tconn, err := upgrader.Upgrade(writer, request, nil)\n\tif err != nil {\n\t\tnewError(\"failed to convert to WebSocket connection\").Base(err).WriteToLog()\n\t\treturn\n\t}\n\n\tforwardedAddrs := http_proto.ParseXForwardedFor(request.Header)\n\tremoteAddr := conn.RemoteAddr()\n\tif len(forwardedAddrs) > 0 && forwardedAddrs[0].Family().IsIP() {\n\t\tremoteAddr.(*net.TCPAddr).IP = forwardedAddrs[0].IP()\n\t}\n\n\th.ln.addConn(newConnection(conn, remoteAddr))\n}\n\ntype Listener struct {\n\tsync.Mutex\n\tserver   http.Server\n\tlistener net.Listener\n\tconfig   *Config\n\taddConn  internet.ConnHandler\n}\n\nfunc ListenWS(ctx context.Context, address net.Address, port net.Port, streamSettings *internet.MemoryStreamConfig, addConn internet.ConnHandler) (internet.Listener, error) {\n\tlistener, err := internet.ListenSystem(ctx, &net.TCPAddr{\n\t\tIP:   address.IP(),\n\t\tPort: int(port),\n\t}, streamSettings.SocketSettings)\n\tif err != nil {\n\t\treturn nil, newError(\"failed to listen TCP(for WS) on\", address, \":\", port).Base(err)\n\t}\n\tnewError(\"listening TCP(for WS) on \", address, \":\", port).WriteToLog(session.ExportIDToError(ctx))\n\n\twsSettings := streamSettings.ProtocolSettings.(*Config)\n\n\tif wsSettings.AcceptProxyProtocol {\n\t\tpolicyFunc := func(upstream net.Addr) (proxyproto.Policy, error) { return proxyproto.REQUIRE, nil }\n\t\tlistener = &proxyproto.Listener{Listener: listener, Policy: policyFunc}\n\t\tnewError(\"accepting PROXY protocol\").AtWarning().WriteToLog(session.ExportIDToError(ctx))\n\t}\n\n\tif config := v2tls.ConfigFromStreamSettings(streamSettings); config != nil {\n\t\tif tlsConfig := config.GetTLSConfig(); tlsConfig != nil {\n\t\t\tlistener = tls.NewListener(listener, tlsConfig)\n\t\t}\n\t}\n\n\tl := &Listener{\n\t\tconfig:   wsSettings,\n\t\taddConn:  addConn,\n\t\tlistener: listener,\n\t}\n\n\tl.server = http.Server{\n\t\tHandler: &requestHandler{\n\t\t\tpath: wsSettings.GetNormalizedPath(),\n\t\t\tln:   l,\n\t\t},\n\t\tReadHeaderTimeout: time.Second * 4,\n\t\tMaxHeaderBytes:    2048,\n\t}\n\n\tgo func() {\n\t\tif err := l.server.Serve(l.listener); err != nil {\n\t\t\tnewError(\"failed to serve http for WebSocket\").Base(err).AtWarning().WriteToLog(session.ExportIDToError(ctx))\n\t\t}\n\t}()\n\n\treturn l, err\n}\n\n// Addr implements net.Listener.Addr().\nfunc (ln *Listener) Addr() net.Addr {\n\treturn ln.listener.Addr()\n}\n\n// Close implements net.Listener.Close().\nfunc (ln *Listener) Close() error {\n\treturn ln.listener.Close()\n}\n\nfunc init() {\n\tcommon.Must(internet.RegisterTransportListener(protocolName, ListenWS))\n}\n"
  },
  {
    "path": "transport/internet/websocket/ws.go",
    "content": "/*Package websocket implements Websocket transport\n\nWebsocket transport implements an HTTP(S) compliable, surveillance proof transport method with plausible deniability.\n*/\npackage websocket\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n"
  },
  {
    "path": "transport/internet/websocket/ws_test.go",
    "content": "package websocket_test\n\nimport (\n\t\"context\"\n\t\"runtime\"\n\t\"testing\"\n\t\"time\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol/tls/cert\"\n\t\"v2ray.com/core/transport/internet\"\n\t\"v2ray.com/core/transport/internet/tls\"\n\t. \"v2ray.com/core/transport/internet/websocket\"\n)\n\nfunc Test_listenWSAndDial(t *testing.T) {\n\tlisten, err := ListenWS(context.Background(), net.LocalHostIP, 13146, &internet.MemoryStreamConfig{\n\t\tProtocolName: \"websocket\",\n\t\tProtocolSettings: &Config{\n\t\t\tPath: \"ws\",\n\t\t},\n\t}, func(conn internet.Connection) {\n\t\tgo func(c internet.Connection) {\n\t\t\tdefer c.Close()\n\n\t\t\tvar b [1024]byte\n\t\t\t_, err := c.Read(b[:])\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tcommon.Must2(c.Write([]byte(\"Response\")))\n\t\t}(conn)\n\t})\n\tcommon.Must(err)\n\n\tctx := context.Background()\n\tstreamSettings := &internet.MemoryStreamConfig{\n\t\tProtocolName:     \"websocket\",\n\t\tProtocolSettings: &Config{Path: \"ws\"},\n\t}\n\tconn, err := Dial(ctx, net.TCPDestination(net.DomainAddress(\"localhost\"), 13146), streamSettings)\n\n\tcommon.Must(err)\n\t_, err = conn.Write([]byte(\"Test connection 1\"))\n\tcommon.Must(err)\n\n\tvar b [1024]byte\n\tn, err := conn.Read(b[:])\n\tcommon.Must(err)\n\tif string(b[:n]) != \"Response\" {\n\t\tt.Error(\"response: \", string(b[:n]))\n\t}\n\n\tcommon.Must(conn.Close())\n\t<-time.After(time.Second * 5)\n\tconn, err = Dial(ctx, net.TCPDestination(net.DomainAddress(\"localhost\"), 13146), streamSettings)\n\tcommon.Must(err)\n\t_, err = conn.Write([]byte(\"Test connection 2\"))\n\tcommon.Must(err)\n\tn, err = conn.Read(b[:])\n\tcommon.Must(err)\n\tif string(b[:n]) != \"Response\" {\n\t\tt.Error(\"response: \", string(b[:n]))\n\t}\n\tcommon.Must(conn.Close())\n\n\tcommon.Must(listen.Close())\n}\n\nfunc TestDialWithRemoteAddr(t *testing.T) {\n\tlisten, err := ListenWS(context.Background(), net.LocalHostIP, 13148, &internet.MemoryStreamConfig{\n\t\tProtocolName: \"websocket\",\n\t\tProtocolSettings: &Config{\n\t\t\tPath: \"ws\",\n\t\t},\n\t}, func(conn internet.Connection) {\n\t\tgo func(c internet.Connection) {\n\t\t\tdefer c.Close()\n\n\t\t\tvar b [1024]byte\n\t\t\t_, err := c.Read(b[:])\n\t\t\t//common.Must(err)\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t_, err = c.Write([]byte(\"Response\"))\n\t\t\tcommon.Must(err)\n\t\t}(conn)\n\t})\n\tcommon.Must(err)\n\n\tconn, err := Dial(context.Background(), net.TCPDestination(net.DomainAddress(\"localhost\"), 13148), &internet.MemoryStreamConfig{\n\t\tProtocolName:     \"websocket\",\n\t\tProtocolSettings: &Config{Path: \"ws\", Header: []*Header{{Key: \"X-Forwarded-For\", Value: \"1.1.1.1\"}}},\n\t})\n\n\tcommon.Must(err)\n\t_, err = conn.Write([]byte(\"Test connection 1\"))\n\tcommon.Must(err)\n\n\tvar b [1024]byte\n\tn, err := conn.Read(b[:])\n\tcommon.Must(err)\n\tif string(b[:n]) != \"Response\" {\n\t\tt.Error(\"response: \", string(b[:n]))\n\t}\n\n\tcommon.Must(listen.Close())\n}\n\nfunc Test_listenWSAndDial_TLS(t *testing.T) {\n\tif runtime.GOARCH == \"arm64\" {\n\t\treturn\n\t}\n\n\tstart := time.Now()\n\n\tstreamSettings := &internet.MemoryStreamConfig{\n\t\tProtocolName: \"websocket\",\n\t\tProtocolSettings: &Config{\n\t\t\tPath: \"wss\",\n\t\t},\n\t\tSecurityType: \"tls\",\n\t\tSecuritySettings: &tls.Config{\n\t\t\tAllowInsecure: true,\n\t\t\tCertificate:   []*tls.Certificate{tls.ParseCertificate(cert.MustGenerate(nil, cert.CommonName(\"localhost\")))},\n\t\t},\n\t}\n\tlisten, err := ListenWS(context.Background(), net.LocalHostIP, 13143, streamSettings, func(conn internet.Connection) {\n\t\tgo func() {\n\t\t\t_ = conn.Close()\n\t\t}()\n\t})\n\tcommon.Must(err)\n\tdefer listen.Close()\n\n\tconn, err := Dial(context.Background(), net.TCPDestination(net.DomainAddress(\"localhost\"), 13143), streamSettings)\n\tcommon.Must(err)\n\t_ = conn.Close()\n\n\tend := time.Now()\n\tif !end.Before(start.Add(time.Second * 5)) {\n\t\tt.Error(\"end: \", end, \" start: \", start)\n\t}\n}\n"
  },
  {
    "path": "transport/internet/xtls/config.go",
    "content": "// +build !confonly\n\npackage xtls\n\nimport (\n\t\"crypto/x509\"\n\t\"sync\"\n\t\"time\"\n\n\txtls \"github.com/xtls/go\"\n\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol/tls/cert\"\n\t\"v2ray.com/core/transport/internet\"\n)\n\nvar (\n\tglobalSessionCache = xtls.NewLRUClientSessionCache(128)\n)\n\n// ParseCertificate converts a cert.Certificate to Certificate.\nfunc ParseCertificate(c *cert.Certificate) *Certificate {\n\tcertPEM, keyPEM := c.ToPEM()\n\treturn &Certificate{\n\t\tCertificate: certPEM,\n\t\tKey:         keyPEM,\n\t}\n}\n\nfunc (c *Config) loadSelfCertPool() (*x509.CertPool, error) {\n\troot := x509.NewCertPool()\n\tfor _, cert := range c.Certificate {\n\t\tif !root.AppendCertsFromPEM(cert.Certificate) {\n\t\t\treturn nil, newError(\"failed to append cert\").AtWarning()\n\t\t}\n\t}\n\treturn root, nil\n}\n\n// BuildCertificates builds a list of TLS certificates from proto definition.\nfunc (c *Config) BuildCertificates() []xtls.Certificate {\n\tcerts := make([]xtls.Certificate, 0, len(c.Certificate))\n\tfor _, entry := range c.Certificate {\n\t\tif entry.Usage != Certificate_ENCIPHERMENT {\n\t\t\tcontinue\n\t\t}\n\t\tkeyPair, err := xtls.X509KeyPair(entry.Certificate, entry.Key)\n\t\tif err != nil {\n\t\t\tnewError(\"ignoring invalid X509 key pair\").Base(err).AtWarning().WriteToLog()\n\t\t\tcontinue\n\t\t}\n\t\tcerts = append(certs, keyPair)\n\t}\n\treturn certs\n}\n\nfunc isCertificateExpired(c *xtls.Certificate) bool {\n\tif c.Leaf == nil && len(c.Certificate) > 0 {\n\t\tif pc, err := x509.ParseCertificate(c.Certificate[0]); err == nil {\n\t\t\tc.Leaf = pc\n\t\t}\n\t}\n\n\t// If leaf is not there, the certificate is probably not used yet. We trust user to provide a valid certificate.\n\treturn c.Leaf != nil && c.Leaf.NotAfter.Before(time.Now().Add(-time.Minute))\n}\n\nfunc issueCertificate(rawCA *Certificate, domain string) (*xtls.Certificate, error) {\n\tparent, err := cert.ParseCertificate(rawCA.Certificate, rawCA.Key)\n\tif err != nil {\n\t\treturn nil, newError(\"failed to parse raw certificate\").Base(err)\n\t}\n\tnewCert, err := cert.Generate(parent, cert.CommonName(domain), cert.DNSNames(domain))\n\tif err != nil {\n\t\treturn nil, newError(\"failed to generate new certificate for \", domain).Base(err)\n\t}\n\tnewCertPEM, newKeyPEM := newCert.ToPEM()\n\tcert, err := xtls.X509KeyPair(newCertPEM, newKeyPEM)\n\treturn &cert, err\n}\n\nfunc (c *Config) getCustomCA() []*Certificate {\n\tcerts := make([]*Certificate, 0, len(c.Certificate))\n\tfor _, certificate := range c.Certificate {\n\t\tif certificate.Usage == Certificate_AUTHORITY_ISSUE {\n\t\t\tcerts = append(certs, certificate)\n\t\t}\n\t}\n\treturn certs\n}\n\nfunc getGetCertificateFunc(c *xtls.Config, ca []*Certificate) func(hello *xtls.ClientHelloInfo) (*xtls.Certificate, error) {\n\tvar access sync.RWMutex\n\n\treturn func(hello *xtls.ClientHelloInfo) (*xtls.Certificate, error) {\n\t\tdomain := hello.ServerName\n\t\tcertExpired := false\n\n\t\taccess.RLock()\n\t\tcertificate, found := c.NameToCertificate[domain]\n\t\taccess.RUnlock()\n\n\t\tif found {\n\t\t\tif !isCertificateExpired(certificate) {\n\t\t\t\treturn certificate, nil\n\t\t\t}\n\t\t\tcertExpired = true\n\t\t}\n\n\t\tif certExpired {\n\t\t\tnewCerts := make([]xtls.Certificate, 0, len(c.Certificates))\n\n\t\t\taccess.Lock()\n\t\t\tfor _, certificate := range c.Certificates {\n\t\t\t\tif !isCertificateExpired(&certificate) {\n\t\t\t\t\tnewCerts = append(newCerts, certificate)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tc.Certificates = newCerts\n\t\t\taccess.Unlock()\n\t\t}\n\n\t\tvar issuedCertificate *xtls.Certificate\n\n\t\t// Create a new certificate from existing CA if possible\n\t\tfor _, rawCert := range ca {\n\t\t\tif rawCert.Usage == Certificate_AUTHORITY_ISSUE {\n\t\t\t\tnewCert, err := issueCertificate(rawCert, domain)\n\t\t\t\tif err != nil {\n\t\t\t\t\tnewError(\"failed to issue new certificate for \", domain).Base(err).WriteToLog()\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\taccess.Lock()\n\t\t\t\tc.Certificates = append(c.Certificates, *newCert)\n\t\t\t\tissuedCertificate = &c.Certificates[len(c.Certificates)-1]\n\t\t\t\taccess.Unlock()\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif issuedCertificate == nil {\n\t\t\treturn nil, newError(\"failed to create a new certificate for \", domain)\n\t\t}\n\n\t\taccess.Lock()\n\t\tc.BuildNameToCertificate()\n\t\taccess.Unlock()\n\n\t\treturn issuedCertificate, nil\n\t}\n}\n\nfunc (c *Config) parseServerName() string {\n\treturn c.ServerName\n}\n\n// GetXTLSConfig converts this Config into xtls.Config.\nfunc (c *Config) GetXTLSConfig(opts ...Option) *xtls.Config {\n\troot, err := c.getCertPool()\n\tif err != nil {\n\t\tnewError(\"failed to load system root certificate\").AtError().Base(err).WriteToLog()\n\t}\n\n\tconfig := &xtls.Config{\n\t\tClientSessionCache:     globalSessionCache,\n\t\tRootCAs:                root,\n\t\tInsecureSkipVerify:     c.AllowInsecure,\n\t\tNextProtos:             c.NextProtocol,\n\t\tSessionTicketsDisabled: c.DisableSessionResumption,\n\t}\n\tif c == nil {\n\t\treturn config\n\t}\n\n\tfor _, opt := range opts {\n\t\topt(config)\n\t}\n\n\tconfig.Certificates = c.BuildCertificates()\n\tconfig.BuildNameToCertificate()\n\n\tcaCerts := c.getCustomCA()\n\tif len(caCerts) > 0 {\n\t\tconfig.GetCertificate = getGetCertificateFunc(config, caCerts)\n\t}\n\n\tif sn := c.parseServerName(); len(sn) > 0 {\n\t\tconfig.ServerName = sn\n\t}\n\n\tif len(config.NextProtos) == 0 {\n\t\tconfig.NextProtos = []string{\"h2\", \"http/1.1\"}\n\t}\n\n\treturn config\n}\n\n// Option for building XTLS config.\ntype Option func(*xtls.Config)\n\n// WithDestination sets the server name in XTLS config.\nfunc WithDestination(dest net.Destination) Option {\n\treturn func(config *xtls.Config) {\n\t\tif dest.Address.Family().IsDomain() && config.ServerName == \"\" {\n\t\t\tconfig.ServerName = dest.Address.Domain()\n\t\t}\n\t}\n}\n\n// WithNextProto sets the ALPN values in XTLS config.\nfunc WithNextProto(protocol ...string) Option {\n\treturn func(config *xtls.Config) {\n\t\tif len(config.NextProtos) == 0 {\n\t\t\tconfig.NextProtos = protocol\n\t\t}\n\t}\n}\n\n// ConfigFromStreamSettings fetches Config from stream settings. Nil if not found.\nfunc ConfigFromStreamSettings(settings *internet.MemoryStreamConfig) *Config {\n\tif settings == nil {\n\t\treturn nil\n\t}\n\tconfig, ok := settings.SecuritySettings.(*Config)\n\tif !ok {\n\t\treturn nil\n\t}\n\treturn config\n}\n"
  },
  {
    "path": "transport/internet/xtls/config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.13.0\n// source: transport/internet/xtls/config.proto\n\npackage xtls\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype Certificate_Usage int32\n\nconst (\n\tCertificate_ENCIPHERMENT     Certificate_Usage = 0\n\tCertificate_AUTHORITY_VERIFY Certificate_Usage = 1\n\tCertificate_AUTHORITY_ISSUE  Certificate_Usage = 2\n)\n\n// Enum value maps for Certificate_Usage.\nvar (\n\tCertificate_Usage_name = map[int32]string{\n\t\t0: \"ENCIPHERMENT\",\n\t\t1: \"AUTHORITY_VERIFY\",\n\t\t2: \"AUTHORITY_ISSUE\",\n\t}\n\tCertificate_Usage_value = map[string]int32{\n\t\t\"ENCIPHERMENT\":     0,\n\t\t\"AUTHORITY_VERIFY\": 1,\n\t\t\"AUTHORITY_ISSUE\":  2,\n\t}\n)\n\nfunc (x Certificate_Usage) Enum() *Certificate_Usage {\n\tp := new(Certificate_Usage)\n\t*p = x\n\treturn p\n}\n\nfunc (x Certificate_Usage) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (Certificate_Usage) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_transport_internet_xtls_config_proto_enumTypes[0].Descriptor()\n}\n\nfunc (Certificate_Usage) Type() protoreflect.EnumType {\n\treturn &file_transport_internet_xtls_config_proto_enumTypes[0]\n}\n\nfunc (x Certificate_Usage) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use Certificate_Usage.Descriptor instead.\nfunc (Certificate_Usage) EnumDescriptor() ([]byte, []int) {\n\treturn file_transport_internet_xtls_config_proto_rawDescGZIP(), []int{0, 0}\n}\n\ntype Certificate struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// XTLS certificate in x509 format.\n\tCertificate []byte `protobuf:\"bytes,1,opt,name=Certificate,proto3\" json:\"Certificate,omitempty\"`\n\t// XTLS key in x509 format.\n\tKey   []byte            `protobuf:\"bytes,2,opt,name=Key,proto3\" json:\"Key,omitempty\"`\n\tUsage Certificate_Usage `protobuf:\"varint,3,opt,name=usage,proto3,enum=v2ray.core.transport.internet.xtls.Certificate_Usage\" json:\"usage,omitempty\"`\n}\n\nfunc (x *Certificate) Reset() {\n\t*x = Certificate{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_transport_internet_xtls_config_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Certificate) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Certificate) ProtoMessage() {}\n\nfunc (x *Certificate) ProtoReflect() protoreflect.Message {\n\tmi := &file_transport_internet_xtls_config_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Certificate.ProtoReflect.Descriptor instead.\nfunc (*Certificate) Descriptor() ([]byte, []int) {\n\treturn file_transport_internet_xtls_config_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *Certificate) GetCertificate() []byte {\n\tif x != nil {\n\t\treturn x.Certificate\n\t}\n\treturn nil\n}\n\nfunc (x *Certificate) GetKey() []byte {\n\tif x != nil {\n\t\treturn x.Key\n\t}\n\treturn nil\n}\n\nfunc (x *Certificate) GetUsage() Certificate_Usage {\n\tif x != nil {\n\t\treturn x.Usage\n\t}\n\treturn Certificate_ENCIPHERMENT\n}\n\ntype Config struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Whether or not to allow self-signed certificates.\n\tAllowInsecure bool `protobuf:\"varint,1,opt,name=allow_insecure,json=allowInsecure,proto3\" json:\"allow_insecure,omitempty\"`\n\t// Whether or not to allow insecure cipher suites.\n\tAllowInsecureCiphers bool `protobuf:\"varint,5,opt,name=allow_insecure_ciphers,json=allowInsecureCiphers,proto3\" json:\"allow_insecure_ciphers,omitempty\"`\n\t// List of certificates to be served on server.\n\tCertificate []*Certificate `protobuf:\"bytes,2,rep,name=certificate,proto3\" json:\"certificate,omitempty\"`\n\t// Override server name.\n\tServerName string `protobuf:\"bytes,3,opt,name=server_name,json=serverName,proto3\" json:\"server_name,omitempty\"`\n\t// Lists of string as ALPN values.\n\tNextProtocol []string `protobuf:\"bytes,4,rep,name=next_protocol,json=nextProtocol,proto3\" json:\"next_protocol,omitempty\"`\n\t// Whether or not to disable session (ticket) resumption.\n\tDisableSessionResumption bool `protobuf:\"varint,6,opt,name=disable_session_resumption,json=disableSessionResumption,proto3\" json:\"disable_session_resumption,omitempty\"`\n\t// If true, root certificates on the system will not be loaded for\n\t// verification.\n\tDisableSystemRoot bool `protobuf:\"varint,7,opt,name=disable_system_root,json=disableSystemRoot,proto3\" json:\"disable_system_root,omitempty\"`\n}\n\nfunc (x *Config) Reset() {\n\t*x = Config{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_transport_internet_xtls_config_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Config) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Config) ProtoMessage() {}\n\nfunc (x *Config) ProtoReflect() protoreflect.Message {\n\tmi := &file_transport_internet_xtls_config_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Config.ProtoReflect.Descriptor instead.\nfunc (*Config) Descriptor() ([]byte, []int) {\n\treturn file_transport_internet_xtls_config_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *Config) GetAllowInsecure() bool {\n\tif x != nil {\n\t\treturn x.AllowInsecure\n\t}\n\treturn false\n}\n\nfunc (x *Config) GetAllowInsecureCiphers() bool {\n\tif x != nil {\n\t\treturn x.AllowInsecureCiphers\n\t}\n\treturn false\n}\n\nfunc (x *Config) GetCertificate() []*Certificate {\n\tif x != nil {\n\t\treturn x.Certificate\n\t}\n\treturn nil\n}\n\nfunc (x *Config) GetServerName() string {\n\tif x != nil {\n\t\treturn x.ServerName\n\t}\n\treturn \"\"\n}\n\nfunc (x *Config) GetNextProtocol() []string {\n\tif x != nil {\n\t\treturn x.NextProtocol\n\t}\n\treturn nil\n}\n\nfunc (x *Config) GetDisableSessionResumption() bool {\n\tif x != nil {\n\t\treturn x.DisableSessionResumption\n\t}\n\treturn false\n}\n\nfunc (x *Config) GetDisableSystemRoot() bool {\n\tif x != nil {\n\t\treturn x.DisableSystemRoot\n\t}\n\treturn false\n}\n\nvar File_transport_internet_xtls_config_proto protoreflect.FileDescriptor\n\nvar file_transport_internet_xtls_config_proto_rawDesc = []byte{\n\t0x0a, 0x24, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65,\n\t0x72, 0x6e, 0x65, 0x74, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,\n\t0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x22, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,\n\t0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74,\n\t0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x78, 0x74, 0x6c, 0x73, 0x22, 0xd4, 0x01, 0x0a, 0x0b, 0x43,\n\t0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x43, 0x65,\n\t0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52,\n\t0x0b, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03,\n\t0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x4b, 0x65, 0x79, 0x12, 0x4b,\n\t0x0a, 0x05, 0x75, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x35, 0x2e,\n\t0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73,\n\t0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x78, 0x74,\n\t0x6c, 0x73, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x2e, 0x55,\n\t0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x75, 0x73, 0x61, 0x67, 0x65, 0x22, 0x44, 0x0a, 0x05, 0x55,\n\t0x73, 0x61, 0x67, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x45, 0x4e, 0x43, 0x49, 0x50, 0x48, 0x45, 0x52,\n\t0x4d, 0x45, 0x4e, 0x54, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x41, 0x55, 0x54, 0x48, 0x4f, 0x52,\n\t0x49, 0x54, 0x59, 0x5f, 0x56, 0x45, 0x52, 0x49, 0x46, 0x59, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f,\n\t0x41, 0x55, 0x54, 0x48, 0x4f, 0x52, 0x49, 0x54, 0x59, 0x5f, 0x49, 0x53, 0x53, 0x55, 0x45, 0x10,\n\t0x02, 0x22, 0xec, 0x02, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x25, 0x0a, 0x0e,\n\t0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x18, 0x01,\n\t0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x49, 0x6e, 0x73, 0x65, 0x63,\n\t0x75, 0x72, 0x65, 0x12, 0x34, 0x0a, 0x16, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x69, 0x6e, 0x73,\n\t0x65, 0x63, 0x75, 0x72, 0x65, 0x5f, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20,\n\t0x01, 0x28, 0x08, 0x52, 0x14, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x49, 0x6e, 0x73, 0x65, 0x63, 0x75,\n\t0x72, 0x65, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, 0x73, 0x12, 0x51, 0x0a, 0x0b, 0x63, 0x65, 0x72,\n\t0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f,\n\t0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e,\n\t0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x78,\n\t0x74, 0x6c, 0x73, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52,\n\t0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x1f, 0x0a, 0x0b,\n\t0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28,\n\t0x09, 0x52, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x23, 0x0a,\n\t0x0d, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x04,\n\t0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63,\n\t0x6f, 0x6c, 0x12, 0x3c, 0x0a, 0x1a, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x65,\n\t0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6d, 0x70, 0x74, 0x69, 0x6f, 0x6e,\n\t0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x18, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53,\n\t0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x70, 0x74, 0x69, 0x6f, 0x6e,\n\t0x12, 0x2e, 0x0a, 0x13, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x79, 0x73, 0x74,\n\t0x65, 0x6d, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x64,\n\t0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x52, 0x6f, 0x6f, 0x74,\n\t0x42, 0x77, 0x0a, 0x26, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,\n\t0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74,\n\t0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x78, 0x74, 0x6c, 0x73, 0x50, 0x01, 0x5a, 0x26, 0x76, 0x32,\n\t0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72, 0x61,\n\t0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2f,\n\t0x78, 0x74, 0x6c, 0x73, 0xaa, 0x02, 0x22, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72,\n\t0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65,\n\t0x72, 0x6e, 0x65, 0x74, 0x2e, 0x58, 0x74, 0x6c, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,\n\t0x33,\n}\n\nvar (\n\tfile_transport_internet_xtls_config_proto_rawDescOnce sync.Once\n\tfile_transport_internet_xtls_config_proto_rawDescData = file_transport_internet_xtls_config_proto_rawDesc\n)\n\nfunc file_transport_internet_xtls_config_proto_rawDescGZIP() []byte {\n\tfile_transport_internet_xtls_config_proto_rawDescOnce.Do(func() {\n\t\tfile_transport_internet_xtls_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_transport_internet_xtls_config_proto_rawDescData)\n\t})\n\treturn file_transport_internet_xtls_config_proto_rawDescData\n}\n\nvar file_transport_internet_xtls_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1)\nvar file_transport_internet_xtls_config_proto_msgTypes = make([]protoimpl.MessageInfo, 2)\nvar file_transport_internet_xtls_config_proto_goTypes = []interface{}{\n\t(Certificate_Usage)(0), // 0: v2ray.core.transport.internet.xtls.Certificate.Usage\n\t(*Certificate)(nil),    // 1: v2ray.core.transport.internet.xtls.Certificate\n\t(*Config)(nil),         // 2: v2ray.core.transport.internet.xtls.Config\n}\nvar file_transport_internet_xtls_config_proto_depIdxs = []int32{\n\t0, // 0: v2ray.core.transport.internet.xtls.Certificate.usage:type_name -> v2ray.core.transport.internet.xtls.Certificate.Usage\n\t1, // 1: v2ray.core.transport.internet.xtls.Config.certificate:type_name -> v2ray.core.transport.internet.xtls.Certificate\n\t2, // [2:2] is the sub-list for method output_type\n\t2, // [2:2] is the sub-list for method input_type\n\t2, // [2:2] is the sub-list for extension type_name\n\t2, // [2:2] is the sub-list for extension extendee\n\t0, // [0:2] is the sub-list for field type_name\n}\n\nfunc init() { file_transport_internet_xtls_config_proto_init() }\nfunc file_transport_internet_xtls_config_proto_init() {\n\tif File_transport_internet_xtls_config_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_transport_internet_xtls_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Certificate); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_transport_internet_xtls_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Config); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_transport_internet_xtls_config_proto_rawDesc,\n\t\t\tNumEnums:      1,\n\t\t\tNumMessages:   2,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_transport_internet_xtls_config_proto_goTypes,\n\t\tDependencyIndexes: file_transport_internet_xtls_config_proto_depIdxs,\n\t\tEnumInfos:         file_transport_internet_xtls_config_proto_enumTypes,\n\t\tMessageInfos:      file_transport_internet_xtls_config_proto_msgTypes,\n\t}.Build()\n\tFile_transport_internet_xtls_config_proto = out.File\n\tfile_transport_internet_xtls_config_proto_rawDesc = nil\n\tfile_transport_internet_xtls_config_proto_goTypes = nil\n\tfile_transport_internet_xtls_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "transport/internet/xtls/config.proto",
    "content": "syntax = \"proto3\";\n\npackage v2ray.core.transport.internet.xtls;\noption csharp_namespace = \"V2Ray.Core.Transport.Internet.Xtls\";\noption go_package = \"v2ray.com/core/transport/internet/xtls\";\noption java_package = \"com.v2ray.core.transport.internet.xtls\";\noption java_multiple_files = true;\n\nmessage Certificate {\n  // XTLS certificate in x509 format.\n  bytes Certificate = 1;\n\n  // XTLS key in x509 format.\n  bytes Key = 2;\n\n  enum Usage {\n    ENCIPHERMENT = 0;\n    AUTHORITY_VERIFY = 1;\n    AUTHORITY_ISSUE = 2;\n  }\n\n  Usage usage = 3;\n}\n\nmessage Config {\n  // Whether or not to allow self-signed certificates.\n  bool allow_insecure = 1;\n\n  // Whether or not to allow insecure cipher suites.\n  bool allow_insecure_ciphers = 5;\n\n  // List of certificates to be served on server.\n  repeated Certificate certificate = 2;\n\n  // Override server name.\n  string server_name = 3;\n\n  // Lists of string as ALPN values.\n  repeated string next_protocol = 4;\n\n  // Whether or not to disable session (ticket) resumption.\n  bool disable_session_resumption = 6;\n\n  // If true, root certificates on the system will not be loaded for\n  // verification.\n  bool disable_system_root = 7;\n}\n"
  },
  {
    "path": "transport/internet/xtls/config_other.go",
    "content": "// +build !windows\n// +build !confonly\n\npackage xtls\n\nimport (\n\t\"crypto/x509\"\n\t\"sync\"\n)\n\ntype rootCertsCache struct {\n\tsync.Mutex\n\tpool *x509.CertPool\n}\n\nfunc (c *rootCertsCache) load() (*x509.CertPool, error) {\n\tc.Lock()\n\tdefer c.Unlock()\n\n\tif c.pool != nil {\n\t\treturn c.pool, nil\n\t}\n\n\tpool, err := x509.SystemCertPool()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tc.pool = pool\n\treturn pool, nil\n}\n\nvar rootCerts rootCertsCache\n\nfunc (c *Config) getCertPool() (*x509.CertPool, error) {\n\tif c.DisableSystemRoot {\n\t\treturn c.loadSelfCertPool()\n\t}\n\n\tif len(c.Certificate) == 0 {\n\t\treturn rootCerts.load()\n\t}\n\n\tpool, err := x509.SystemCertPool()\n\tif err != nil {\n\t\treturn nil, newError(\"system root\").AtWarning().Base(err)\n\t}\n\tfor _, cert := range c.Certificate {\n\t\tif !pool.AppendCertsFromPEM(cert.Certificate) {\n\t\t\treturn nil, newError(\"append cert to root\").AtWarning().Base(err)\n\t\t}\n\t}\n\treturn pool, err\n}\n"
  },
  {
    "path": "transport/internet/xtls/config_test.go",
    "content": "package xtls_test\n\nimport (\n\t\"crypto/x509\"\n\t\"testing\"\n\t\"time\"\n\n\txtls \"github.com/xtls/go\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/protocol/tls/cert\"\n\t. \"v2ray.com/core/transport/internet/xtls\"\n)\n\nfunc TestCertificateIssuing(t *testing.T) {\n\tcertificate := ParseCertificate(cert.MustGenerate(nil, cert.Authority(true), cert.KeyUsage(x509.KeyUsageCertSign)))\n\tcertificate.Usage = Certificate_AUTHORITY_ISSUE\n\n\tc := &Config{\n\t\tCertificate: []*Certificate{\n\t\t\tcertificate,\n\t\t},\n\t}\n\n\txtlsConfig := c.GetXTLSConfig()\n\tv2rayCert, err := xtlsConfig.GetCertificate(&xtls.ClientHelloInfo{\n\t\tServerName: \"www.v2fly.org\",\n\t})\n\tcommon.Must(err)\n\n\tx509Cert, err := x509.ParseCertificate(v2rayCert.Certificate[0])\n\tcommon.Must(err)\n\tif !x509Cert.NotAfter.After(time.Now()) {\n\t\tt.Error(\"NotAfter: \", x509Cert.NotAfter)\n\t}\n}\n\nfunc TestExpiredCertificate(t *testing.T) {\n\tcaCert := cert.MustGenerate(nil, cert.Authority(true), cert.KeyUsage(x509.KeyUsageCertSign))\n\texpiredCert := cert.MustGenerate(caCert, cert.NotAfter(time.Now().Add(time.Minute*-2)), cert.CommonName(\"www.v2fly.org\"), cert.DNSNames(\"www.v2fly.org\"))\n\n\tcertificate := ParseCertificate(caCert)\n\tcertificate.Usage = Certificate_AUTHORITY_ISSUE\n\n\tcertificate2 := ParseCertificate(expiredCert)\n\n\tc := &Config{\n\t\tCertificate: []*Certificate{\n\t\t\tcertificate,\n\t\t\tcertificate2,\n\t\t},\n\t}\n\n\txtlsConfig := c.GetXTLSConfig()\n\tv2rayCert, err := xtlsConfig.GetCertificate(&xtls.ClientHelloInfo{\n\t\tServerName: \"www.v2fly.org\",\n\t})\n\tcommon.Must(err)\n\n\tx509Cert, err := x509.ParseCertificate(v2rayCert.Certificate[0])\n\tcommon.Must(err)\n\tif !x509Cert.NotAfter.After(time.Now()) {\n\t\tt.Error(\"NotAfter: \", x509Cert.NotAfter)\n\t}\n}\n\nfunc TestInsecureCertificates(t *testing.T) {\n\tc := &Config{\n\t\tAllowInsecureCiphers: true,\n\t}\n\n\txtlsConfig := c.GetXTLSConfig()\n\tif len(xtlsConfig.CipherSuites) > 0 {\n\t\tt.Fatal(\"Unexpected tls cipher suites list: \", xtlsConfig.CipherSuites)\n\t}\n}\n\nfunc BenchmarkCertificateIssuing(b *testing.B) {\n\tcertificate := ParseCertificate(cert.MustGenerate(nil, cert.Authority(true), cert.KeyUsage(x509.KeyUsageCertSign)))\n\tcertificate.Usage = Certificate_AUTHORITY_ISSUE\n\n\tc := &Config{\n\t\tCertificate: []*Certificate{\n\t\t\tcertificate,\n\t\t},\n\t}\n\n\txtlsConfig := c.GetXTLSConfig()\n\tlenCerts := len(xtlsConfig.Certificates)\n\n\tb.ResetTimer()\n\n\tfor i := 0; i < b.N; i++ {\n\t\t_, _ = xtlsConfig.GetCertificate(&xtls.ClientHelloInfo{\n\t\t\tServerName: \"www.v2fly.org\",\n\t\t})\n\t\tdelete(xtlsConfig.NameToCertificate, \"www.v2fly.org\")\n\t\txtlsConfig.Certificates = xtlsConfig.Certificates[:lenCerts]\n\t}\n}\n"
  },
  {
    "path": "transport/internet/xtls/config_windows.go",
    "content": "// +build windows\n// +build !confonly\n\npackage xtls\n\nimport \"crypto/x509\"\n\nfunc (c *Config) getCertPool() (*x509.CertPool, error) {\n\tif c.DisableSystemRoot {\n\t\treturn c.loadSelfCertPool()\n\t}\n\n\treturn nil, nil\n}\n"
  },
  {
    "path": "transport/internet/xtls/errors.generated.go",
    "content": "package xtls\n\nimport \"v2ray.com/core/common/errors\"\n\ntype errPathObjHolder struct{}\n\nfunc newError(values ...interface{}) *errors.Error {\n\treturn errors.New(values...).WithPathObj(errPathObjHolder{})\n}\n"
  },
  {
    "path": "transport/internet/xtls/xtls.go",
    "content": "// +build !confonly\n\npackage xtls\n\nimport (\n\txtls \"github.com/xtls/go\"\n\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/net\"\n)\n\n//go:generate go run v2ray.com/core/common/errors/errorgen\n\nvar (\n\t_ buf.Writer = (*Conn)(nil)\n)\n\ntype Conn struct {\n\t*xtls.Conn\n}\n\nfunc (c *Conn) WriteMultiBuffer(mb buf.MultiBuffer) error {\n\tmb = buf.Compact(mb)\n\tmb, err := buf.WriteMultiBuffer(c, mb)\n\tbuf.ReleaseMulti(mb)\n\treturn err\n}\n\nfunc (c *Conn) HandshakeAddress() net.Address {\n\tif err := c.Handshake(); err != nil {\n\t\treturn nil\n\t}\n\tstate := c.ConnectionState()\n\tif state.ServerName == \"\" {\n\t\treturn nil\n\t}\n\treturn net.ParseAddress(state.ServerName)\n}\n\n// Client initiates a XTLS client handshake on the given connection.\nfunc Client(c net.Conn, config *xtls.Config) net.Conn {\n\txtlsConn := xtls.Client(c, config)\n\treturn &Conn{Conn: xtlsConn}\n}\n\n// Server initiates a XTLS server handshake on the given connection.\nfunc Server(c net.Conn, config *xtls.Config) net.Conn {\n\txtlsConn := xtls.Server(c, config)\n\treturn &Conn{Conn: xtlsConn}\n}\n"
  },
  {
    "path": "transport/link.go",
    "content": "package transport\n\nimport \"v2ray.com/core/common/buf\"\n\n// Link is a utility for connecting between an inbound and an outbound proxy handler.\ntype Link struct {\n\tReader buf.Reader\n\tWriter buf.Writer\n}\n"
  },
  {
    "path": "transport/pipe/impl.go",
    "content": "package pipe\n\nimport (\n\t\"errors\"\n\t\"io\"\n\t\"runtime\"\n\t\"sync\"\n\t\"time\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t\"v2ray.com/core/common/signal\"\n\t\"v2ray.com/core/common/signal/done\"\n)\n\ntype state byte\n\nconst (\n\topen state = iota\n\tclosed\n\terrord\n)\n\ntype pipeOption struct {\n\tlimit           int32 // maximum buffer size in bytes\n\tdiscardOverflow bool\n}\n\nfunc (o *pipeOption) isFull(curSize int32) bool {\n\treturn o.limit >= 0 && curSize > o.limit\n}\n\ntype pipe struct {\n\tsync.Mutex\n\tdata        buf.MultiBuffer\n\treadSignal  *signal.Notifier\n\twriteSignal *signal.Notifier\n\tdone        *done.Instance\n\toption      pipeOption\n\tstate       state\n}\n\nvar errBufferFull = errors.New(\"buffer full\")\nvar errSlowDown = errors.New(\"slow down\")\n\nfunc (p *pipe) getState(forRead bool) error {\n\tswitch p.state {\n\tcase open:\n\t\tif !forRead && p.option.isFull(p.data.Len()) {\n\t\t\treturn errBufferFull\n\t\t}\n\t\treturn nil\n\tcase closed:\n\t\tif !forRead {\n\t\t\treturn io.ErrClosedPipe\n\t\t}\n\t\tif !p.data.IsEmpty() {\n\t\t\treturn nil\n\t\t}\n\t\treturn io.EOF\n\tcase errord:\n\t\treturn io.ErrClosedPipe\n\tdefault:\n\t\tpanic(\"impossible case\")\n\t}\n}\n\nfunc (p *pipe) readMultiBufferInternal() (buf.MultiBuffer, error) {\n\tp.Lock()\n\tdefer p.Unlock()\n\n\tif err := p.getState(true); err != nil {\n\t\treturn nil, err\n\t}\n\n\tdata := p.data\n\tp.data = nil\n\treturn data, nil\n}\n\nfunc (p *pipe) ReadMultiBuffer() (buf.MultiBuffer, error) {\n\tfor {\n\t\tdata, err := p.readMultiBufferInternal()\n\t\tif data != nil || err != nil {\n\t\t\tp.writeSignal.Signal()\n\t\t\treturn data, err\n\t\t}\n\n\t\tselect {\n\t\tcase <-p.readSignal.Wait():\n\t\tcase <-p.done.Wait():\n\t\t}\n\t}\n}\n\nfunc (p *pipe) ReadMultiBufferTimeout(d time.Duration) (buf.MultiBuffer, error) {\n\ttimer := time.NewTimer(d)\n\tdefer timer.Stop()\n\n\tfor {\n\t\tdata, err := p.readMultiBufferInternal()\n\t\tif data != nil || err != nil {\n\t\t\tp.writeSignal.Signal()\n\t\t\treturn data, err\n\t\t}\n\n\t\tselect {\n\t\tcase <-p.readSignal.Wait():\n\t\tcase <-p.done.Wait():\n\t\tcase <-timer.C:\n\t\t\treturn nil, buf.ErrReadTimeout\n\t\t}\n\t}\n}\n\nfunc (p *pipe) writeMultiBufferInternal(mb buf.MultiBuffer) error {\n\tp.Lock()\n\tdefer p.Unlock()\n\n\tif err := p.getState(false); err != nil {\n\t\treturn err\n\t}\n\n\tif p.data == nil {\n\t\tp.data = mb\n\t\treturn nil\n\t}\n\n\tp.data, _ = buf.MergeMulti(p.data, mb)\n\treturn errSlowDown\n}\n\nfunc (p *pipe) WriteMultiBuffer(mb buf.MultiBuffer) error {\n\tif mb.IsEmpty() {\n\t\treturn nil\n\t}\n\n\tfor {\n\t\terr := p.writeMultiBufferInternal(mb)\n\t\tif err == nil {\n\t\t\tp.readSignal.Signal()\n\t\t\treturn nil\n\t\t}\n\n\t\tif err == errSlowDown {\n\t\t\tp.readSignal.Signal()\n\n\t\t\t// Yield current goroutine. Hopefully the reading counterpart can pick up the payload.\n\t\t\truntime.Gosched()\n\t\t\treturn nil\n\t\t}\n\n\t\tif err == errBufferFull && p.option.discardOverflow {\n\t\t\tbuf.ReleaseMulti(mb)\n\t\t\treturn nil\n\t\t}\n\n\t\tif err != errBufferFull {\n\t\t\tbuf.ReleaseMulti(mb)\n\t\t\tp.readSignal.Signal()\n\t\t\treturn err\n\t\t}\n\n\t\tselect {\n\t\tcase <-p.writeSignal.Wait():\n\t\tcase <-p.done.Wait():\n\t\t\treturn io.ErrClosedPipe\n\t\t}\n\t}\n}\n\nfunc (p *pipe) Close() error {\n\tp.Lock()\n\tdefer p.Unlock()\n\n\tif p.state == closed || p.state == errord {\n\t\treturn nil\n\t}\n\n\tp.state = closed\n\tcommon.Must(p.done.Close())\n\treturn nil\n}\n\n// Interrupt implements common.Interruptible.\nfunc (p *pipe) Interrupt() {\n\tp.Lock()\n\tdefer p.Unlock()\n\n\tif p.state == closed || p.state == errord {\n\t\treturn\n\t}\n\n\tp.state = errord\n\n\tif !p.data.IsEmpty() {\n\t\tbuf.ReleaseMulti(p.data)\n\t\tp.data = nil\n\t}\n\n\tcommon.Must(p.done.Close())\n}\n"
  },
  {
    "path": "transport/pipe/pipe.go",
    "content": "package pipe\n\nimport (\n\t\"context\"\n\n\t\"v2ray.com/core/common/signal\"\n\t\"v2ray.com/core/common/signal/done\"\n\t\"v2ray.com/core/features/policy\"\n)\n\n// Option for creating new Pipes.\ntype Option func(*pipeOption)\n\n// WithoutSizeLimit returns an Option for Pipe to have no size limit.\nfunc WithoutSizeLimit() Option {\n\treturn func(opt *pipeOption) {\n\t\topt.limit = -1\n\t}\n}\n\n// WithSizeLimit returns an Option for Pipe to have the given size limit.\nfunc WithSizeLimit(limit int32) Option {\n\treturn func(opt *pipeOption) {\n\t\topt.limit = limit\n\t}\n}\n\n// DiscardOverflow returns an Option for Pipe to discard writes if full.\nfunc DiscardOverflow() Option {\n\treturn func(opt *pipeOption) {\n\t\topt.discardOverflow = true\n\t}\n}\n\n// OptionsFromContext returns a list of Options from context.\nfunc OptionsFromContext(ctx context.Context) []Option {\n\tvar opt []Option\n\n\tbp := policy.BufferPolicyFromContext(ctx)\n\tif bp.PerConnection >= 0 {\n\t\topt = append(opt, WithSizeLimit(bp.PerConnection))\n\t} else {\n\t\topt = append(opt, WithoutSizeLimit())\n\t}\n\n\treturn opt\n}\n\n// New creates a new Reader and Writer that connects to each other.\nfunc New(opts ...Option) (*Reader, *Writer) {\n\tp := &pipe{\n\t\treadSignal:  signal.NewNotifier(),\n\t\twriteSignal: signal.NewNotifier(),\n\t\tdone:        done.New(),\n\t\toption: pipeOption{\n\t\t\tlimit: -1,\n\t\t},\n\t}\n\n\tfor _, opt := range opts {\n\t\topt(&(p.option))\n\t}\n\n\treturn &Reader{\n\t\t\tpipe: p,\n\t\t}, &Writer{\n\t\t\tpipe: p,\n\t\t}\n}\n"
  },
  {
    "path": "transport/pipe/pipe_test.go",
    "content": "package pipe_test\n\nimport (\n\t\"errors\"\n\t\"io\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"golang.org/x/sync/errgroup\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/buf\"\n\t. \"v2ray.com/core/transport/pipe\"\n)\n\nfunc TestPipeReadWrite(t *testing.T) {\n\tpReader, pWriter := New(WithSizeLimit(1024))\n\n\tb := buf.New()\n\tb.WriteString(\"abcd\")\n\tcommon.Must(pWriter.WriteMultiBuffer(buf.MultiBuffer{b}))\n\n\tb2 := buf.New()\n\tb2.WriteString(\"efg\")\n\tcommon.Must(pWriter.WriteMultiBuffer(buf.MultiBuffer{b2}))\n\n\trb, err := pReader.ReadMultiBuffer()\n\tcommon.Must(err)\n\tif r := cmp.Diff(rb.String(), \"abcdefg\"); r != \"\" {\n\t\tt.Error(r)\n\t}\n}\n\nfunc TestPipeInterrupt(t *testing.T) {\n\tpReader, pWriter := New(WithSizeLimit(1024))\n\tpayload := []byte{'a', 'b', 'c', 'd'}\n\tb := buf.New()\n\tb.Write(payload)\n\tcommon.Must(pWriter.WriteMultiBuffer(buf.MultiBuffer{b}))\n\tpWriter.Interrupt()\n\n\trb, err := pReader.ReadMultiBuffer()\n\tif err != io.ErrClosedPipe {\n\t\tt.Fatal(\"expect io.ErrClosePipe, but got \", err)\n\t}\n\tif !rb.IsEmpty() {\n\t\tt.Fatal(\"expect empty buffer, but got \", rb.Len())\n\t}\n}\n\nfunc TestPipeClose(t *testing.T) {\n\tpReader, pWriter := New(WithSizeLimit(1024))\n\tpayload := []byte{'a', 'b', 'c', 'd'}\n\tb := buf.New()\n\tcommon.Must2(b.Write(payload))\n\tcommon.Must(pWriter.WriteMultiBuffer(buf.MultiBuffer{b}))\n\tcommon.Must(pWriter.Close())\n\n\trb, err := pReader.ReadMultiBuffer()\n\tcommon.Must(err)\n\tif rb.String() != string(payload) {\n\t\tt.Fatal(\"expect content \", string(payload), \" but actually \", rb.String())\n\t}\n\n\trb, err = pReader.ReadMultiBuffer()\n\tif err != io.EOF {\n\t\tt.Fatal(\"expected EOF, but got \", err)\n\t}\n\tif !rb.IsEmpty() {\n\t\tt.Fatal(\"expect empty buffer, but got \", rb.String())\n\t}\n}\n\nfunc TestPipeLimitZero(t *testing.T) {\n\tpReader, pWriter := New(WithSizeLimit(0))\n\tbb := buf.New()\n\tcommon.Must2(bb.Write([]byte{'a', 'b'}))\n\tcommon.Must(pWriter.WriteMultiBuffer(buf.MultiBuffer{bb}))\n\n\tvar errg errgroup.Group\n\terrg.Go(func() error {\n\t\tb := buf.New()\n\t\tb.Write([]byte{'c', 'd'})\n\t\treturn pWriter.WriteMultiBuffer(buf.MultiBuffer{b})\n\t})\n\terrg.Go(func() error {\n\t\ttime.Sleep(time.Second)\n\n\t\tvar container buf.MultiBufferContainer\n\t\tif err := buf.Copy(pReader, &container); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif r := cmp.Diff(container.String(), \"abcd\"); r != \"\" {\n\t\t\treturn errors.New(r)\n\t\t}\n\t\treturn nil\n\t})\n\terrg.Go(func() error {\n\t\ttime.Sleep(time.Second * 2)\n\t\treturn pWriter.Close()\n\t})\n\tif err := errg.Wait(); err != nil {\n\t\tt.Error(err)\n\t}\n}\n\nfunc TestPipeWriteMultiThread(t *testing.T) {\n\tpReader, pWriter := New(WithSizeLimit(0))\n\n\tvar errg errgroup.Group\n\tfor i := 0; i < 10; i++ {\n\t\terrg.Go(func() error {\n\t\t\tb := buf.New()\n\t\t\tb.WriteString(\"abcd\")\n\t\t\treturn pWriter.WriteMultiBuffer(buf.MultiBuffer{b})\n\t\t})\n\t}\n\ttime.Sleep(time.Millisecond * 100)\n\tpWriter.Close()\n\terrg.Wait()\n\n\tb, err := pReader.ReadMultiBuffer()\n\tcommon.Must(err)\n\tif r := cmp.Diff(b[0].Bytes(), []byte{'a', 'b', 'c', 'd'}); r != \"\" {\n\t\tt.Error(r)\n\t}\n}\n\nfunc TestInterfaces(t *testing.T) {\n\t_ = (buf.Reader)(new(Reader))\n\t_ = (buf.TimeoutReader)(new(Reader))\n\n\t_ = (common.Interruptible)(new(Reader))\n\t_ = (common.Interruptible)(new(Writer))\n\t_ = (common.Closable)(new(Writer))\n}\n\nfunc BenchmarkPipeReadWrite(b *testing.B) {\n\treader, writer := New(WithoutSizeLimit())\n\ta := buf.New()\n\ta.Extend(buf.Size)\n\tc := buf.MultiBuffer{a}\n\n\tb.ResetTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\tcommon.Must(writer.WriteMultiBuffer(c))\n\t\td, err := reader.ReadMultiBuffer()\n\t\tcommon.Must(err)\n\t\tc = d\n\t}\n}\n"
  },
  {
    "path": "transport/pipe/reader.go",
    "content": "package pipe\n\nimport (\n\t\"time\"\n\n\t\"v2ray.com/core/common/buf\"\n)\n\n// Reader is a buf.Reader that reads content from a pipe.\ntype Reader struct {\n\tpipe *pipe\n}\n\n// ReadMultiBuffer implements buf.Reader.\nfunc (r *Reader) ReadMultiBuffer() (buf.MultiBuffer, error) {\n\treturn r.pipe.ReadMultiBuffer()\n}\n\n// ReadMultiBufferTimeout reads content from a pipe within the given duration, or returns buf.ErrTimeout otherwise.\nfunc (r *Reader) ReadMultiBufferTimeout(d time.Duration) (buf.MultiBuffer, error) {\n\treturn r.pipe.ReadMultiBufferTimeout(d)\n}\n\n// Interrupt implements common.Interruptible.\nfunc (r *Reader) Interrupt() {\n\tr.pipe.Interrupt()\n}\n"
  },
  {
    "path": "transport/pipe/writer.go",
    "content": "package pipe\n\nimport (\n\t\"v2ray.com/core/common/buf\"\n)\n\n// Writer is a buf.Writer that writes data into a pipe.\ntype Writer struct {\n\tpipe *pipe\n}\n\n// WriteMultiBuffer implements buf.Writer.\nfunc (w *Writer) WriteMultiBuffer(mb buf.MultiBuffer) error {\n\treturn w.pipe.WriteMultiBuffer(mb)\n}\n\n// Close implements io.Closer. After the pipe is closed, writing to the pipe will return io.ErrClosedPipe, while reading will return io.EOF.\nfunc (w *Writer) Close() error {\n\treturn w.pipe.Close()\n}\n\n// Interrupt implements common.Interruptible.\nfunc (w *Writer) Interrupt() {\n\tw.pipe.Interrupt()\n}\n"
  },
  {
    "path": "v2ray.go",
    "content": "// +build !confonly\n\npackage core\n\nimport (\n\t\"context\"\n\t\"reflect\"\n\t\"sync\"\n\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/serial\"\n\t\"v2ray.com/core/features\"\n\t\"v2ray.com/core/features/dns\"\n\t\"v2ray.com/core/features/dns/localdns\"\n\t\"v2ray.com/core/features/inbound\"\n\t\"v2ray.com/core/features/outbound\"\n\t\"v2ray.com/core/features/policy\"\n\t\"v2ray.com/core/features/routing\"\n\t\"v2ray.com/core/features/stats\"\n)\n\n// Server is an instance of V2Ray. At any time, there must be at most one Server instance running.\ntype Server interface {\n\tcommon.Runnable\n}\n\n// ServerType returns the type of the server.\nfunc ServerType() interface{} {\n\treturn (*Instance)(nil)\n}\n\ntype resolution struct {\n\tdeps     []reflect.Type\n\tcallback interface{}\n}\n\nfunc getFeature(allFeatures []features.Feature, t reflect.Type) features.Feature {\n\tfor _, f := range allFeatures {\n\t\tif reflect.TypeOf(f.Type()) == t {\n\t\t\treturn f\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (r *resolution) resolve(allFeatures []features.Feature) (bool, error) {\n\tvar fs []features.Feature\n\tfor _, d := range r.deps {\n\t\tf := getFeature(allFeatures, d)\n\t\tif f == nil {\n\t\t\treturn false, nil\n\t\t}\n\t\tfs = append(fs, f)\n\t}\n\n\tcallback := reflect.ValueOf(r.callback)\n\tvar input []reflect.Value\n\tcallbackType := callback.Type()\n\tfor i := 0; i < callbackType.NumIn(); i++ {\n\t\tpt := callbackType.In(i)\n\t\tfor _, f := range fs {\n\t\t\tif reflect.TypeOf(f).AssignableTo(pt) {\n\t\t\t\tinput = append(input, reflect.ValueOf(f))\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\tif len(input) != callbackType.NumIn() {\n\t\tpanic(\"Can't get all input parameters\")\n\t}\n\n\tvar err error\n\tret := callback.Call(input)\n\terrInterface := reflect.TypeOf((*error)(nil)).Elem()\n\tfor i := len(ret) - 1; i >= 0; i-- {\n\t\tif ret[i].Type() == errInterface {\n\t\t\tv := ret[i].Interface()\n\t\t\tif v != nil {\n\t\t\t\terr = v.(error)\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn true, err\n}\n\n// Instance combines all functionalities in V2Ray.\ntype Instance struct {\n\taccess             sync.Mutex\n\tfeatures           []features.Feature\n\tfeatureResolutions []resolution\n\trunning            bool\n\n\tctx context.Context\n}\n\nfunc AddInboundHandler(server *Instance, config *InboundHandlerConfig) error {\n\tinboundManager := server.GetFeature(inbound.ManagerType()).(inbound.Manager)\n\trawHandler, err := CreateObject(server, config)\n\tif err != nil {\n\t\treturn err\n\t}\n\thandler, ok := rawHandler.(inbound.Handler)\n\tif !ok {\n\t\treturn newError(\"not an InboundHandler\")\n\t}\n\tif err := inboundManager.AddHandler(server.ctx, handler); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc addInboundHandlers(server *Instance, configs []*InboundHandlerConfig) error {\n\tfor _, inboundConfig := range configs {\n\t\tif err := AddInboundHandler(server, inboundConfig); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc AddOutboundHandler(server *Instance, config *OutboundHandlerConfig) error {\n\toutboundManager := server.GetFeature(outbound.ManagerType()).(outbound.Manager)\n\trawHandler, err := CreateObject(server, config)\n\tif err != nil {\n\t\treturn err\n\t}\n\thandler, ok := rawHandler.(outbound.Handler)\n\tif !ok {\n\t\treturn newError(\"not an OutboundHandler\")\n\t}\n\tif err := outboundManager.AddHandler(server.ctx, handler); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc addOutboundHandlers(server *Instance, configs []*OutboundHandlerConfig) error {\n\tfor _, outboundConfig := range configs {\n\t\tif err := AddOutboundHandler(server, outboundConfig); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// RequireFeatures is a helper function to require features from Instance in context.\n// See Instance.RequireFeatures for more information.\nfunc RequireFeatures(ctx context.Context, callback interface{}) error {\n\tv := MustFromContext(ctx)\n\treturn v.RequireFeatures(callback)\n}\n\n// New returns a new V2Ray instance based on given configuration.\n// The instance is not started at this point.\n// To ensure V2Ray instance works properly, the config must contain one Dispatcher, one InboundHandlerManager and one OutboundHandlerManager. Other features are optional.\nfunc New(config *Config) (*Instance, error) {\n\tvar server = &Instance{ctx: context.Background()}\n\n\terr, done := initInstanceWithConfig(config, server)\n\tif done {\n\t\treturn nil, err\n\t}\n\n\treturn server, nil\n}\n\nfunc NewWithContext(config *Config, ctx context.Context) (*Instance, error) {\n\tvar server = &Instance{ctx: ctx}\n\n\terr, done := initInstanceWithConfig(config, server)\n\tif done {\n\t\treturn nil, err\n\t}\n\n\treturn server, nil\n}\n\nfunc initInstanceWithConfig(config *Config, server *Instance) (error, bool) {\n\tif config.Transport != nil {\n\t\tfeatures.PrintDeprecatedFeatureWarning(\"global transport settings\")\n\t}\n\tif err := config.Transport.Apply(); err != nil {\n\t\treturn err, true\n\t}\n\n\tfor _, appSettings := range config.App {\n\t\tsettings, err := appSettings.GetInstance()\n\t\tif err != nil {\n\t\t\treturn err, true\n\t\t}\n\t\tobj, err := CreateObject(server, settings)\n\t\tif err != nil {\n\t\t\treturn err, true\n\t\t}\n\t\tif feature, ok := obj.(features.Feature); ok {\n\t\t\tif err := server.AddFeature(feature); err != nil {\n\t\t\t\treturn err, true\n\t\t\t}\n\t\t}\n\t}\n\n\tessentialFeatures := []struct {\n\t\tType     interface{}\n\t\tInstance features.Feature\n\t}{\n\t\t{dns.ClientType(), localdns.New()},\n\t\t{policy.ManagerType(), policy.DefaultManager{}},\n\t\t{routing.RouterType(), routing.DefaultRouter{}},\n\t\t{stats.ManagerType(), stats.NoopManager{}},\n\t}\n\n\tfor _, f := range essentialFeatures {\n\t\tif server.GetFeature(f.Type) == nil {\n\t\t\tif err := server.AddFeature(f.Instance); err != nil {\n\t\t\t\treturn err, true\n\t\t\t}\n\t\t}\n\t}\n\n\tif server.featureResolutions != nil {\n\t\treturn newError(\"not all dependency are resolved.\"), true\n\t}\n\n\tif err := addInboundHandlers(server, config.Inbound); err != nil {\n\t\treturn err, true\n\t}\n\n\tif err := addOutboundHandlers(server, config.Outbound); err != nil {\n\t\treturn err, true\n\t}\n\treturn nil, false\n}\n\n// Type implements common.HasType.\nfunc (s *Instance) Type() interface{} {\n\treturn ServerType()\n}\n\n// Close shutdown the V2Ray instance.\nfunc (s *Instance) Close() error {\n\ts.access.Lock()\n\tdefer s.access.Unlock()\n\n\ts.running = false\n\n\tvar errors []interface{}\n\tfor _, f := range s.features {\n\t\tif err := f.Close(); err != nil {\n\t\t\terrors = append(errors, err)\n\t\t}\n\t}\n\tif len(errors) > 0 {\n\t\treturn newError(\"failed to close all features\").Base(newError(serial.Concat(errors...)))\n\t}\n\n\treturn nil\n}\n\n// RequireFeatures registers a callback, which will be called when all dependent features are registered.\n// The callback must be a func(). All its parameters must be features.Feature.\nfunc (s *Instance) RequireFeatures(callback interface{}) error {\n\tcallbackType := reflect.TypeOf(callback)\n\tif callbackType.Kind() != reflect.Func {\n\t\tpanic(\"not a function\")\n\t}\n\n\tvar featureTypes []reflect.Type\n\tfor i := 0; i < callbackType.NumIn(); i++ {\n\t\tfeatureTypes = append(featureTypes, reflect.PtrTo(callbackType.In(i)))\n\t}\n\n\tr := resolution{\n\t\tdeps:     featureTypes,\n\t\tcallback: callback,\n\t}\n\tif finished, err := r.resolve(s.features); finished {\n\t\treturn err\n\t}\n\ts.featureResolutions = append(s.featureResolutions, r)\n\treturn nil\n}\n\n// AddFeature registers a feature into current Instance.\nfunc (s *Instance) AddFeature(feature features.Feature) error {\n\ts.features = append(s.features, feature)\n\n\tif s.running {\n\t\tif err := feature.Start(); err != nil {\n\t\t\tnewError(\"failed to start feature\").Base(err).WriteToLog()\n\t\t}\n\t\treturn nil\n\t}\n\n\tif s.featureResolutions == nil {\n\t\treturn nil\n\t}\n\n\tvar pendingResolutions []resolution\n\tfor _, r := range s.featureResolutions {\n\t\tfinished, err := r.resolve(s.features)\n\t\tif finished && err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif !finished {\n\t\t\tpendingResolutions = append(pendingResolutions, r)\n\t\t}\n\t}\n\tif len(pendingResolutions) == 0 {\n\t\ts.featureResolutions = nil\n\t} else if len(pendingResolutions) < len(s.featureResolutions) {\n\t\ts.featureResolutions = pendingResolutions\n\t}\n\n\treturn nil\n}\n\n// GetFeature returns a feature of the given type, or nil if such feature is not registered.\nfunc (s *Instance) GetFeature(featureType interface{}) features.Feature {\n\treturn getFeature(s.features, reflect.TypeOf(featureType))\n}\n\n// Start starts the V2Ray instance, including all registered features. When Start returns error, the state of the instance is unknown.\n// A V2Ray instance can be started only once. Upon closing, the instance is not guaranteed to start again.\n//\n// v2ray:api:stable\nfunc (s *Instance) Start() error {\n\ts.access.Lock()\n\tdefer s.access.Unlock()\n\n\ts.running = true\n\tfor _, f := range s.features {\n\t\tif err := f.Start(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tnewError(\"V2Ray \", Version(), \" started\").AtWarning().WriteToLog()\n\n\treturn nil\n}\n"
  },
  {
    "path": "v2ray_test.go",
    "content": "package core_test\n\nimport (\n\t\"testing\"\n\n\tproto \"github.com/golang/protobuf/proto\"\n\t. \"v2ray.com/core\"\n\t\"v2ray.com/core/app/dispatcher\"\n\t\"v2ray.com/core/app/proxyman\"\n\t\"v2ray.com/core/common\"\n\t\"v2ray.com/core/common/net\"\n\t\"v2ray.com/core/common/protocol\"\n\t\"v2ray.com/core/common/serial\"\n\t\"v2ray.com/core/common/uuid\"\n\t\"v2ray.com/core/features/dns\"\n\t\"v2ray.com/core/features/dns/localdns\"\n\t_ \"v2ray.com/core/main/distro/all\"\n\t\"v2ray.com/core/proxy/dokodemo\"\n\t\"v2ray.com/core/proxy/vmess\"\n\t\"v2ray.com/core/proxy/vmess/outbound\"\n\t\"v2ray.com/core/testing/servers/tcp\"\n)\n\nfunc TestV2RayDependency(t *testing.T) {\n\tinstance := new(Instance)\n\n\twait := make(chan bool, 1)\n\tinstance.RequireFeatures(func(d dns.Client) {\n\t\tif d == nil {\n\t\t\tt.Error(\"expected dns client fulfilled, but actually nil\")\n\t\t}\n\t\twait <- true\n\t})\n\tinstance.AddFeature(localdns.New())\n\t<-wait\n}\n\nfunc TestV2RayClose(t *testing.T) {\n\tport := tcp.PickPort()\n\n\tuserId := uuid.New()\n\tconfig := &Config{\n\t\tApp: []*serial.TypedMessage{\n\t\t\tserial.ToTypedMessage(&dispatcher.Config{}),\n\t\t\tserial.ToTypedMessage(&proxyman.InboundConfig{}),\n\t\t\tserial.ToTypedMessage(&proxyman.OutboundConfig{}),\n\t\t},\n\t\tInbound: []*InboundHandlerConfig{\n\t\t\t{\n\t\t\t\tReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{\n\t\t\t\t\tPortRange: net.SinglePortRange(port),\n\t\t\t\t\tListen:    net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t}),\n\t\t\t\tProxySettings: serial.ToTypedMessage(&dokodemo.Config{\n\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\tPort:    uint32(0),\n\t\t\t\t\tNetworkList: &net.NetworkList{\n\t\t\t\t\t\tNetwork: []net.Network{net.Network_TCP, net.Network_UDP},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tOutbound: []*OutboundHandlerConfig{\n\t\t\t{\n\t\t\t\tProxySettings: serial.ToTypedMessage(&outbound.Config{\n\t\t\t\t\tReceiver: []*protocol.ServerEndpoint{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: net.NewIPOrDomain(net.LocalHostIP),\n\t\t\t\t\t\t\tPort:    uint32(0),\n\t\t\t\t\t\t\tUser: []*protocol.User{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAccount: serial.ToTypedMessage(&vmess.Account{\n\t\t\t\t\t\t\t\t\t\tId: userId.String(),\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t},\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},\n\t}\n\n\tcfgBytes, err := proto.Marshal(config)\n\tcommon.Must(err)\n\n\tserver, err := StartInstance(\"protobuf\", cfgBytes)\n\tcommon.Must(err)\n\tserver.Close()\n}\n"
  }
]