Showing preview only (747K chars total). Download the full file or copy to clipboard to get everything.
Repository: ehang-io/nps
Branch: master
Commit: ab648d6f0c61
Files: 129
Total size: 710.5 KB
Directory structure:
gitextract_d7ijj7nu/
├── .gitattributes
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ └── feature_request.md
│ └── workflows/
│ └── release.yml
├── .gitignore
├── .travis.yml
├── Dockerfile.npc
├── Dockerfile.nps
├── LICENSE
├── Makefile
├── README.md
├── README_zh.md
├── bridge/
│ └── bridge.go
├── build.android.sh
├── build.assets.sh
├── build.sh
├── client/
│ ├── client.go
│ ├── control.go
│ ├── health.go
│ ├── local.go
│ └── register.go
├── conf/
│ ├── clients.json
│ ├── hosts.json
│ ├── multi_account.conf
│ ├── npc.conf
│ ├── nps.conf
│ ├── server.key
│ ├── server.pem
│ └── tasks.json
├── docs/
│ ├── .nojekyll
│ ├── README.md
│ ├── _coverpage.md
│ ├── _navbar.md
│ ├── _sidebar.md
│ ├── api.md
│ ├── contribute.md
│ ├── description.md
│ ├── discuss.md
│ ├── donate.md
│ ├── example.md
│ ├── faq.md
│ ├── feature.md
│ ├── index.html
│ ├── install.md
│ ├── introduction.md
│ ├── npc_extend.md
│ ├── npc_sdk.md
│ ├── nps_extend.md
│ ├── nps_use.md
│ ├── run.md
│ ├── server_config.md
│ ├── thanks.md
│ ├── use.md
│ └── webapi.md
├── go.mod
├── go.sum
├── lib/
│ ├── cache/
│ │ └── lru.go
│ ├── common/
│ │ ├── const.go
│ │ ├── logs.go
│ │ ├── netpackager.go
│ │ ├── pool.go
│ │ ├── pprof.go
│ │ ├── run.go
│ │ └── util.go
│ ├── config/
│ │ ├── config.go
│ │ └── config_test.go
│ ├── conn/
│ │ ├── conn.go
│ │ ├── link.go
│ │ ├── listener.go
│ │ └── snappy.go
│ ├── crypt/
│ │ ├── clientHello.go
│ │ ├── crypt.go
│ │ └── tls.go
│ ├── daemon/
│ │ ├── daemon.go
│ │ └── reload.go
│ ├── file/
│ │ ├── db.go
│ │ ├── file.go
│ │ ├── obj.go
│ │ └── sort.go
│ ├── goroutine/
│ │ └── pool.go
│ ├── install/
│ │ └── install.go
│ ├── pmux/
│ │ ├── pconn.go
│ │ ├── plistener.go
│ │ ├── pmux.go
│ │ └── pmux_test.go
│ ├── rate/
│ │ ├── conn.go
│ │ └── rate.go
│ ├── sheap/
│ │ └── heap.go
│ └── version/
│ └── version.go
├── server/
│ ├── connection/
│ │ └── connection.go
│ ├── proxy/
│ │ ├── base.go
│ │ ├── http.go
│ │ ├── https.go
│ │ ├── p2p.go
│ │ ├── socks5.go
│ │ ├── tcp.go
│ │ ├── transport.go
│ │ ├── transport_windows.go
│ │ └── udp.go
│ ├── server.go
│ ├── test/
│ │ └── test.go
│ └── tool/
│ └── utils.go
└── web/
├── controllers/
│ ├── auth.go
│ ├── base.go
│ ├── client.go
│ ├── index.go
│ └── login.go
├── routers/
│ └── router.go
├── static/
│ ├── css/
│ │ ├── datatables.css
│ │ └── style.css
│ ├── js/
│ │ ├── inspinia.js
│ │ └── language.js
│ └── page/
│ ├── error.html
│ └── languages.xml
└── views/
├── client/
│ ├── add.html
│ ├── edit.html
│ └── list.html
├── index/
│ ├── add.html
│ ├── edit.html
│ ├── hadd.html
│ ├── hedit.html
│ ├── help.html
│ ├── hlist.html
│ ├── index.html
│ └── list.html
├── login/
│ ├── index.html
│ └── register.html
└── public/
├── error.html
└── layout.html
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
*.js linguist-language=golang
*.css linguist-language=golang
*.html linguist-language=golang
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Opening '...'
2. Click on '....'
3. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots or logs**
Add screenshots or logs to help explain your problem.
**Server (please complete the following information):**
- OS: [e.g. Centos, Windows]
- ARCH: [e.g. Amd64, Arm]
- Tunnel [e.g. TCP, HTTP]
- Version [e.g. 0.24.0]
**Client (please complete the following information):**
- OS: [e.g. Centos, Windows]
- ARCH: [e.g. Amd64, Arm]
- Tunnel [e.g. TCP, HTTP]
- Version [e.g. 0.24.0]
**Additional context**
Add any other context about the problem here.
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
================================================
FILE: .github/workflows/release.yml
================================================
name: Release
on:
release:
types: [published]
branches: [ master ]
jobs:
build_assets:
runs-on: ubuntu-latest
steps:
- name: Set up Go 1.x
uses: actions/setup-go@v2
with:
go-version: 1.15
id: go
- name: Check out code into the Go module directory
uses: actions/checkout@v2
- name: Get dependencies
run: |
go get -v -t -d ./...
if [ -f Gopkg.toml ]; then
curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
dep ensure
fi
- name: Build
run: |
chmod +x build.assets.sh
./build.assets.sh
- name: Upload
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
with:
files: |
freebsd_386_client.tar.gz
freebsd_386_server.tar.gz
freebsd_amd64_client.tar.gz
freebsd_amd64_server.tar.gz
freebsd_arm_client.tar.gz
freebsd_arm_server.tar.gz
linux_386_client.tar.gz
linux_386_server.tar.gz
linux_amd64_client.tar.gz
linux_amd64_server.tar.gz
linux_arm64_client.tar.gz
linux_arm64_server.tar.gz
linux_arm_v5_client.tar.gz
linux_arm_v6_client.tar.gz
linux_arm_v7_client.tar.gz
linux_arm_v5_server.tar.gz
linux_arm_v6_server.tar.gz
linux_arm_v7_server.tar.gz
linux_mips64le_client.tar.gz
linux_mips64le_server.tar.gz
linux_mips64_client.tar.gz
linux_mips64_server.tar.gz
linux_mipsle_client.tar.gz
linux_mipsle_server.tar.gz
linux_mips_client.tar.gz
linux_mips_server.tar.gz
darwin_amd64_client.tar.gz
darwin_amd64_server.tar.gz
windows_386_client.tar.gz
windows_386_server.tar.gz
windows_amd64_client.tar.gz
windows_amd64_server.tar.gz
npc_sdk.tar.gz
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
build_android:
runs-on: ubuntu-latest
steps:
- name: Check out code into the Go module directory
uses: actions/checkout@v2
- name: Build
run: |
chmod +x build.android.sh
docker run --rm -i -w /app -v $(pwd):/app -e ANDROID_HOME=/usr/local/android_sdk -e GOPROXY=direct fyneio/fyne-cross:android-latest /app/build.android.sh
- name: Upload
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
with:
files: |
android_client.apk
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
build_spk:
runs-on: ubuntu-latest
steps:
- name: Check out code into the Go module directory
uses: actions/checkout@v2
- name: Set env
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
- name: Build
run: |
git clone https://github.com/cnlh/spksrc.git ~/spksrc
mkdir ~/spksrc/nps && cp -rf ./* ~/spksrc/nps/
docker run -id --name spksrc --env VERSION=${{ env.RELEASE_VERSION }} -e GOPROXY=direct -v ~/spksrc:/spksrc synocommunity/spksrc /bin/bash
docker exec spksrc /bin/bash -c 'cd /spksrc && make setup && cd /spksrc/spk/npc && make'
cp ~/spksrc/packages/npc_noarch-all_${{ env.RELEASE_VERSION }}-1.spk ./npc_syno.spk
- name: Upload
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
with:
files: |
npc_syno.spk
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
build_docker:
runs-on: ubuntu-latest
steps:
- name: Check out code into the Go module directory
uses: actions/checkout@v2
- name: Set env
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Cache Docker layers
uses: actions/cache@v2
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-
- name: Login to DockerHub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push nps
uses: docker/build-push-action@v2
with:
context: .
file: ./Dockerfile.nps
platforms: linux/amd64,linux/arm,linux/arm64
push: true
tags: |
${{ secrets.DOCKERHUB_USERNAME }}/nps:latest
${{ secrets.DOCKERHUB_USERNAME }}/nps:${{ env.RELEASE_VERSION }}
- name: Build and push npc
uses: docker/build-push-action@v2
with:
context: .
file: ./Dockerfile.npc
platforms: linux/amd64,linux/arm,linux/arm64
push: true
tags: |
${{ secrets.DOCKERHUB_USERNAME }}/npc:latest
${{ secrets.DOCKERHUB_USERNAME }}/npc:${{ env.RELEASE_VERSION }}
================================================
FILE: .gitignore
================================================
.idea
nps
npc
================================================
FILE: .travis.yml
================================================
language: go
go:
- 1.14.x
services:
- docker
script:
- GOPROXY=direct go test -v ./cmd/nps/
os:
- linux
before_deploy:
- chmod +x ./build.sh && chmod +x ./build.android.sh && ./build.sh
deploy:
provider: releases
edge: true
token: ${GH_TOKEN}
cleanup: false
file:
- freebsd_386_client.tar.gz
- freebsd_386_server.tar.gz
- freebsd_amd64_client.tar.gz
- freebsd_amd64_server.tar.gz
- freebsd_arm_client.tar.gz
- freebsd_arm_server.tar.gz
- linux_386_client.tar.gz
- linux_386_server.tar.gz
- linux_amd64_client.tar.gz
- linux_amd64_server.tar.gz
- linux_arm64_client.tar.gz
- linux_arm64_server.tar.gz
- linux_arm_v5_client.tar.gz
- linux_arm_v6_client.tar.gz
- linux_arm_v7_client.tar.gz
- linux_arm_v5_server.tar.gz
- linux_arm_v6_server.tar.gz
- linux_arm_v7_server.tar.gz
- linux_mips64le_client.tar.gz
- linux_mips64le_server.tar.gz
- linux_mips64_client.tar.gz
- linux_mips64_server.tar.gz
- linux_mipsle_client.tar.gz
- linux_mipsle_server.tar.gz
- linux_mips_client.tar.gz
- linux_mips_server.tar.gz
- darwin_amd64_client.tar.gz
- darwin_amd64_server.tar.gz
- windows_386_client.tar.gz
- windows_386_server.tar.gz
- windows_amd64_client.tar.gz
- windows_amd64_server.tar.gz
- npc_syno.spk
- npc_sdk.tar.gz
- android_client.apk
on:
tags: true
all_branches: true
================================================
FILE: Dockerfile.npc
================================================
FROM golang:1.15 as builder
ARG GOPROXY=direct
WORKDIR /go/src/ehang.io/nps
COPY . .
RUN go get -d -v ./...
RUN CGO_ENABLED=0 go build -ldflags="-w -s -extldflags -static" ./cmd/npc/npc.go
FROM scratch
COPY --from=builder /go/src/ehang.io/nps/npc /
VOLUME /conf
ENTRYPOINT ["/npc"]
================================================
FILE: Dockerfile.nps
================================================
FROM golang:1.15 as builder
ARG GOPROXY=direct
WORKDIR /go/src/ehang.io/nps
COPY . .
RUN go get -d -v ./...
RUN CGO_ENABLED=0 go build -ldflags="-w -s -extldflags -static" ./cmd/nps/nps.go
FROM scratch
COPY --from=builder /go/src/ehang.io/nps/nps /
COPY --from=builder /go/src/ehang.io/nps/web /web
VOLUME /conf
CMD ["/nps"]
================================================
FILE: LICENSE
================================================
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
{one line to give the program's name and a brief idea of what it does.}
Copyright (C) {year} {name of author}
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
{project} Copyright (C) {year} {fullname}
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
================================================
FILE: Makefile
================================================
SOURCE_FILES?=./...
TEST_PATTERN?=.
TEST_OPTIONS?=
export PATH := ./bin:$(PATH)
export GO111MODULE := on
export GOPROXY := https://gocenter.io
# Build a beta version of goreleaser
build:
go build cmd/nps/nps.go
go build cmd/npc/npc.go
.PHONY: build
# Install all the build and lint dependencies
setup:
curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh
curl -L https://git.io/misspell | sh
go mod download
.PHONY: setup
# Run all the tests
test:
go test $(TEST_OPTIONS) -failfast -race -coverpkg=./... -covermode=atomic -coverprofile=coverage.txt $(SOURCE_FILES) -run $(TEST_PATTERN) -timeout=2m
.PHONY: test
# Run all the tests and opens the coverage report
cover: test
go tool cover -html=coverage.txt
.PHONY: cover
# gofmt and goimports all go files
fmt:
find . -name '*.go' -not -wholename './vendor/*' | while read -r file; do gofmt -w -s "$$file"; goimports -w "$$file"; done
.PHONY: fmt
# Run all the linters
lint:
# TODO: fix tests and lll issues
./bin/golangci-lint run --tests=false --enable-all --disable=lll ./...
./bin/misspell -error **/*
.PHONY: lint
# Clean go.mod
go-mod-tidy:
@go mod tidy -v
@git diff HEAD
@git diff-index --quiet HEAD
.PHONY: go-mod-tidy
# Run all the tests and code checks
ci: build test lint go-mod-tidy
.PHONY: ci
# Generate the static documentation
static:
@hugo --enableGitInfo --source www
.PHONY: static
# Show to-do items per file.
todo:
@grep \
--exclude-dir=vendor \
--exclude-dir=node_modules \
--exclude=Makefile \
--text \
--color \
-nRo -E ' TODO:.*|SkipNow' .
.PHONY: todo
clean:
rm npc nps
.PHONY: clean
.DEFAULT_GOAL := build
================================================
FILE: README.md
================================================
# NPS
 
[](https://gitter.im/cnlh-nps/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)


[README](https://github.com/ehang-io/nps/blob/master/README.md)|[中文文档](https://github.com/ehang-io/nps/blob/master/README_zh.md)
NPS is a lightweight, high-performance, powerful **intranet penetration** proxy server, with a powerful web management terminal.

## Feature
- Comprehensive protocol support, compatible with almost all commonly used protocols, such as tcp, udp, http(s), socks5, p2p, http proxy ...
- Full platform compatibility (linux, windows, macos, Synology, etc.), support installation as a system service simply.
- Comprehensive control, both client and server control are allowed.
- Https integration, support to convert backend proxy and web services to https, and support multiple certificates.
- Just simple configuration on web ui can complete most requirements.
- Complete information display, such as traffic, system information, real-time bandwidth, client version, etc.
- Powerful extension functions, everything is available (cache, compression, encryption, traffic limit, bandwidth limit, port reuse, etc.)
- Domain name resolution has functions such as custom headers, 404 page configuration, host modification, site protection, URL routing, and pan-resolution.
- Multi-user and user registration support on server.
**Didn't find the feature you want? It doesn't matter, click [Enter the document](https://ehang-io.github.io/nps/) to find it!**
## Quick start
### Installation
> [releases](https://github.com/ehang-io/nps/releases)
Download the corresponding system version, the server and client are separate.
### Server start
After downloading the server compressed package, unzip it, and then enter the unzipped folder.
- execute installation command
For linux、darwin ```sudo ./nps install```
For windows, run cmd as administrator and enter the installation directory ```nps.exe install```
- default ports
The default configuration file of nps use 80,443,8080,8024 ports
80 and 443 ports for host mode default ports
8080 for web management access port
8024 for net bridge port, to communicate between server and client
- start up
For linux、darwin ```sudo nps start```
For windows, run cmd as administrator and enter the program directory ```nps.exe start```
```After installation, the windows configuration file is located at C:\Program Files\nps, linux or darwin is located at /etc/nps```
**If you don't find it started successfully, you can check the log (Windows log files are located in the current running directory, linux and darwin are located in /var/log/nps.log).**
- Access server IP:web service port (default is 8080).
- Login with username and password (default is admin/123, must be modified when officially used).
- Create a client.
### Client connection
- Click the + sign in front of the client in web management and copy the startup command.
- Execute the startup command, Linux can be executed directly, Windows will replace ./npc with npc.exe and execute it with cmd.
If you need to register to the system service, you can check [Register to the system service](https://ehang-io.github.io/nps/#/use?id=注册到系统服务)
### Configuration
- After the client connects, configure the corresponding penetration service in the web.
- For more advanced usage, see [Complete Documentation](https://ehang-io.github.io/nps/)
## Contribution
- If you encounter a bug, you can submit it to the dev branch directly.
- If you encounter a problem, you can feedback through the issue.
- The project is under development, and there is still a lot of room for improvement. If you can contribute code, please submit PR to the dev branch.
- If there is feedback on new features, you can feedback via issues or qq group.
================================================
FILE: README_zh.md
================================================
# nps
 
[](https://gitter.im/cnlh-nps/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)


[README](https://github.com/ehang-io/nps/blob/master/README.md)|[中文文档](https://github.com/ehang-io/nps/blob/master/README_zh.md)
nps是一款轻量级、高性能、功能强大的**内网穿透**代理服务器。目前支持**tcp、udp流量转发**,可支持任何**tcp、udp**上层协议(访问内网网站、本地支付接口调试、ssh访问、远程桌面,内网dns解析等等……),此外还**支持内网http代理、内网socks5代理**、**p2p等**,并带有功能强大的web管理端。
## 背景

1. 做微信公众号开发、小程序开发等----> 域名代理模式
2. 想在外网通过ssh连接内网的机器,做云服务器到内网服务器端口的映射,----> tcp代理模式
3. 在非内网环境下使用内网dns,或者需要通过udp访问内网机器等----> udp代理模式
4. 在外网使用HTTP代理访问内网站点----> http代理模式
5. 搭建一个内网穿透ss,在外网如同使用内网vpn一样访问内网资源或者设备----> socks5代理模式
## 特点
- 协议支持全面,兼容几乎所有常用协议,例如tcp、udp、http(s)、socks5、p2p、http代理...
- 全平台兼容(linux、windows、macos、群辉等),支持一键安装为系统服务
- 控制全面,同时支持服务端和客户端控制
- https集成,支持将后端代理和web服务转成https,同时支持多证书
- 操作简单,只需简单的配置即可在web ui上完成其余操作
- 展示信息全面,流量、系统信息、即时带宽、客户端版本等
- 扩展功能强大,该有的都有了(缓存、压缩、加密、流量限制、带宽限制、端口复用等等)
- 域名解析具备自定义header、404页面配置、host修改、站点保护、URL路由、泛解析等功能
- 服务端支持多用户和用户注册功能
**没找到你想要的功能?不要紧,点击[进入文档](https://ehang-io.github.io/nps)查找吧**
## 快速开始
### 安装
> [releases](https://github.com/ehang-io/nps/releases)
下载对应的系统版本即可,服务端和客户端是单独的
### 服务端启动
下载完服务器压缩包后,解压,然后进入解压后的文件夹
- 执行安装命令
对于linux|darwin ```sudo ./nps install```
对于windows,管理员身份运行cmd,进入安装目录 ```nps.exe install```
- 默认端口
nps默认配置文件使用了80,443,8080,8024端口
80与443端口为域名解析模式默认端口
8080为web管理访问端口
8024为网桥端口,用于客户端与服务器通信
- 启动
对于linux|darwin ```sudo nps start```
对于windows,管理员身份运行cmd,进入程序目录 ```nps.exe start```
```安装后windows配置文件位于 C:\Program Files\nps,linux和darwin位于/etc/nps```
**如果发现没有启动成功,可以查看日志(Windows日志文件位于当前运行目录下,linux和darwin位于/var/log/nps.log)**
- 访问服务端ip:web服务端口(默认为8080)
- 使用用户名和密码登陆(默认admin/123,正式使用一定要更改)
- 创建客户端
### 客户端连接
- 点击web管理中客户端前的+号,复制启动命令
- 执行启动命令,linux直接执行即可,windows将./npc换成npc.exe用cmd执行
如果需要注册到系统服务可查看[注册到系统服务](https://ehang-io.github.io/nps/#/use?id=注册到系统服务)
### 配置
- 客户端连接后,在web中配置对应穿透服务即可
- 更多高级用法见[完整文档](https://ehang-io.github.io/nps/)
## 贡献
- 如果遇到bug可以直接提交至dev分支
- 使用遇到问题可以通过issues反馈
- 项目处于开发阶段,还有很多待完善的地方,如果可以贡献代码,请提交 PR 至 dev 分支
- 如果有新的功能特性反馈,可以通过issues或者qq群反馈
================================================
FILE: bridge/bridge.go
================================================
package bridge
import (
"ehang.io/nps-mux"
"encoding/binary"
"errors"
"fmt"
"net"
"os"
"strconv"
"strings"
"sync"
"time"
"ehang.io/nps/lib/common"
"ehang.io/nps/lib/conn"
"ehang.io/nps/lib/crypt"
"ehang.io/nps/lib/file"
"ehang.io/nps/lib/version"
"ehang.io/nps/server/connection"
"ehang.io/nps/server/tool"
"github.com/astaxie/beego"
"github.com/astaxie/beego/logs"
)
type Client struct {
tunnel *nps_mux.Mux
signal *conn.Conn
file *nps_mux.Mux
Version string
retryTime int // it will be add 1 when ping not ok until to 3 will close the client
}
func NewClient(t, f *nps_mux.Mux, s *conn.Conn, vs string) *Client {
return &Client{
signal: s,
tunnel: t,
file: f,
Version: vs,
}
}
type Bridge struct {
TunnelPort int //通信隧道端口
Client sync.Map
Register sync.Map
tunnelType string //bridge type kcp or tcp
OpenTask chan *file.Tunnel
CloseTask chan *file.Tunnel
CloseClient chan int
SecretChan chan *conn.Secret
ipVerify bool
runList sync.Map //map[int]interface{}
disconnectTime int
}
func NewTunnel(tunnelPort int, tunnelType string, ipVerify bool, runList sync.Map, disconnectTime int) *Bridge {
return &Bridge{
TunnelPort: tunnelPort,
tunnelType: tunnelType,
OpenTask: make(chan *file.Tunnel),
CloseTask: make(chan *file.Tunnel),
CloseClient: make(chan int),
SecretChan: make(chan *conn.Secret),
ipVerify: ipVerify,
runList: runList,
disconnectTime: disconnectTime,
}
}
func (s *Bridge) StartTunnel() error {
go s.ping()
if s.tunnelType == "kcp" {
logs.Info("server start, the bridge type is %s, the bridge port is %d", s.tunnelType, s.TunnelPort)
return conn.NewKcpListenerAndProcess(beego.AppConfig.String("bridge_ip")+":"+beego.AppConfig.String("bridge_port"), func(c net.Conn) {
s.cliProcess(conn.NewConn(c))
})
} else {
listener, err := connection.GetBridgeListener(s.tunnelType)
if err != nil {
logs.Error(err)
os.Exit(0)
return err
}
conn.Accept(listener, func(c net.Conn) {
s.cliProcess(conn.NewConn(c))
})
}
return nil
}
//get health information form client
func (s *Bridge) GetHealthFromClient(id int, c *conn.Conn) {
for {
if info, status, err := c.GetHealthInfo(); err != nil {
break
} else if !status { //the status is true , return target to the targetArr
file.GetDb().JsonDb.Tasks.Range(func(key, value interface{}) bool {
v := value.(*file.Tunnel)
if v.Client.Id == id && v.Mode == "tcp" && strings.Contains(v.Target.TargetStr, info) {
v.Lock()
if v.Target.TargetArr == nil || (len(v.Target.TargetArr) == 0 && len(v.HealthRemoveArr) == 0) {
v.Target.TargetArr = common.TrimArr(strings.Split(v.Target.TargetStr, "\n"))
}
v.Target.TargetArr = common.RemoveArrVal(v.Target.TargetArr, info)
if v.HealthRemoveArr == nil {
v.HealthRemoveArr = make([]string, 0)
}
v.HealthRemoveArr = append(v.HealthRemoveArr, info)
v.Unlock()
}
return true
})
file.GetDb().JsonDb.Hosts.Range(func(key, value interface{}) bool {
v := value.(*file.Host)
if v.Client.Id == id && strings.Contains(v.Target.TargetStr, info) {
v.Lock()
if v.Target.TargetArr == nil || (len(v.Target.TargetArr) == 0 && len(v.HealthRemoveArr) == 0) {
v.Target.TargetArr = common.TrimArr(strings.Split(v.Target.TargetStr, "\n"))
}
v.Target.TargetArr = common.RemoveArrVal(v.Target.TargetArr, info)
if v.HealthRemoveArr == nil {
v.HealthRemoveArr = make([]string, 0)
}
v.HealthRemoveArr = append(v.HealthRemoveArr, info)
v.Unlock()
}
return true
})
} else { //the status is false,remove target from the targetArr
file.GetDb().JsonDb.Tasks.Range(func(key, value interface{}) bool {
v := value.(*file.Tunnel)
if v.Client.Id == id && v.Mode == "tcp" && common.IsArrContains(v.HealthRemoveArr, info) && !common.IsArrContains(v.Target.TargetArr, info) {
v.Lock()
v.Target.TargetArr = append(v.Target.TargetArr, info)
v.HealthRemoveArr = common.RemoveArrVal(v.HealthRemoveArr, info)
v.Unlock()
}
return true
})
file.GetDb().JsonDb.Hosts.Range(func(key, value interface{}) bool {
v := value.(*file.Host)
if v.Client.Id == id && common.IsArrContains(v.HealthRemoveArr, info) && !common.IsArrContains(v.Target.TargetArr, info) {
v.Lock()
v.Target.TargetArr = append(v.Target.TargetArr, info)
v.HealthRemoveArr = common.RemoveArrVal(v.HealthRemoveArr, info)
v.Unlock()
}
return true
})
}
}
s.DelClient(id)
}
//验证失败,返回错误验证flag,并且关闭连接
func (s *Bridge) verifyError(c *conn.Conn) {
c.Write([]byte(common.VERIFY_EER))
}
func (s *Bridge) verifySuccess(c *conn.Conn) {
c.Write([]byte(common.VERIFY_SUCCESS))
}
func (s *Bridge) cliProcess(c *conn.Conn) {
//read test flag
if _, err := c.GetShortContent(3); err != nil {
logs.Info("The client %s connect error", c.Conn.RemoteAddr(), err.Error())
return
}
//version check
if b, err := c.GetShortLenContent(); err != nil || string(b) != version.GetVersion() {
logs.Info("The client %s version does not match", c.Conn.RemoteAddr())
c.Close()
return
}
//version get
var vs []byte
var err error
if vs, err = c.GetShortLenContent(); err != nil {
logs.Info("get client %s version error", err.Error())
c.Close()
return
}
//write server version to client
c.Write([]byte(crypt.Md5(version.GetVersion())))
c.SetReadDeadlineBySecond(5)
var buf []byte
//get vKey from client
if buf, err = c.GetShortContent(32); err != nil {
c.Close()
return
}
//verify
id, err := file.GetDb().GetIdByVerifyKey(string(buf), c.Conn.RemoteAddr().String())
if err != nil {
logs.Info("Current client connection validation error, close this client:", c.Conn.RemoteAddr())
s.verifyError(c)
return
} else {
s.verifySuccess(c)
}
if flag, err := c.ReadFlag(); err == nil {
s.typeDeal(flag, c, id, string(vs))
} else {
logs.Warn(err, flag)
}
return
}
func (s *Bridge) DelClient(id int) {
if v, ok := s.Client.Load(id); ok {
if v.(*Client).signal != nil {
v.(*Client).signal.Close()
}
s.Client.Delete(id)
if file.GetDb().IsPubClient(id) {
return
}
if c, err := file.GetDb().GetClient(id); err == nil {
s.CloseClient <- c.Id
}
}
}
//use different
func (s *Bridge) typeDeal(typeVal string, c *conn.Conn, id int, vs string) {
isPub := file.GetDb().IsPubClient(id)
switch typeVal {
case common.WORK_MAIN:
if isPub {
c.Close()
return
}
tcpConn, ok := c.Conn.(*net.TCPConn)
if ok {
// add tcp keep alive option for signal connection
_ = tcpConn.SetKeepAlive(true)
_ = tcpConn.SetKeepAlivePeriod(5 * time.Second)
}
//the vKey connect by another ,close the client of before
if v, ok := s.Client.LoadOrStore(id, NewClient(nil, nil, c, vs)); ok {
if v.(*Client).signal != nil {
v.(*Client).signal.WriteClose()
}
v.(*Client).signal = c
v.(*Client).Version = vs
}
go s.GetHealthFromClient(id, c)
logs.Info("clientId %d connection succeeded, address:%s ", id, c.Conn.RemoteAddr())
case common.WORK_CHAN:
muxConn := nps_mux.NewMux(c.Conn, s.tunnelType, s.disconnectTime)
if v, ok := s.Client.LoadOrStore(id, NewClient(muxConn, nil, nil, vs)); ok {
v.(*Client).tunnel = muxConn
}
case common.WORK_CONFIG:
client, err := file.GetDb().GetClient(id)
if err != nil || (!isPub && !client.ConfigConnAllow) {
c.Close()
return
}
binary.Write(c, binary.LittleEndian, isPub)
go s.getConfig(c, isPub, client)
case common.WORK_REGISTER:
go s.register(c)
case common.WORK_SECRET:
if b, err := c.GetShortContent(32); err == nil {
s.SecretChan <- conn.NewSecret(string(b), c)
} else {
logs.Error("secret error, failed to match the key successfully")
}
case common.WORK_FILE:
muxConn := nps_mux.NewMux(c.Conn, s.tunnelType, s.disconnectTime)
if v, ok := s.Client.LoadOrStore(id, NewClient(nil, muxConn, nil, vs)); ok {
v.(*Client).file = muxConn
}
case common.WORK_P2P:
//read md5 secret
if b, err := c.GetShortContent(32); err != nil {
logs.Error("p2p error,", err.Error())
} else if t := file.GetDb().GetTaskByMd5Password(string(b)); t == nil {
logs.Error("p2p error, failed to match the key successfully")
} else {
if v, ok := s.Client.Load(t.Client.Id); !ok {
return
} else {
//向密钥对应的客户端发送与服务端udp建立连接信息,地址,密钥
v.(*Client).signal.Write([]byte(common.NEW_UDP_CONN))
svrAddr := beego.AppConfig.String("p2p_ip") + ":" + beego.AppConfig.String("p2p_port")
if err != nil {
logs.Warn("get local udp addr error")
return
}
v.(*Client).signal.WriteLenContent([]byte(svrAddr))
v.(*Client).signal.WriteLenContent(b)
//向该请求者发送建立连接请求,服务器地址
c.WriteLenContent([]byte(svrAddr))
}
}
}
c.SetAlive(s.tunnelType)
return
}
//register ip
func (s *Bridge) register(c *conn.Conn) {
var hour int32
if err := binary.Read(c, binary.LittleEndian, &hour); err == nil {
s.Register.Store(common.GetIpByAddr(c.Conn.RemoteAddr().String()), time.Now().Add(time.Hour*time.Duration(hour)))
}
}
func (s *Bridge) SendLinkInfo(clientId int, link *conn.Link, t *file.Tunnel) (target net.Conn, err error) {
//if the proxy type is local
if link.LocalProxy {
target, err = net.Dial("tcp", link.Host)
return
}
if v, ok := s.Client.Load(clientId); ok {
//If ip is restricted to do ip verification
if s.ipVerify {
ip := common.GetIpByAddr(link.RemoteAddr)
if v, ok := s.Register.Load(ip); !ok {
return nil, errors.New(fmt.Sprintf("The ip %s is not in the validation list", ip))
} else {
if !v.(time.Time).After(time.Now()) {
return nil, errors.New(fmt.Sprintf("The validity of the ip %s has expired", ip))
}
}
}
var tunnel *nps_mux.Mux
if t != nil && t.Mode == "file" {
tunnel = v.(*Client).file
} else {
tunnel = v.(*Client).tunnel
}
if tunnel == nil {
err = errors.New("the client connect error")
return
}
if target, err = tunnel.NewConn(); err != nil {
return
}
if t != nil && t.Mode == "file" {
//TODO if t.mode is file ,not use crypt or compress
link.Crypt = false
link.Compress = false
return
}
if _, err = conn.NewConn(target).SendInfo(link, ""); err != nil {
logs.Info("new connect error ,the target %s refuse to connect", link.Host)
return
}
} else {
err = errors.New(fmt.Sprintf("the client %d is not connect", clientId))
}
return
}
func (s *Bridge) ping() {
ticker := time.NewTicker(time.Second * 5)
defer ticker.Stop()
for {
select {
case <-ticker.C:
arr := make([]int, 0)
s.Client.Range(func(key, value interface{}) bool {
v := value.(*Client)
if v.tunnel == nil || v.signal == nil {
v.retryTime += 1
if v.retryTime >= 3 {
arr = append(arr, key.(int))
}
return true
}
if v.tunnel.IsClose {
arr = append(arr, key.(int))
}
return true
})
for _, v := range arr {
logs.Info("the client %d closed", v)
s.DelClient(v)
}
}
}
}
//get config and add task from client config
func (s *Bridge) getConfig(c *conn.Conn, isPub bool, client *file.Client) {
var fail bool
loop:
for {
flag, err := c.ReadFlag()
if err != nil {
break
}
switch flag {
case common.WORK_STATUS:
if b, err := c.GetShortContent(32); err != nil {
break loop
} else {
var str string
id, err := file.GetDb().GetClientIdByVkey(string(b))
if err != nil {
break loop
}
file.GetDb().JsonDb.Hosts.Range(func(key, value interface{}) bool {
v := value.(*file.Host)
if v.Client.Id == id {
str += v.Remark + common.CONN_DATA_SEQ
}
return true
})
file.GetDb().JsonDb.Tasks.Range(func(key, value interface{}) bool {
v := value.(*file.Tunnel)
//if _, ok := s.runList[v.Id]; ok && v.Client.Id == id {
if _, ok := s.runList.Load(v.Id); ok && v.Client.Id == id {
str += v.Remark + common.CONN_DATA_SEQ
}
return true
})
binary.Write(c, binary.LittleEndian, int32(len([]byte(str))))
binary.Write(c, binary.LittleEndian, []byte(str))
}
case common.NEW_CONF:
var err error
if client, err = c.GetConfigInfo(); err != nil {
fail = true
c.WriteAddFail()
break loop
} else {
if err = file.GetDb().NewClient(client); err != nil {
fail = true
c.WriteAddFail()
break loop
}
c.WriteAddOk()
c.Write([]byte(client.VerifyKey))
s.Client.Store(client.Id, NewClient(nil, nil, nil, ""))
}
case common.NEW_HOST:
h, err := c.GetHostInfo()
if err != nil {
fail = true
c.WriteAddFail()
break loop
}
h.Client = client
if h.Location == "" {
h.Location = "/"
}
if !client.HasHost(h) {
if file.GetDb().IsHostExist(h) {
fail = true
c.WriteAddFail()
break loop
} else {
file.GetDb().NewHost(h)
c.WriteAddOk()
}
} else {
c.WriteAddOk()
}
case common.NEW_TASK:
if t, err := c.GetTaskInfo(); err != nil {
fail = true
c.WriteAddFail()
break loop
} else {
ports := common.GetPorts(t.Ports)
targets := common.GetPorts(t.Target.TargetStr)
if len(ports) > 1 && (t.Mode == "tcp" || t.Mode == "udp") && (len(ports) != len(targets)) {
fail = true
c.WriteAddFail()
break loop
} else if t.Mode == "secret" || t.Mode == "p2p" {
ports = append(ports, 0)
}
if len(ports) == 0 {
fail = true
c.WriteAddFail()
break loop
}
for i := 0; i < len(ports); i++ {
tl := new(file.Tunnel)
tl.Mode = t.Mode
tl.Port = ports[i]
tl.ServerIp = t.ServerIp
if len(ports) == 1 {
tl.Target = t.Target
tl.Remark = t.Remark
} else {
tl.Remark = t.Remark + "_" + strconv.Itoa(tl.Port)
tl.Target = new(file.Target)
if t.TargetAddr != "" {
tl.Target.TargetStr = t.TargetAddr + ":" + strconv.Itoa(targets[i])
} else {
tl.Target.TargetStr = strconv.Itoa(targets[i])
}
}
tl.Id = int(file.GetDb().JsonDb.GetTaskId())
tl.Status = true
tl.Flow = new(file.Flow)
tl.NoStore = true
tl.Client = client
tl.Password = t.Password
tl.LocalPath = t.LocalPath
tl.StripPre = t.StripPre
tl.MultiAccount = t.MultiAccount
if !client.HasTunnel(tl) {
if err := file.GetDb().NewTask(tl); err != nil {
logs.Notice("Add task error ", err.Error())
fail = true
c.WriteAddFail()
break loop
}
if b := tool.TestServerPort(tl.Port, tl.Mode); !b && t.Mode != "secret" && t.Mode != "p2p" {
fail = true
c.WriteAddFail()
break loop
} else {
s.OpenTask <- tl
}
}
c.WriteAddOk()
}
}
}
}
if fail && client != nil {
s.DelClient(client.Id)
}
c.Close()
}
================================================
FILE: build.android.sh
================================================
#/bin/bash
cd /go
apt-get install libegl1-mesa-dev libgles2-mesa-dev libx11-dev xorg-dev -y
go get -u fyne.io/fyne/v2/cmd/fyne fyne.io/fyne/v2
#mkdir -p /go/src/fyne.io
#cd src/fyne.io
#git clone https://github.com/fyne-io/fyne.git
#cd fyne
#git checkout v1.2.0
#go install -v ./cmd/fyne
#fyne package -os android fyne.io/fyne/cmd/hello
echo "fyne install success"
mkdir -p /go/src/ehang.io/nps
cp -R /app/* /go/src/ehang.io/nps
cd /go/src/ehang.io/nps
#go get -u fyne.io/fyne fyne.io/fyne/cmd/fyne
rm cmd/npc/sdk.go
#go get -u ./...
#go mod tidy
#rm -rf /go/src/golang.org/x/mobile
echo "tidy success"
cd /go/src/ehang.io/nps
go mod vendor
cd vendor
cp -R * /go/src
cd ..
rm -rf vendor
#rm -rf ~/.cache/*
echo "vendor success"
cd gui/npc
fyne package -appID org.nps.client -os android -icon ../../docs/logo.png
mv npc.apk /app/android_client.apk
echo "android build success"
================================================
FILE: build.assets.sh
================================================
export GOPROXY=direct
sudo apt-get update
sudo apt-get install gcc-mingw-w64-i686 gcc-multilib
env GOOS=windows GOARCH=386 CGO_ENABLED=1 CC=i686-w64-mingw32-gcc go build -ldflags "-s -w -extldflags -static -extldflags -static" -buildmode=c-shared -o npc_sdk.dll cmd/npc/sdk.go
env GOOS=linux GOARCH=386 CGO_ENABLED=1 CC=gcc go build -ldflags "-s -w -extldflags -static -extldflags -static" -buildmode=c-shared -o npc_sdk.so cmd/npc/sdk.go
tar -czvf npc_sdk.tar.gz npc_sdk.dll npc_sdk.so npc_sdk.h
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
tar -czvf linux_amd64_client.tar.gz npc conf/npc.conf conf/multi_account.conf
CGO_ENABLED=0 GOOS=linux GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
tar -czvf linux_386_client.tar.gz npc conf/npc.conf conf/multi_account.conf
CGO_ENABLED=0 GOOS=freebsd GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
tar -czvf freebsd_386_client.tar.gz npc conf/npc.conf conf/multi_account.conf
CGO_ENABLED=0 GOOS=freebsd GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
tar -czvf freebsd_amd64_client.tar.gz npc conf/npc.conf conf/multi_account.conf
CGO_ENABLED=0 GOOS=freebsd GOARCH=arm go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
tar -czvf freebsd_arm_client.tar.gz npc conf/npc.conf conf/multi_account.conf
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
tar -czvf linux_arm_v7_client.tar.gz npc conf/npc.conf conf/multi_account.conf
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=6 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
tar -czvf linux_arm_v6_client.tar.gz npc conf/npc.conf conf/multi_account.conf
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=5 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
tar -czvf linux_arm_v5_client.tar.gz npc conf/npc.conf conf/multi_account.conf
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
tar -czvf linux_arm64_client.tar.gz npc conf/npc.conf conf/multi_account.conf
CGO_ENABLED=0 GOOS=linux GOARCH=mips64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
tar -czvf linux_mips64_client.tar.gz npc conf/npc.conf conf/multi_account.conf
CGO_ENABLED=0 GOOS=linux GOARCH=mips64le go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
tar -czvf linux_mips64le_client.tar.gz npc conf/npc.conf conf/multi_account.conf
CGO_ENABLED=0 GOOS=linux GOARCH=mipsle go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
tar -czvf linux_mipsle_client.tar.gz npc conf/npc.conf conf/multi_account.conf
CGO_ENABLED=0 GOOS=linux GOARCH=mips go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
tar -czvf linux_mips_client.tar.gz npc conf/npc.conf conf/multi_account.conf
CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
tar -czvf windows_386_client.tar.gz npc.exe conf/npc.conf conf/multi_account.conf
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
tar -czvf windows_amd64_client.tar.gz npc.exe conf/npc.conf conf/multi_account.conf
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
tar -czvf darwin_amd64_client.tar.gz npc conf/npc.conf conf/multi_account.conf
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
tar -czvf linux_amd64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
CGO_ENABLED=0 GOOS=linux GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
tar -czvf linux_386_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=5 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
tar -czvf linux_arm_v5_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=6 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
tar -czvf linux_arm_v6_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
tar -czvf linux_arm_v7_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
tar -czvf linux_arm64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
CGO_ENABLED=0 GOOS=freebsd GOARCH=arm go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
tar -czvf freebsd_arm_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
CGO_ENABLED=0 GOOS=freebsd GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
tar -czvf freebsd_386_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
CGO_ENABLED=0 GOOS=freebsd GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
tar -czvf freebsd_amd64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
CGO_ENABLED=0 GOOS=linux GOARCH=mips go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
tar -czvf linux_mips_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
CGO_ENABLED=0 GOOS=linux GOARCH=mips64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
tar -czvf linux_mips64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
CGO_ENABLED=0 GOOS=linux GOARCH=mips64le go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
tar -czvf linux_mips64le_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
CGO_ENABLED=0 GOOS=linux GOARCH=mipsle go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
tar -czvf linux_mipsle_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
tar -czvf darwin_amd64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
tar -czvf windows_amd64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps.exe
CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
tar -czvf windows_386_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps.exe
================================================
FILE: build.sh
================================================
#/bash/sh
export VERSION=0.26.10
export GOPROXY=direct
sudo apt-get update
sudo apt-get install gcc-mingw-w64-i686 gcc-multilib
env GOOS=windows GOARCH=386 CGO_ENABLED=1 CC=i686-w64-mingw32-gcc go build -ldflags "-s -w -extldflags -static -extldflags -static" -buildmode=c-shared -o npc_sdk.dll cmd/npc/sdk.go
env GOOS=linux GOARCH=386 CGO_ENABLED=1 CC=gcc go build -ldflags "-s -w -extldflags -static -extldflags -static" -buildmode=c-shared -o npc_sdk.so cmd/npc/sdk.go
tar -czvf npc_sdk.tar.gz npc_sdk.dll npc_sdk.so npc_sdk.h
wget https://github.com/upx/upx/releases/download/v3.95/upx-3.95-amd64_linux.tar.xz
tar -xvf upx-3.95-amd64_linux.tar.xz
cp upx-3.95-amd64_linux/upx ./
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
tar -czvf linux_amd64_client.tar.gz npc conf/npc.conf conf/multi_account.conf
CGO_ENABLED=0 GOOS=linux GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
tar -czvf linux_386_client.tar.gz npc conf/npc.conf conf/multi_account.conf
CGO_ENABLED=0 GOOS=freebsd GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
tar -czvf freebsd_386_client.tar.gz npc conf/npc.conf conf/multi_account.conf
CGO_ENABLED=0 GOOS=freebsd GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
tar -czvf freebsd_amd64_client.tar.gz npc conf/npc.conf conf/multi_account.conf
CGO_ENABLED=0 GOOS=freebsd GOARCH=arm go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
tar -czvf freebsd_arm_client.tar.gz npc conf/npc.conf conf/multi_account.conf
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
tar -czvf linux_arm_v7_client.tar.gz npc conf/npc.conf conf/multi_account.conf
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=6 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
tar -czvf linux_arm_v6_client.tar.gz npc conf/npc.conf conf/multi_account.conf
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=5 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
tar -czvf linux_arm_v5_client.tar.gz npc conf/npc.conf conf/multi_account.conf
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
tar -czvf linux_arm64_client.tar.gz npc conf/npc.conf conf/multi_account.conf
CGO_ENABLED=0 GOOS=linux GOARCH=mips64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
tar -czvf linux_mips64_client.tar.gz npc conf/npc.conf conf/multi_account.conf
CGO_ENABLED=0 GOOS=linux GOARCH=mips64le go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
tar -czvf linux_mips64le_client.tar.gz npc conf/npc.conf conf/multi_account.conf
CGO_ENABLED=0 GOOS=linux GOARCH=mipsle go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
tar -czvf linux_mipsle_client.tar.gz npc conf/npc.conf conf/multi_account.conf
CGO_ENABLED=0 GOOS=linux GOARCH=mips go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
tar -czvf linux_mips_client.tar.gz npc conf/npc.conf conf/multi_account.conf
CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
tar -czvf windows_386_client.tar.gz npc.exe conf/npc.conf conf/multi_account.conf
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
tar -czvf windows_amd64_client.tar.gz npc.exe conf/npc.conf conf/multi_account.conf
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
tar -czvf darwin_amd64_client.tar.gz npc conf/npc.conf conf/multi_account.conf
CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
tar -czvf darwin_arm64_client.tar.gz npc conf/npc.conf conf/multi_account.conf
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
tar -czvf linux_amd64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
CGO_ENABLED=0 GOOS=linux GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
tar -czvf linux_386_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=5 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
tar -czvf linux_arm_v5_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=6 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
tar -czvf linux_arm_v6_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
tar -czvf linux_arm_v7_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
tar -czvf linux_arm64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
CGO_ENABLED=0 GOOS=freebsd GOARCH=arm go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
tar -czvf freebsd_arm_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
CGO_ENABLED=0 GOOS=freebsd GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
tar -czvf freebsd_386_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
CGO_ENABLED=0 GOOS=freebsd GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
tar -czvf freebsd_amd64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
CGO_ENABLED=0 GOOS=linux GOARCH=mips go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
tar -czvf linux_mips_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
CGO_ENABLED=0 GOOS=linux GOARCH=mips64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
tar -czvf linux_mips64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
CGO_ENABLED=0 GOOS=linux GOARCH=mips64le go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
tar -czvf linux_mips64le_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
CGO_ENABLED=0 GOOS=linux GOARCH=mipsle go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
tar -czvf linux_mipsle_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
tar -czvf darwin_amd64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
tar -czvf darwin_arm64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
tar -czvf windows_amd64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps.exe
CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
tar -czvf windows_386_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps.exe
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
sudo apt-get update
sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
docker --version
docker run --rm -i -w /app -v $(pwd):/app -e ANDROID_HOME=/usr/local/android_sdk -e GOPROXY=direct lucor/fyne-cross:android-latest /app/build.android.sh
git clone https://github.com/cnlh/spksrc.git ~/spksrc
mkdir ~/spksrc/nps && cp -rf ./* ~/spksrc/nps/
docker run -itd --name spksrc --env VERSION=$VERSION -e GOPROXY=direct -v ~/spksrc:/spksrc synocommunity/spksrc /bin/bash
docker exec -it spksrc /bin/bash -c 'cd /spksrc && make setup && cd /spksrc/spk/npc && make arch-x64-7.0'
cp ~/spksrc/packages/npc_x64-7.0_$VERSION-1.spk ./npc_syno.spk
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
export DOCKER_CLI_EXPERIMENTAL=enabled
docker run --rm --privileged docker/binfmt:66f9012c56a8316f9244ffd7622d7c21c1f6f28d
docker buildx create --use --name mybuilder
docker buildx build --tag ffdfgdfg/nps:$VERSION --tag ffdfgdfg/nps:latest --output type=image,push=true --file Dockerfile.nps --platform=linux/amd64,linux/arm64,linux/386,linux/arm .
docker buildx build --tag ffdfgdfg/npc:$VERSION --tag ffdfgdfg/npc:latest --output type=image,push=true --file Dockerfile.npc --platform=linux/amd64,linux/arm64,linux/386,linux/arm .
================================================
FILE: client/client.go
================================================
package client
import (
"bufio"
"bytes"
"ehang.io/nps-mux"
"net"
"net/http"
"strconv"
"sync"
"time"
"github.com/astaxie/beego/logs"
"github.com/xtaci/kcp-go"
"ehang.io/nps/lib/common"
"ehang.io/nps/lib/config"
"ehang.io/nps/lib/conn"
"ehang.io/nps/lib/crypt"
)
type TRPClient struct {
svrAddr string
bridgeConnType string
proxyUrl string
vKey string
p2pAddr map[string]string
tunnel *nps_mux.Mux
signal *conn.Conn
ticker *time.Ticker
cnf *config.Config
disconnectTime int
once sync.Once
}
//new client
func NewRPClient(svraddr string, vKey string, bridgeConnType string, proxyUrl string, cnf *config.Config, disconnectTime int) *TRPClient {
return &TRPClient{
svrAddr: svraddr,
p2pAddr: make(map[string]string, 0),
vKey: vKey,
bridgeConnType: bridgeConnType,
proxyUrl: proxyUrl,
cnf: cnf,
disconnectTime: disconnectTime,
once: sync.Once{},
}
}
var NowStatus int
var CloseClient bool
//start
func (s *TRPClient) Start() {
CloseClient = false
retry:
if CloseClient {
return
}
NowStatus = 0
c, err := NewConn(s.bridgeConnType, s.vKey, s.svrAddr, common.WORK_MAIN, s.proxyUrl)
if err != nil {
logs.Error("The connection server failed and will be reconnected in five seconds, error", err.Error())
time.Sleep(time.Second * 5)
goto retry
}
if c == nil {
logs.Error("Error data from server, and will be reconnected in five seconds")
time.Sleep(time.Second * 5)
goto retry
}
logs.Info("Successful connection with server %s", s.svrAddr)
//monitor the connection
go s.ping()
s.signal = c
//start a channel connection
go s.newChan()
//start health check if the it's open
if s.cnf != nil && len(s.cnf.Healths) > 0 {
go heathCheck(s.cnf.Healths, s.signal)
}
NowStatus = 1
//msg connection, eg udp
s.handleMain()
}
//handle main connection
func (s *TRPClient) handleMain() {
for {
flags, err := s.signal.ReadFlag()
if err != nil {
logs.Error("Accept server data error %s, end this service", err.Error())
break
}
switch flags {
case common.NEW_UDP_CONN:
//read server udp addr and password
if lAddr, err := s.signal.GetShortLenContent(); err != nil {
logs.Warn(err)
return
} else if pwd, err := s.signal.GetShortLenContent(); err == nil {
var localAddr string
//The local port remains unchanged for a certain period of time
if v, ok := s.p2pAddr[crypt.Md5(string(pwd)+strconv.Itoa(int(time.Now().Unix()/100)))]; !ok {
tmpConn, err := common.GetLocalUdpAddr()
if err != nil {
logs.Error(err)
return
}
localAddr = tmpConn.LocalAddr().String()
} else {
localAddr = v
}
go s.newUdpConn(localAddr, string(lAddr), string(pwd))
}
}
}
s.Close()
}
func (s *TRPClient) newUdpConn(localAddr, rAddr string, md5Password string) {
var localConn net.PacketConn
var err error
var remoteAddress string
if remoteAddress, localConn, err = handleP2PUdp(localAddr, rAddr, md5Password, common.WORK_P2P_PROVIDER); err != nil {
logs.Error(err)
return
}
l, err := kcp.ServeConn(nil, 150, 3, localConn)
if err != nil {
logs.Error(err)
return
}
logs.Trace("start local p2p udp listen, local address", localConn.LocalAddr().String())
for {
udpTunnel, err := l.AcceptKCP()
if err != nil {
logs.Error(err)
l.Close()
return
}
if udpTunnel.RemoteAddr().String() == string(remoteAddress) {
conn.SetUdpSession(udpTunnel)
logs.Trace("successful connection with client ,address %s", udpTunnel.RemoteAddr().String())
//read link info from remote
conn.Accept(nps_mux.NewMux(udpTunnel, s.bridgeConnType, s.disconnectTime), func(c net.Conn) {
go s.handleChan(c)
})
break
}
}
}
//pmux tunnel
func (s *TRPClient) newChan() {
tunnel, err := NewConn(s.bridgeConnType, s.vKey, s.svrAddr, common.WORK_CHAN, s.proxyUrl)
if err != nil {
logs.Error("connect to ", s.svrAddr, "error:", err)
return
}
s.tunnel = nps_mux.NewMux(tunnel.Conn, s.bridgeConnType, s.disconnectTime)
for {
src, err := s.tunnel.Accept()
if err != nil {
logs.Warn(err)
s.Close()
break
}
go s.handleChan(src)
}
}
func (s *TRPClient) handleChan(src net.Conn) {
lk, err := conn.NewConn(src).GetLinkInfo()
if err != nil || lk == nil {
src.Close()
logs.Error("get connection info from server error ", err)
return
}
//host for target processing
lk.Host = common.FormatAddress(lk.Host)
//if Conn type is http, read the request and log
if lk.ConnType == "http" {
if targetConn, err := net.DialTimeout(common.CONN_TCP, lk.Host, lk.Option.Timeout); err != nil {
logs.Warn("connect to %s error %s", lk.Host, err.Error())
src.Close()
} else {
srcConn := conn.GetConn(src, lk.Crypt, lk.Compress, nil, false)
go func() {
common.CopyBuffer(srcConn, targetConn)
srcConn.Close()
targetConn.Close()
}()
for {
if r, err := http.ReadRequest(bufio.NewReader(srcConn)); err != nil {
srcConn.Close()
targetConn.Close()
break
} else {
logs.Trace("http request, method %s, host %s, url %s, remote address %s", r.Method, r.Host, r.URL.Path, r.RemoteAddr)
r.Write(targetConn)
}
}
}
return
}
if lk.ConnType == "udp5" {
logs.Trace("new %s connection with the goal of %s, remote address:%s", lk.ConnType, lk.Host, lk.RemoteAddr)
s.handleUdp(src)
}
//connect to target if conn type is tcp or udp
if targetConn, err := net.DialTimeout(lk.ConnType, lk.Host, lk.Option.Timeout); err != nil {
logs.Warn("connect to %s error %s", lk.Host, err.Error())
src.Close()
} else {
logs.Trace("new %s connection with the goal of %s, remote address:%s", lk.ConnType, lk.Host, lk.RemoteAddr)
conn.CopyWaitGroup(src, targetConn, lk.Crypt, lk.Compress, nil, nil, false, nil)
}
}
func (s *TRPClient) handleUdp(serverConn net.Conn) {
// bind a local udp port
local, err := net.ListenUDP("udp", nil)
defer serverConn.Close()
if err != nil {
logs.Error("bind local udp port error ", err.Error())
return
}
defer local.Close()
go func() {
defer serverConn.Close()
b := common.BufPoolUdp.Get().([]byte)
defer common.BufPoolUdp.Put(b)
for {
n, raddr, err := local.ReadFrom(b)
if err != nil {
logs.Error("read data from remote server error", err.Error())
}
buf := bytes.Buffer{}
dgram := common.NewUDPDatagram(common.NewUDPHeader(0, 0, common.ToSocksAddr(raddr)), b[:n])
dgram.Write(&buf)
b, err := conn.GetLenBytes(buf.Bytes())
if err != nil {
logs.Warn("get len bytes error", err.Error())
continue
}
if _, err := serverConn.Write(b); err != nil {
logs.Error("write data to remote error", err.Error())
return
}
}
}()
b := common.BufPoolUdp.Get().([]byte)
defer common.BufPoolUdp.Put(b)
for {
n, err := serverConn.Read(b)
if err != nil {
logs.Error("read udp data from server error ", err.Error())
return
}
udpData, err := common.ReadUDPDatagram(bytes.NewReader(b[:n]))
if err != nil {
logs.Error("unpack data error", err.Error())
return
}
raddr, err := net.ResolveUDPAddr("udp", udpData.Header.Addr.String())
if err != nil {
logs.Error("build remote addr err", err.Error())
continue // drop silently
}
_, err = local.WriteTo(udpData.Data, raddr)
if err != nil {
logs.Error("write data to remote ", raddr.String(), "error", err.Error())
return
}
}
}
// Whether the monitor channel is closed
func (s *TRPClient) ping() {
s.ticker = time.NewTicker(time.Second * 5)
loop:
for {
select {
case <-s.ticker.C:
if s.tunnel != nil && s.tunnel.IsClose {
s.Close()
break loop
}
}
}
}
func (s *TRPClient) Close() {
s.once.Do(s.closing)
}
func (s *TRPClient) closing() {
CloseClient = true
NowStatus = 0
if s.tunnel != nil {
_ = s.tunnel.Close()
}
if s.signal != nil {
_ = s.signal.Close()
}
if s.ticker != nil {
s.ticker.Stop()
}
}
================================================
FILE: client/control.go
================================================
package client
import (
"bufio"
"encoding/base64"
"encoding/binary"
"errors"
"fmt"
"io/ioutil"
"log"
"math"
"math/rand"
"net"
"net/http"
"net/url"
"os"
"path/filepath"
"strconv"
"strings"
"time"
"ehang.io/nps/lib/common"
"ehang.io/nps/lib/config"
"ehang.io/nps/lib/conn"
"ehang.io/nps/lib/crypt"
"ehang.io/nps/lib/version"
"github.com/astaxie/beego/logs"
"github.com/xtaci/kcp-go"
"golang.org/x/net/proxy"
)
func GetTaskStatus(path string) {
cnf, err := config.NewConfig(path)
if err != nil {
log.Fatalln(err)
}
c, err := NewConn(cnf.CommonConfig.Tp, cnf.CommonConfig.VKey, cnf.CommonConfig.Server, common.WORK_CONFIG, cnf.CommonConfig.ProxyUrl)
if err != nil {
log.Fatalln(err)
}
if _, err := c.Write([]byte(common.WORK_STATUS)); err != nil {
log.Fatalln(err)
}
//read now vKey and write to server
if f, err := common.ReadAllFromFile(filepath.Join(common.GetTmpPath(), "npc_vkey.txt")); err != nil {
log.Fatalln(err)
} else if _, err := c.Write([]byte(crypt.Md5(string(f)))); err != nil {
log.Fatalln(err)
}
var isPub bool
binary.Read(c, binary.LittleEndian, &isPub)
if l, err := c.GetLen(); err != nil {
log.Fatalln(err)
} else if b, err := c.GetShortContent(l); err != nil {
log.Fatalln(err)
} else {
arr := strings.Split(string(b), common.CONN_DATA_SEQ)
for _, v := range cnf.Hosts {
if common.InStrArr(arr, v.Remark) {
log.Println(v.Remark, "ok")
} else {
log.Println(v.Remark, "not running")
}
}
for _, v := range cnf.Tasks {
ports := common.GetPorts(v.Ports)
if v.Mode == "secret" {
ports = append(ports, 0)
}
for _, vv := range ports {
var remark string
if len(ports) > 1 {
remark = v.Remark + "_" + strconv.Itoa(vv)
} else {
remark = v.Remark
}
if common.InStrArr(arr, remark) {
log.Println(remark, "ok")
} else {
log.Println(remark, "not running")
}
}
}
}
os.Exit(0)
}
var errAdd = errors.New("The server returned an error, which port or host may have been occupied or not allowed to open.")
func StartFromFile(path string) {
first := true
cnf, err := config.NewConfig(path)
if err != nil || cnf.CommonConfig == nil {
logs.Error("Config file %s loading error %s", path, err.Error())
os.Exit(0)
}
logs.Info("Loading configuration file %s successfully", path)
re:
if first || cnf.CommonConfig.AutoReconnection {
if !first {
logs.Info("Reconnecting...")
time.Sleep(time.Second * 5)
}
} else {
return
}
first = false
c, err := NewConn(cnf.CommonConfig.Tp, cnf.CommonConfig.VKey, cnf.CommonConfig.Server, common.WORK_CONFIG, cnf.CommonConfig.ProxyUrl)
if err != nil {
logs.Error(err)
goto re
}
var isPub bool
binary.Read(c, binary.LittleEndian, &isPub)
// get tmp password
var b []byte
vkey := cnf.CommonConfig.VKey
if isPub {
// send global configuration to server and get status of config setting
if _, err := c.SendInfo(cnf.CommonConfig.Client, common.NEW_CONF); err != nil {
logs.Error(err)
goto re
}
if !c.GetAddStatus() {
logs.Error("the web_user may have been occupied!")
goto re
}
if b, err = c.GetShortContent(16); err != nil {
logs.Error(err)
goto re
}
vkey = string(b)
}
ioutil.WriteFile(filepath.Join(common.GetTmpPath(), "npc_vkey.txt"), []byte(vkey), 0600)
//send hosts to server
for _, v := range cnf.Hosts {
if _, err := c.SendInfo(v, common.NEW_HOST); err != nil {
logs.Error(err)
goto re
}
if !c.GetAddStatus() {
logs.Error(errAdd, v.Host)
goto re
}
}
//send task to server
for _, v := range cnf.Tasks {
if _, err := c.SendInfo(v, common.NEW_TASK); err != nil {
logs.Error(err)
goto re
}
if !c.GetAddStatus() {
logs.Error(errAdd, v.Ports, v.Remark)
goto re
}
if v.Mode == "file" {
//start local file server
go startLocalFileServer(cnf.CommonConfig, v, vkey)
}
}
//create local server secret or p2p
for _, v := range cnf.LocalServer {
go StartLocalServer(v, cnf.CommonConfig)
}
c.Close()
if cnf.CommonConfig.Client.WebUserName == "" || cnf.CommonConfig.Client.WebPassword == "" {
logs.Notice("web access login username:user password:%s", vkey)
} else {
logs.Notice("web access login username:%s password:%s", cnf.CommonConfig.Client.WebUserName, cnf.CommonConfig.Client.WebPassword)
}
NewRPClient(cnf.CommonConfig.Server, vkey, cnf.CommonConfig.Tp, cnf.CommonConfig.ProxyUrl, cnf, cnf.CommonConfig.DisconnectTime).Start()
CloseLocalServer()
goto re
}
// Create a new connection with the server and verify it
func NewConn(tp string, vkey string, server string, connType string, proxyUrl string) (*conn.Conn, error) {
var err error
var connection net.Conn
var sess *kcp.UDPSession
if tp == "tcp" {
if proxyUrl != "" {
u, er := url.Parse(proxyUrl)
if er != nil {
return nil, er
}
switch u.Scheme {
case "socks5":
n, er := proxy.FromURL(u, nil)
if er != nil {
return nil, er
}
connection, err = n.Dial("tcp", server)
default:
connection, err = NewHttpProxyConn(u, server)
}
} else {
connection, err = net.Dial("tcp", server)
}
} else {
sess, err = kcp.DialWithOptions(server, nil, 10, 3)
if err == nil {
conn.SetUdpSession(sess)
connection = sess
}
}
if err != nil {
return nil, err
}
connection.SetDeadline(time.Now().Add(time.Second * 10))
defer connection.SetDeadline(time.Time{})
c := conn.NewConn(connection)
if _, err := c.Write([]byte(common.CONN_TEST)); err != nil {
return nil, err
}
if err := c.WriteLenContent([]byte(version.GetVersion())); err != nil {
return nil, err
}
if err := c.WriteLenContent([]byte(version.VERSION)); err != nil {
return nil, err
}
b, err := c.GetShortContent(32)
if err != nil {
logs.Error(err)
return nil, err
}
if crypt.Md5(version.GetVersion()) != string(b) {
logs.Error("The client does not match the server version. The current core version of the client is", version.GetVersion())
return nil, err
}
if _, err := c.Write([]byte(common.Getverifyval(vkey))); err != nil {
return nil, err
}
if s, err := c.ReadFlag(); err != nil {
return nil, err
} else if s == common.VERIFY_EER {
return nil, errors.New(fmt.Sprintf("Validation key %s incorrect", vkey))
}
if _, err := c.Write([]byte(connType)); err != nil {
return nil, err
}
c.SetAlive(tp)
return c, nil
}
//http proxy connection
func NewHttpProxyConn(url *url.URL, remoteAddr string) (net.Conn, error) {
req, err := http.NewRequest("CONNECT", "http://"+remoteAddr, nil)
if err != nil {
return nil, err
}
password, _ := url.User.Password()
req.Header.Set("Authorization", "Basic "+basicAuth(strings.Trim(url.User.Username(), " "), password))
// we make a http proxy request
proxyConn, err := net.Dial("tcp", url.Host)
if err != nil {
return nil, err
}
if err := req.Write(proxyConn); err != nil {
return nil, err
}
res, err := http.ReadResponse(bufio.NewReader(proxyConn), req)
if err != nil {
return nil, err
}
_ = res.Body.Close()
if res.StatusCode != 200 {
return nil, errors.New("Proxy error " + res.Status)
}
return proxyConn, nil
}
//get a basic auth string
func basicAuth(username, password string) string {
auth := username + ":" + password
return base64.StdEncoding.EncodeToString([]byte(auth))
}
func getRemoteAddressFromServer(rAddr string, localConn *net.UDPConn, md5Password, role string, add int) error {
rAddr, err := getNextAddr(rAddr, add)
if err != nil {
logs.Error(err)
return err
}
addr, err := net.ResolveUDPAddr("udp", rAddr)
if err != nil {
return err
}
if _, err := localConn.WriteTo(common.GetWriteStr(md5Password, role), addr); err != nil {
return err
}
return nil
}
func handleP2PUdp(localAddr, rAddr, md5Password, role string) (remoteAddress string, c net.PacketConn, err error) {
localConn, err := newUdpConnByAddr(localAddr)
if err != nil {
return
}
err = getRemoteAddressFromServer(rAddr, localConn, md5Password, role, 0)
if err != nil {
logs.Error(err)
return
}
err = getRemoteAddressFromServer(rAddr, localConn, md5Password, role, 1)
if err != nil {
logs.Error(err)
return
}
err = getRemoteAddressFromServer(rAddr, localConn, md5Password, role, 2)
if err != nil {
logs.Error(err)
return
}
var remoteAddr1, remoteAddr2, remoteAddr3 string
for {
buf := make([]byte, 1024)
if n, addr, er := localConn.ReadFromUDP(buf); er != nil {
err = er
return
} else {
rAddr2, _ := getNextAddr(rAddr, 1)
rAddr3, _ := getNextAddr(rAddr, 2)
switch addr.String() {
case rAddr:
remoteAddr1 = string(buf[:n])
case rAddr2:
remoteAddr2 = string(buf[:n])
case rAddr3:
remoteAddr3 = string(buf[:n])
}
}
if remoteAddr1 != "" && remoteAddr2 != "" && remoteAddr3 != "" {
break
}
}
if remoteAddress, err = sendP2PTestMsg(localConn, remoteAddr1, remoteAddr2, remoteAddr3); err != nil {
return
}
c, err = newUdpConnByAddr(localAddr)
return
}
func sendP2PTestMsg(localConn *net.UDPConn, remoteAddr1, remoteAddr2, remoteAddr3 string) (string, error) {
logs.Trace(remoteAddr3, remoteAddr2, remoteAddr1)
defer localConn.Close()
isClose := false
defer func() { isClose = true }()
interval, err := getAddrInterval(remoteAddr1, remoteAddr2, remoteAddr3)
if err != nil {
return "", err
}
go func() {
addr, err := getNextAddr(remoteAddr3, interval)
if err != nil {
return
}
remoteUdpAddr, err := net.ResolveUDPAddr("udp", addr)
if err != nil {
return
}
logs.Trace("try send test packet to target %s", addr)
ticker := time.NewTicker(time.Millisecond * 500)
defer ticker.Stop()
for {
select {
case <-ticker.C:
if isClose {
return
}
if _, err := localConn.WriteTo([]byte(common.WORK_P2P_CONNECT), remoteUdpAddr); err != nil {
return
}
}
}
}()
if interval != 0 {
ip := common.GetIpByAddr(remoteAddr2)
go func() {
ports := getRandomPortArr(common.GetPortByAddr(remoteAddr3), common.GetPortByAddr(remoteAddr3)+interval*50)
for i := 0; i <= 50; i++ {
go func(port int) {
trueAddress := ip + ":" + strconv.Itoa(port)
logs.Trace("try send test packet to target %s", trueAddress)
remoteUdpAddr, err := net.ResolveUDPAddr("udp", trueAddress)
if err != nil {
return
}
ticker := time.NewTicker(time.Second * 2)
defer ticker.Stop()
for {
select {
case <-ticker.C:
if isClose {
return
}
if _, err := localConn.WriteTo([]byte(common.WORK_P2P_CONNECT), remoteUdpAddr); err != nil {
return
}
}
}
}(ports[i])
time.Sleep(time.Millisecond * 10)
}
}()
}
buf := make([]byte, 10)
for {
localConn.SetReadDeadline(time.Now().Add(time.Second * 10))
n, addr, err := localConn.ReadFromUDP(buf)
localConn.SetReadDeadline(time.Time{})
if err != nil {
break
}
switch string(buf[:n]) {
case common.WORK_P2P_SUCCESS:
for i := 20; i > 0; i-- {
if _, err = localConn.WriteTo([]byte(common.WORK_P2P_END), addr); err != nil {
return "", err
}
}
return addr.String(), nil
case common.WORK_P2P_END:
logs.Trace("Remotely Address %s Reply Packet Successfully Received", addr.String())
return addr.String(), nil
case common.WORK_P2P_CONNECT:
go func() {
for i := 20; i > 0; i-- {
logs.Trace("try send receive success packet to target %s", addr.String())
if _, err = localConn.WriteTo([]byte(common.WORK_P2P_SUCCESS), addr); err != nil {
return
}
time.Sleep(time.Second)
}
}()
default:
continue
}
}
return "", errors.New("connect to the target failed, maybe the nat type is not support p2p")
}
func newUdpConnByAddr(addr string) (*net.UDPConn, error) {
udpAddr, err := net.ResolveUDPAddr("udp", addr)
if err != nil {
return nil, err
}
udpConn, err := net.ListenUDP("udp", udpAddr)
if err != nil {
return nil, err
}
return udpConn, nil
}
func getNextAddr(addr string, n int) (string, error) {
arr := strings.Split(addr, ":")
if len(arr) != 2 {
return "", errors.New(fmt.Sprintf("the format of %s incorrect", addr))
}
if p, err := strconv.Atoi(arr[1]); err != nil {
return "", err
} else {
return arr[0] + ":" + strconv.Itoa(p+n), nil
}
}
func getAddrInterval(addr1, addr2, addr3 string) (int, error) {
arr1 := strings.Split(addr1, ":")
if len(arr1) != 2 {
return 0, errors.New(fmt.Sprintf("the format of %s incorrect", addr1))
}
arr2 := strings.Split(addr2, ":")
if len(arr2) != 2 {
return 0, errors.New(fmt.Sprintf("the format of %s incorrect", addr2))
}
arr3 := strings.Split(addr3, ":")
if len(arr3) != 2 {
return 0, errors.New(fmt.Sprintf("the format of %s incorrect", addr3))
}
p1, err := strconv.Atoi(arr1[1])
if err != nil {
return 0, err
}
p2, err := strconv.Atoi(arr2[1])
if err != nil {
return 0, err
}
p3, err := strconv.Atoi(arr3[1])
if err != nil {
return 0, err
}
interVal := int(math.Floor(math.Min(math.Abs(float64(p3-p2)), math.Abs(float64(p2-p1)))))
if p3-p1 < 0 {
return -interVal, nil
}
return interVal, nil
}
func getRandomPortArr(min, max int) []int {
if min > max {
min, max = max, min
}
addrAddr := make([]int, max-min+1)
for i := min; i <= max; i++ {
addrAddr[max-i] = i
}
rand.Seed(time.Now().UnixNano())
var r, temp int
for i := max - min; i > 0; i-- {
r = rand.Int() % i
temp = addrAddr[i]
addrAddr[i] = addrAddr[r]
addrAddr[r] = temp
}
return addrAddr
}
================================================
FILE: client/health.go
================================================
package client
import (
"container/heap"
"net"
"net/http"
"strings"
"time"
"ehang.io/nps/lib/conn"
"ehang.io/nps/lib/file"
"ehang.io/nps/lib/sheap"
"github.com/astaxie/beego/logs"
"github.com/pkg/errors"
)
var isStart bool
var serverConn *conn.Conn
func heathCheck(healths []*file.Health, c *conn.Conn) bool {
serverConn = c
if isStart {
for _, v := range healths {
v.HealthMap = make(map[string]int)
}
return true
}
isStart = true
h := &sheap.IntHeap{}
for _, v := range healths {
if v.HealthMaxFail > 0 && v.HealthCheckTimeout > 0 && v.HealthCheckInterval > 0 {
v.HealthNextTime = time.Now().Add(time.Duration(v.HealthCheckInterval) * time.Second)
heap.Push(h, v.HealthNextTime.Unix())
v.HealthMap = make(map[string]int)
}
}
go session(healths, h)
return true
}
func session(healths []*file.Health, h *sheap.IntHeap) {
for {
if h.Len() == 0 {
logs.Error("health check error")
break
}
rs := heap.Pop(h).(int64) - time.Now().Unix()
if rs <= 0 {
continue
}
timer := time.NewTimer(time.Duration(rs) * time.Second)
select {
case <-timer.C:
for _, v := range healths {
if v.HealthNextTime.Before(time.Now()) {
v.HealthNextTime = time.Now().Add(time.Duration(v.HealthCheckInterval) * time.Second)
//check
go check(v)
//reset time
heap.Push(h, v.HealthNextTime.Unix())
}
}
}
}
}
// work when just one port and many target
func check(t *file.Health) {
arr := strings.Split(t.HealthCheckTarget, ",")
var err error
var rs *http.Response
for _, v := range arr {
if t.HealthCheckType == "tcp" {
var c net.Conn
c, err = net.DialTimeout("tcp", v, time.Duration(t.HealthCheckTimeout)*time.Second)
if err == nil {
c.Close()
}
} else {
client := &http.Client{}
client.Timeout = time.Duration(t.HealthCheckTimeout) * time.Second
rs, err = client.Get("http://" + v + t.HttpHealthUrl)
if err == nil && rs.StatusCode != 200 {
err = errors.New("status code is not match")
}
}
t.Lock()
if err != nil {
t.HealthMap[v] += 1
} else if t.HealthMap[v] >= t.HealthMaxFail {
//send recovery add
serverConn.SendHealthInfo(v, "1")
t.HealthMap[v] = 0
}
if t.HealthMap[v] > 0 && t.HealthMap[v]%t.HealthMaxFail == 0 {
//send fail remove
serverConn.SendHealthInfo(v, "0")
}
t.Unlock()
}
}
================================================
FILE: client/local.go
================================================
package client
import (
"ehang.io/nps-mux"
"errors"
"net"
"net/http"
"runtime"
"sync"
"time"
"ehang.io/nps/lib/common"
"ehang.io/nps/lib/config"
"ehang.io/nps/lib/conn"
"ehang.io/nps/lib/crypt"
"ehang.io/nps/lib/file"
"ehang.io/nps/server/proxy"
"github.com/astaxie/beego/logs"
"github.com/xtaci/kcp-go"
)
var (
LocalServer []*net.TCPListener
udpConn net.Conn
muxSession *nps_mux.Mux
fileServer []*http.Server
p2pNetBridge *p2pBridge
lock sync.RWMutex
udpConnStatus bool
)
type p2pBridge struct {
}
func (p2pBridge *p2pBridge) SendLinkInfo(clientId int, link *conn.Link, t *file.Tunnel) (target net.Conn, err error) {
for i := 0; muxSession == nil; i++ {
if i >= 20 {
err = errors.New("p2pBridge:too many times to get muxSession")
logs.Error(err)
return
}
runtime.Gosched() // waiting for another goroutine establish the mux connection
}
nowConn, err := muxSession.NewConn()
if err != nil {
udpConn = nil
return nil, err
}
if _, err := conn.NewConn(nowConn).SendInfo(link, ""); err != nil {
udpConnStatus = false
return nil, err
}
return nowConn, nil
}
func CloseLocalServer() {
for _, v := range LocalServer {
v.Close()
}
for _, v := range fileServer {
v.Close()
}
}
func startLocalFileServer(config *config.CommonConfig, t *file.Tunnel, vkey string) {
remoteConn, err := NewConn(config.Tp, vkey, config.Server, common.WORK_FILE, config.ProxyUrl)
if err != nil {
logs.Error("Local connection server failed ", err.Error())
return
}
srv := &http.Server{
Handler: http.StripPrefix(t.StripPre, http.FileServer(http.Dir(t.LocalPath))),
}
logs.Info("start local file system, local path %s, strip prefix %s ,remote port %s ", t.LocalPath, t.StripPre, t.Ports)
fileServer = append(fileServer, srv)
listener := nps_mux.NewMux(remoteConn.Conn, common.CONN_TCP, config.DisconnectTime)
logs.Error(srv.Serve(listener))
}
func StartLocalServer(l *config.LocalServer, config *config.CommonConfig) error {
if l.Type != "secret" {
go handleUdpMonitor(config, l)
}
task := &file.Tunnel{
Port: l.Port,
ServerIp: "0.0.0.0",
Status: true,
Client: &file.Client{
Cnf: &file.Config{
U: "",
P: "",
Compress: config.Client.Cnf.Compress,
},
Status: true,
RateLimit: 0,
Flow: &file.Flow{},
},
Flow: &file.Flow{},
Target: &file.Target{},
}
switch l.Type {
case "p2ps":
logs.Info("successful start-up of local socks5 monitoring, port", l.Port)
return proxy.NewSock5ModeServer(p2pNetBridge, task).Start()
case "p2pt":
logs.Info("successful start-up of local tcp trans monitoring, port", l.Port)
return proxy.NewTunnelModeServer(proxy.HandleTrans, p2pNetBridge, task).Start()
case "p2p", "secret":
listener, err := net.ListenTCP("tcp", &net.TCPAddr{net.ParseIP("0.0.0.0"), l.Port, ""})
if err != nil {
logs.Error("local listener startup failed port %d, error %s", l.Port, err.Error())
return err
}
LocalServer = append(LocalServer, listener)
logs.Info("successful start-up of local tcp monitoring, port", l.Port)
conn.Accept(listener, func(c net.Conn) {
logs.Trace("new %s connection", l.Type)
if l.Type == "secret" {
handleSecret(c, config, l)
} else if l.Type == "p2p" {
handleP2PVisitor(c, config, l)
}
})
}
return nil
}
func handleUdpMonitor(config *config.CommonConfig, l *config.LocalServer) {
ticker := time.NewTicker(time.Second * 1)
defer ticker.Stop()
for {
select {
case <-ticker.C:
if !udpConnStatus {
udpConn = nil
tmpConn, err := common.GetLocalUdpAddr()
if err != nil {
logs.Error(err)
return
}
for i := 0; i < 10; i++ {
logs.Notice("try to connect to the server", i+1)
newUdpConn(tmpConn.LocalAddr().String(), config, l)
if udpConn != nil {
udpConnStatus = true
break
}
}
}
}
}
}
func handleSecret(localTcpConn net.Conn, config *config.CommonConfig, l *config.LocalServer) {
remoteConn, err := NewConn(config.Tp, config.VKey, config.Server, common.WORK_SECRET, config.ProxyUrl)
if err != nil {
logs.Error("Local connection server failed ", err.Error())
return
}
if _, err := remoteConn.Write([]byte(crypt.Md5(l.Password))); err != nil {
logs.Error("Local connection server failed ", err.Error())
return
}
conn.CopyWaitGroup(remoteConn.Conn, localTcpConn, false, false, nil, nil, false, nil)
}
func handleP2PVisitor(localTcpConn net.Conn, config *config.CommonConfig, l *config.LocalServer) {
if udpConn == nil {
logs.Notice("new conn, P2P can not penetrate successfully, traffic will be transferred through the server")
handleSecret(localTcpConn, config, l)
return
}
logs.Trace("start trying to connect with the server")
//TODO just support compress now because there is not tls file in client packages
link := conn.NewLink(common.CONN_TCP, l.Target, false, config.Client.Cnf.Compress, localTcpConn.LocalAddr().String(), false)
if target, err := p2pNetBridge.SendLinkInfo(0, link, nil); err != nil {
logs.Error(err)
udpConnStatus = false
return
} else {
conn.CopyWaitGroup(target, localTcpConn, false, config.Client.Cnf.Compress, nil, nil, false, nil)
}
}
func newUdpConn(localAddr string, config *config.CommonConfig, l *config.LocalServer) {
lock.Lock()
defer lock.Unlock()
remoteConn, err := NewConn(config.Tp, config.VKey, config.Server, common.WORK_P2P, config.ProxyUrl)
if err != nil {
logs.Error("Local connection server failed ", err.Error())
return
}
if _, err := remoteConn.Write([]byte(crypt.Md5(l.Password))); err != nil {
logs.Error("Local connection server failed ", err.Error())
return
}
var rAddr []byte
//读取服务端地址、密钥 继续做处理
if rAddr, err = remoteConn.GetShortLenContent(); err != nil {
logs.Error(err)
return
}
var localConn net.PacketConn
var remoteAddress string
if remoteAddress, localConn, err = handleP2PUdp(localAddr, string(rAddr), crypt.Md5(l.Password), common.WORK_P2P_VISITOR); err != nil {
logs.Error(err)
return
}
udpTunnel, err := kcp.NewConn(remoteAddress, nil, 150, 3, localConn)
if err != nil || udpTunnel == nil {
logs.Warn(err)
return
}
logs.Trace("successful create a connection with server", remoteAddress)
conn.SetUdpSession(udpTunnel)
udpConn = udpTunnel
muxSession = nps_mux.NewMux(udpConn, "kcp", config.DisconnectTime)
p2pNetBridge = &p2pBridge{}
}
================================================
FILE: client/register.go
================================================
package client
import (
"encoding/binary"
"log"
"os"
"ehang.io/nps/lib/common"
)
func RegisterLocalIp(server string, vKey string, tp string, proxyUrl string, hour int) {
c, err := NewConn(tp, vKey, server, common.WORK_REGISTER, proxyUrl)
if err != nil {
log.Fatalln(err)
}
if err := binary.Write(c, binary.LittleEndian, int32(hour)); err != nil {
log.Fatalln(err)
}
log.Printf("Successful ip registration for local public network, the validity period is %d hours.", hour)
os.Exit(0)
}
================================================
FILE: conf/clients.json
================================================
================================================
FILE: conf/hosts.json
================================================
================================================
FILE: conf/multi_account.conf
================================================
# key -> user | value -> pwd
npc=npc.pwd
================================================
FILE: conf/npc.conf
================================================
[common]
server_addr=127.0.0.1:8024
conn_type=tcp
vkey=123
auto_reconnection=true
max_conn=1000
flow_limit=1000
rate_limit=1000
basic_username=11
basic_password=3
web_username=user
web_password=1234
crypt=true
compress=true
#pprof_addr=0.0.0.0:9999
disconnect_timeout=60
[health_check_test1]
health_check_timeout=1
health_check_max_failed=3
health_check_interval=1
health_http_url=/
health_check_type=http
health_check_target=127.0.0.1:8083,127.0.0.1:8082
[health_check_test2]
health_check_timeout=1
health_check_max_failed=3
health_check_interval=1
health_check_type=tcp
health_check_target=127.0.0.1:8083,127.0.0.1:8082
[web]
host=c.o.com
target_addr=127.0.0.1:8083,127.0.0.1:8082
[tcp]
mode=tcp
target_addr=127.0.0.1:8080
server_port=10000
[socks5]
mode=socks5
server_port=19009
multi_account=multi_account.conf
[file]
mode=file
server_port=19008
local_path=/Users/liuhe/Downloads
strip_pre=/web/
[http]
mode=httpProxy
server_port=19004
[udp]
mode=udp
server_port=12253
target_addr=114.114.114.114:53
[ssh_secret]
mode=secret
password=ssh2
target_addr=123.206.77.88:22
[ssh_p2p]
mode=p2p
password=ssh3
[secret_ssh]
local_port=2001
password=ssh2
[p2p_ssh]
local_port=2002
password=ssh3
target_addr=123.206.77.88:22
================================================
FILE: conf/nps.conf
================================================
appname = nps
#Boot mode(dev|pro)
runmode = dev
#HTTP(S) proxy port, no startup if empty
http_proxy_ip=0.0.0.0
http_proxy_port=80
https_proxy_port=443
https_just_proxy=true
#default https certificate setting
https_default_cert_file=conf/server.pem
https_default_key_file=conf/server.key
##bridge
bridge_type=tcp
bridge_port=8024
bridge_ip=0.0.0.0
# Public password, which clients can use to connect to the server
# After the connection, the server will be able to open relevant ports and parse related domain names according to its own configuration file.
public_vkey=123
#Traffic data persistence interval(minute)
#Ignorance means no persistence
#flow_store_interval=1
# log level LevelEmergency->0 LevelAlert->1 LevelCritical->2 LevelError->3 LevelWarning->4 LevelNotice->5 LevelInformational->6 LevelDebug->7
log_level=7
#log_path=nps.log
#Whether to restrict IP access, true or false or ignore
#ip_limit=true
#p2p
#p2p_ip=127.0.0.1
#p2p_port=6000
#web
web_host=a.o.com
web_username=admin
web_password=123
web_port = 8080
web_ip=0.0.0.0
web_base_url=
web_open_ssl=false
web_cert_file=conf/server.pem
web_key_file=conf/server.key
# if web under proxy use sub path. like http://host/nps need this.
#web_base_url=/nps
#Web API unauthenticated IP address(the len of auth_crypt_key must be 16)
#Remove comments if needed
#auth_key=test
auth_crypt_key =1234567812345678
#allow_ports=9001-9009,10001,11000-12000
#Web management multi-user login
allow_user_login=false
allow_user_register=false
allow_user_change_username=false
#extension
allow_flow_limit=false
allow_rate_limit=false
allow_tunnel_num_limit=false
allow_local_proxy=false
allow_connection_num_limit=false
allow_multi_ip=false
system_info_display=false
#cache
http_cache=false
http_cache_length=100
#get origin ip
http_add_origin_header=false
#pprof debug options
#pprof_ip=0.0.0.0
#pprof_port=9999
#client disconnect timeout
disconnect_timeout=60
================================================
FILE: conf/server.key
================================================
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA2MVLOHvgU8FCp6LgQrPfaWcGygrsRk7TL9hbT8MxbCRUSLV7
Lbt3q5Knz8eTN4NWmwE6L5glOcH2x3Hnn+hPjbvgq35XBBIccAm0cYYKqoKkikeK
FZM0Gp/WhSrhJ4laTyQqyleIFKpwD9kHDiC/sxjGDhSFmHKhhAnsQIRm2tppFXX0
aAMqJEm88jzk1BN2QtKjEAn1u8v1+QW1KP3WuzdXH4L7hhMll66/KIm6Hfs2FRHQ
pRUWqZeJY4q79NW5p5f+siGwOsGpxb/p11pM+0xnCH3UIFbm3zCTzP4sLvkfFGAe
yAHsAwmaP8dJxh40ej3NN8uNiNvt8nw2Vb/1LwIDAQABAoIBAD40x/RKoEKIyE8B
D6g0pB1EQo+CePFoN3SYewO1uR4WgtVmtxWVoa7r5BpdZGLe3uCWhpMX7z7W6bGs
f1LFQOckjkHIfMIfTGfecRjO5Yqu+Pbxtq+gUah+S/plJr3IzdC+SUVNvzBnBMeX
eU3Vmg2UQ2nQ+9GWu8D/c/vDwxx0X8oQ2G8QaxX0tUurlSMNA3M7xySwEvhx54fO
UrDF3Q4yF48eA4butxVLFWf3cnlY+nR8uYd2vKfmp689/8C6kkfoM9igB78e93sm
uDM2eRLm4kU5WLl301T42n6AF7w8J0MhLLVOIeLs4l5gZPa3uKvYFmuHQao7e/5R
U/jHKrECgYEA8alPXuxFSVOvdhIsSN//Frj9CdExVdYmaLkt/2LO4FMnOaWh1xh7
5iCY1bJT8D9dhfbqRg3qW2oguZD8gu04R8fTRegQ89qmAIwsEYqVf9salR41lZU4
Rc+5yc7O11WIe9Lzu+ONFBFkAh3UFMR4zVZ/JhKIG/P5Srm7SUdKW2cCgYEA5aHo
x2LR+yKhjkrBzHG3Qrfy1PtlYHjOpYYAKHQcBFuiG08W3CK/vkYl+mhv0uyhT7mn
q6NDqrpZPRnDlOoEqgRS1X/QWKN6Pgd4HNLIawvp0vK9jYXDPcAXFzVthXCIwFcn
3a3m4cHiuLdRNOHkydiHQyTOF6eEneN07TDvwvkCgYEApzOd1u9igPmFzQuF2GYi
+HXFnaU/nUQuDwcQ7EJRIKRn31raPxiRoQesty5LJU6yRp4wOYgnPliPi9Tk4TGA
XynC4/tMv2vorzhMxVY9Wdke602bhYNZC/RNd3O/aP2lEQdD3Bv04I2nxE8fDb9i
VbAjCRSJV83WDf2zt1+78sECgYEAzezjRiKdcZu9y0/I+WEk2cUCE/MaF2he0FsZ
uy1cjp/qAJltQ5452xUnK6cKWNlxU4CHF0mC/hC8xCldliZCZoEYE3PaUBLSJdwm
35o6tpxpZI3gZJCG5NJlIp/8BkVDrVC7ZHV17hAkFEf4n/bPaB8wNYtE8jt8luaK
TcarzGkCgYBn2alN0RLN2PHDurraFZB6GuCvh/arEjSCY3SDFQPF10CVjTDV7sx3
eqJkwJ81syTmfJwZIceWbOFGgsuSx37UrQAVlHZSvzeqEg9dA5HqSoOACyidJI7j
RG2+HB+KpsIZjGgLrEM4i7VOpYUDRdaouIXngFq/t9HNT+MDck5/Lw==
-----END RSA PRIVATE KEY-----
================================================
FILE: conf/server.pem
================================================
-----BEGIN CERTIFICATE-----
MIIDtTCCAp2gAwIBAgIJAPXRSiP0Fs7sMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
aWRnaXRzIFB0eSBMdGQwHhcNMTcxMTA3MDg1MzQ2WhcNMjcxMTA1MDg1MzQ2WjBF
MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
CgKCAQEA2MVLOHvgU8FCp6LgQrPfaWcGygrsRk7TL9hbT8MxbCRUSLV7Lbt3q5Kn
z8eTN4NWmwE6L5glOcH2x3Hnn+hPjbvgq35XBBIccAm0cYYKqoKkikeKFZM0Gp/W
hSrhJ4laTyQqyleIFKpwD9kHDiC/sxjGDhSFmHKhhAnsQIRm2tppFXX0aAMqJEm8
8jzk1BN2QtKjEAn1u8v1+QW1KP3WuzdXH4L7hhMll66/KIm6Hfs2FRHQpRUWqZeJ
Y4q79NW5p5f+siGwOsGpxb/p11pM+0xnCH3UIFbm3zCTzP4sLvkfFGAeyAHsAwma
P8dJxh40ej3NN8uNiNvt8nw2Vb/1LwIDAQABo4GnMIGkMB0GA1UdDgQWBBQdPc0R
a8alY6Ab7voidkTGaH4PxzB1BgNVHSMEbjBsgBQdPc0Ra8alY6Ab7voidkTGaH4P
x6FJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNV
BAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAPXRSiP0Fs7sMAwGA1UdEwQF
MAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAH1IZNkjuvt2nZPzXsuiVNyCE1vm346z
naE0Uzt3aseAN9m/iiB8mLz+ryvWc2aFMX5lTdsHdm2rqmqBCBXeRwTLf4OeHIju
ZQW6makWt6PxANEo6gbdPbQXbS420ssUhnR2irIH1SdI31iikVFPdiS0baRRE/gS
+440M1jOOOnKm0Qin92ejsshmji/0qaD2+6D5TNw4HmIZaFTBw+kfjxCL6trfeBn
4fT0RJ121V3G3+AtG5sWQ93B3pCg+jtD+fGKkNSLhphq84bD1Zv7l73QGOoylkEn
Sc0ajTLOXFBb83yRdlgV3Da95jH9rDZ4jSod48m+KemoZTDQw0vSwAU=
-----END CERTIFICATE-----
================================================
FILE: conf/tasks.json
================================================
================================================
FILE: docs/.nojekyll
================================================
================================================
FILE: docs/README.md
================================================
# nps
 
[](https://gitter.im/cnlh-nps/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
[](https://travis-ci.org/cnlh/nps)
nps是一款轻量级、高性能、功能强大的**内网穿透**代理服务器。目前支持**tcp、udp流量转发**,可支持任何**tcp、udp**上层协议(访问内网网站、本地支付接口调试、ssh访问、远程桌面,内网dns解析等等……),此外还**支持内网http代理、内网socks5代理**、**p2p等**,并带有功能强大的web管理端。
## 背景

1. 做微信公众号开发、小程序开发等----> 域名代理模式
2. 想在外网通过ssh连接内网的机器,做云服务器到内网服务器端口的映射,----> tcp代理模式
3. 在非内网环境下使用内网dns,或者需要通过udp访问内网机器等----> udp代理模式
4. 在外网使用HTTP代理访问内网站点----> http代理模式
5. 搭建一个内网穿透ss,在外网如同使用内网vpn一样访问内网资源或者设备----> socks5代理模式
================================================
FILE: docs/_coverpage.md
================================================

# NPS <small>0.26.10</small>
> 一款轻量级、高性能、功能强大的内网穿透代理服务器
- 几乎支持所有协议
- 支持内网http代理、内网socks5代理、p2p等
- 简洁但功能强大的WEB管理界面
- 支持服务端、客户端同时控制
- 扩展功能强大
- 全平台兼容,一键注册为服务
[GitHub](https://github.com/ehang-io/nps/)
[开始使用](#nps)
================================================
FILE: docs/_navbar.md
================================================
* [](https://github.com/ehang-io/nps/stargazers)
* [](https://github.com/ehang-io/nps/network)
================================================
FILE: docs/_sidebar.md
================================================
* 入门
* [安装](install.md)
* [启动](run.md)
* [使用示例](example.md)
* 服务端
* [介绍](introduction.md)
* [使用](nps_use.md)
* [配置文件](server_config.md)
* [增强功能](nps_extend.md)
* 客户端
* [基本使用](use.md)
* [增强功能](npc_extend.md)
* 扩展
* [功能](feature.md)
* [说明](description.md)
* [web api](api.md)
* [sdk](npc_sdk.md)
* 其他
* [FAQ](faq.md)
* [贡献](contribute.md)
* [捐助](donate.md)
* [致谢](thanks.md)
* [交流](discuss.md)
================================================
FILE: docs/api.md
================================================
# web api
需要开启请先去掉`nps.conf`中`auth_key`的注释并配置一个合适的密钥
## webAPI验证说明
- 采用auth_key的验证方式
- 在提交的每个请求后面附带两个参数,`auth_key` 和`timestamp`
```
auth_key的生成方式为:md5(配置文件中的auth_key+当前时间戳)
```
```
timestamp为当前时间戳
```
```
curl --request POST \
--url http://127.0.0.1:8080/client/list \
--data 'auth_key=2a0000d9229e7dbcf79dd0f5e04bb084×tamp=1553045344&start=0&limit=10'
```
**注意:** 为保证安全,时间戳的有效范围为20秒内,所以每次提交请求必须重新生成。
## 获取服务端时间
由于服务端与api请求的客户端时间差异不能太大,所以提供了一个可以获取服务端时间的接口
```
POST /auth/gettime
```
## 获取服务端authKey
如果想获取authKey,服务端提供获取authKey的接口
```
POST /auth/getauthkey
```
将返回加密后的authKey,采用aes cbc加密,请使用与服务端配置文件中cryptKey相同的密钥进行解密
**注意:** nps配置文件中`auth_crypt_key`需为16位
- 解密密钥长度128
- 偏移量与密钥相同
- 补码方式pkcs5padding
- 解密串编码方式 十六进制
## 详细文档
- **[详见](webapi.md)** (感谢@avengexyz)
================================================
FILE: docs/contribute.md
================================================
# 贡献
- 如果遇到bug可以直接提交至dev分支
- 使用遇到问题可以通过issues反馈
- 项目处于开发阶段,还有很多待完善的地方,如果可以贡献代码,请提交 PR 至 dev 分支
- 如果有新的功能特性反馈,可以通过issues或者qq群反馈
================================================
FILE: docs/description.md
================================================
# 说明
## 获取用户真实ip
如需使用需要在`nps.conf`中设置`http_add_origin_header=true`
在域名代理模式中,可以通过request请求 header 中的 X-Forwarded-For 和 X-Real-IP 来获取用户真实 IP。
**本代理前会在每一个http(s)请求中添加了这两个 header。**
## 热更新支持
对于绝大多数配置,在web管理中的修改将实时使用,无需重启客户端或者服务端
## 客户端地址显示
在web管理中将显示客户端的连接地址
## 流量统计
可统计显示每个代理使用的流量,由于压缩和加密等原因,会和实际环境中的略有差异
## 当前客户端带宽
可统计每个客户端当前的带宽,可能和实际有一定差异,仅供参考。
## 客户端与服务端版本对比
为了程序正常运行,客户端与服务端的核心版本必须一致,否则将导致客户端无法成功连接致服务端。
## Linux系统限制
默认情况下linux对连接数量有限制,对于性能好的机器完全可以调整内核参数以处理更多的连接。
`tcp_max_syn_backlog` `somaxconn`
酌情调整参数,增强网络性能
## web管理保护
当一个ip连续登陆失败次数超过10次,将在一分钟内禁止该ip再次尝试。
================================================
FILE: docs/discuss.md
================================================
# 交流群

================================================
FILE: docs/donate.md
================================================
# 捐助
如果您觉得nps对你有帮助,欢迎给予我们一定捐助,也是帮助nps更好的发展。
## 支付宝

## 微信

================================================
FILE: docs/example.md
================================================
# 使用示例
## 统一准备工作(必做)
- 开启服务端,假设公网服务器ip为1.1.1.1,配置文件中`bridge_port`为8024,配置文件中`web_port`为8080
- 访问1.1.1.1:8080
- 在客户端管理中创建一个客户端,记录下验证密钥
- 内网客户端运行(windows使用cmd运行加.exe)
```shell
./npc -server=1.1.1.1:8024 -vkey=客户端的密钥
```
**注意:运行服务端后,请确保能从客户端设备上正常访问配置文件中所配置的`bridge_port`端口,telnet,netcat这类的来检查**
## 域名解析
**适用范围:** 小程序开发、微信公众号开发、产品演示
**注意:域名解析模式为http反向代理,不是dns服务器,在web上能够轻松灵活配置**
**假设场景:**
- 有一个域名proxy.com,有一台公网机器ip为1.1.1.1
- 两个内网开发站点127.0.0.1:81,127.0.0.1:82
- 想通过(http|https://)a.proxy.com访问127.0.0.1:81,通过(http|https://)b.proxy.com访问127.0.0.1:82
**使用步骤**
- 将*.proxy.com解析到公网服务器1.1.1.1
- 点击刚才创建的客户端的域名管理,添加两条规则规则:1、域名:`a.proxy.com`,内网目标:`127.0.0.1:81`,2、域名:`b.proxy.com`,内网目标:`127.0.0.1:82`
现在访问(http|https://)`a.proxy.com`,`b.proxy.com`即可成功
**https:** 如需使用https请进行相关配置,详见 [使用https](/nps_extend?id=使用https)
## tcp隧道
**适用范围:** ssh、远程桌面等tcp连接场景
**假设场景:**
想通过访问公网服务器1.1.1.1的8001端口,连接内网机器10.1.50.101的22端口,实现ssh连接
**使用步骤**
- 在刚才创建的客户端隧道管理中添加一条tcp隧道,填写监听的端口(8001)、内网目标ip和目标端口(10.1.50.101:22),保存。
- 访问公网服务器ip(1.1.1.1),填写的监听端口(8001),相当于访问内网ip(10.1.50.101):目标端口(22),例如:`ssh -p 8001 root@1.1.1.1`
## udp隧道
**适用范围:** 内网dns解析等udp连接场景
**假设场景:**
内网有一台dns(10.1.50.102:53),在非内网环境下想使用该dns,公网服务器为1.1.1.1
**使用步骤**
- 在刚才创建的客户端的隧道管理中添加一条udp隧道,填写监听的端口(53)、内网目标ip和目标端口(10.1.50.102:53),保存。
- 修改需要使用的dns地址为1.1.1.1,则相当于使用10.1.50.102作为dns服务器
## socks5代理
**适用范围:** 在外网环境下如同使用vpn一样访问内网设备或者资源
**假设场景:**
想将公网服务器1.1.1.1的8003端口作为socks5代理,达到访问内网任意设备或者资源的效果
**使用步骤**
- 在刚才创建的客户端隧道管理中添加一条socks5代理,填写监听的端口(8003),保存。
- 在外网环境的本机配置socks5代理(例如使用proxifier进行全局代理),ip为公网服务器ip(1.1.1.1),端口为填写的监听端口(8003),即可畅享内网了
**注意**
经过socks5代理,当收到socks5数据包时socket已经是accept状态。表现是扫描端口全open,建立连接后短时间关闭。若想同内网表现一致,建议远程连接一台设备。
## http正向代理
**适用范围:** 在外网环境下使用http正向代理访问内网站点
**假设场景:**
想将公网服务器1.1.1.1的8004端口作为http代理,访问内网网站
**使用步骤**
- 在刚才创建的客户端隧道管理中添加一条http代理,填写监听的端口(8004),保存。
- 在外网环境的本机配置http代理,ip为公网服务器ip(1.1.1.1),端口为填写的监听端口(8004),即可访问了
**注意:对于私密代理与p2p,除了统一配置的客户端和服务端,还需要一个客户端作为访问端提供一个端口来访问**
## 私密代理
**适用范围:** 无需占用多余的端口、安全性要求较高可以防止其他人连接的tcp服务,例如ssh。
**假设场景:**
无需新增多的端口实现访问内网服务器10.1.50.2的22端口
**使用步骤**
- 在刚才创建的客户端中添加一条私密代理,并设置唯一密钥secrettest和内网目标10.1.50.2:22
- 在需要连接ssh的机器上以执行命令
```
./npc -server=1.1.1.1:8024 -vkey=vkey -type=tcp -password=secrettest -local_type=secret
```
如需指定本地端口可加参数`-local_port=xx`,默认为2000
**注意:** password为web管理上添加的唯一密钥,具体命令可查看web管理上的命令提示
假设10.1.50.2用户名为root,现在执行`ssh -p 2000 root@127.0.0.1`即可访问ssh
## p2p服务
**适用范围:** 大流量传输场景,流量不经过公网服务器,但是由于p2p穿透和nat类型关系较大,不保证100%成功,支持大部分nat类型。[nat类型检测](/npc_extend?id=nat类型检测)
**假设场景:**
想通过访问使用端机器(访问端,也就是本机)的2000端口---->访问到内网机器 10.2.50.2的22端口
**使用步骤**
- 在`nps.conf`中设置`p2p_ip`(nps服务器ip)和`p2p_port`(nps服务器udp端口)
> 注:若 `p2p_port` 设置为6000,请在防火墙开放6000~6002(额外添加2个端口)udp端口
- 在刚才刚才创建的客户端中添加一条p2p代理,并设置唯一密钥p2pssh
- 在使用端机器(本机)执行命令
```
./npc -server=1.1.1.1:8024 -vkey=123 -password=p2pssh -target=10.2.50.2:22
```
如需指定本地端口可加参数`-local_port=xx`,默认为2000
**注意:** password为web管理上添加的唯一密钥,具体命令可查看web管理上的命令提示
假设内网机器为10.2.50.2的ssh用户名为root,现在在本机上执行`ssh -p 2000 root@127.0.0.1`即可访问机器2的ssh,如果是网站在浏览器访问127.0.0.1:2000端口即可。
================================================
FILE: docs/faq.md
================================================
# FAQ
- 服务端无法启动
```
服务端默认配置启用了8024,8080,80,443端口,端口冲突无法启动,请修改配置
```
- 客户端无法连接服务端
```
请检查配置文件中的所有端口是否在安全组,防火墙放行
请检查vkey是否对应
请检查版本是否对应
```
- 服务端配置文件修改无效
```
install 之后,Linux 配置文件在 /etc/nps
```
- p2p穿透失败 [p2p服务](https://ehang-io.github.io/nps/#/example?id=p2p%e6%9c%8d%e5%8a%a1)
```
双方nat类型都是Symmetric Nat一定不成功,建议先查看nat类型。请按照文档操作(标题上有超链接)
```
================================================
FILE: docs/feature.md
================================================
# 扩展功能
## 缓存支持
对于web站点来说,一些静态文件往往消耗更大的流量,且在内网穿透中,静态文件还需到客户端获取一次,这将导致更大的流量消耗。nps在域名解析代理中支持对静态文件进行缓存。
即假设一个站点有a.css,nps将只需从npc客户端读取一次该文件,然后把该文件的内容放在内存中,下一次将不再对npc客户端进行请求而直接返回内存中的对应内容。该功能默认是关闭的,如需开启请在`nps.conf`中设置`http_cache=true`,并设置`http_cache_length`(缓存文件的个数,消耗内存,不宜过大,0表示不限制个数)
## 数据压缩支持
由于是内网穿透,内网客户端与服务端之间的隧道存在大量的数据交换,为节省流量,加快传输速度,由此本程序支持SNNAPY形式的压缩。
- 所有模式均支持数据压缩
- 在web管理或客户端配置文件中设置
## 加密传输
如果公司内网防火墙对外网访问进行了流量识别与屏蔽,例如禁止了ssh协议等,通过设置 配置文件,将服务端与客户端之间的通信内容加密传输,将会有效防止流量被拦截。
- nps现在默认每次启动时随机生成tls证书,用于加密传输
## 站点保护
域名代理模式所有客户端共用一个http服务端口,在知道域名后任何人都可访问,一些开发或者测试环境需要保密,所以可以设置用户名和密码,nps将通过 Http Basic Auth 来保护,访问时需要输入正确的用户名和密码。
- 在web管理或客户端配置文件中设置
## host修改
由于内网站点需要的host可能与公网域名不一致,域名代理支持host修改功能,即修改request的header中的host字段。
**使用方法:在web管理中设置**
## 自定义header
支持对header进行新增或者修改,以配合服务的需要
## 404页面配置
支持域名解析模式的自定义404页面,修改/web/static/page/error.html中内容即可,暂不支持静态文件等内容
## 流量限制
支持客户端级流量限制,当该客户端入口流量与出口流量达到设定的总量后会拒绝服务
,域名代理会返回404页面,其他代理会拒绝连接,使用该功能需要在`nps.conf`中设置`allow_flow_limit`,默认是关闭的。
## 带宽限制
支持客户端级带宽限制,带宽计算方式为入口和出口总和,权重均衡,使用该功能需要在`nps.conf`中设置`allow_rate_limit`,默认是关闭的。
## 负载均衡
本代理支持域名解析模式和tcp代理的负载均衡,在web域名添加或者编辑中内网目标分行填写多个目标即可实现轮训级别的负载均衡
## 端口白名单
为了防止服务端上的端口被滥用,可在nps.conf中配置allow_ports限制可开启的端口,忽略或者不填表示端口不受限制,格式:
```ini
allow_ports=9001-9009,10001,11000-12000
```
## 端口范围映射
当客户端以配置文件的方式启动时,可以将本地的端口进行范围映射,仅支持tcp和udp模式,例如:
```ini
[tcp]
mode=tcp
server_port=9001-9009,10001,11000-12000
target_port=8001-8009,10002,13000-14000
```
逗号分隔,可单个或者范围,注意上下端口的对应关系,无法一一对应将不能成功
## 端口范围映射到其他机器
```ini
[tcp]
mode=tcp
server_port=9001-9009,10001,11000-12000
target_port=8001-8009,10002,13000-14000
target_ip=10.1.50.2
```
填写target_ip后则表示映射的该地址机器的端口,忽略则便是映射本地127.0.0.1,仅范围映射时有效
## KCP协议支持
在网络质量非常好的情况下,例如专线,内网,可以开启略微降低延迟。如需使用可在nps.conf中修改`bridge_type`为kcp
,设置后本代理将开启udp端口(`bridge_port`)
注意:当服务端为kcp时,客户端连接时也需要使用相同配置,无配置文件模式加上参数type=kcp,配置文件模式在配置文件中设置tp=kcp
## 域名泛解析
支持域名泛解析,例如将host设置为*.proxy.com,a.proxy.com、b.proxy.com等都将解析到同一目标,在web管理中或客户端配置文件中将host设置为此格式即可。
## URL路由
本代理支持根据URL将同一域名转发到不同的内网服务器,可在web中或客户端配置文件中设置,此参数也可忽略,例如在客户端配置文件中
```ini
[web1]
host=a.proxy.com
target_addr=127.0.0.1:7001
location=/test
[web2]
host=a.proxy.com
target_addr=127.0.0.1:7002
location=/static
```
对于`a.proxy.com/test`将转发到`web1`,对于`a.proxy.com/static`将转发到`web2`
## 限制ip访问
如果将一些危险性高的端口例如ssh端口暴露在公网上,可能会带来一些风险,本代理支持限制ip访问。
**使用方法:** 在配置文件nps.conf中设置`ip_limit`=true,设置后仅通过注册的ip方可访问。
**ip注册**:
**方式一:**
在需要访问的机器上,运行客户端
```
./npc register -server=ip:port -vkey=公钥或客户端密钥 time=2
```
time为有效小时数,例如time=2,在当前时间后的两小时内,本机公网ip都可以访问nps代理.
**方式二:**
此外nps的web登陆也可提供验证的功能,成功登陆nps web admin后将自动为登陆的ip注册两小时的允许访问权限。
**注意:** 本机公网ip并不是一成不变的,请自行注意有效期的设置,同时同一网络下,多人也可能是在公用同一个公网ip。
## 客户端最大连接数
为防止恶意大量长连接,影响服务端程序的稳定性,可以在web或客户端配置文件中为每个客户端设置最大连接数。该功能针对`socks5`、`http正向代理`、`域名代理`、`tcp代理`、`udp代理`、`私密代理`生效,使用该功能需要在`nps.conf`中设置`allow_connection_num_limit=true`,默认是关闭的。
## 客户端最大隧道数限制
nps支持对客户端的隧道数量进行限制,该功能默认是关闭的,如需开启,请在`nps.conf`中设置`allow_tunnel_num_limit=true`。
## 端口复用
在一些严格的网络环境中,对端口的个数等限制较大,nps支持强大端口复用功能。将`bridge_port`、 `http_proxy_port`、 `https_proxy_port` 、`web_port`都设置为同一端口,也能正常使用。
- 使用时将需要复用的端口设置为与`bridge_port`一致即可,将自动识别。
- 如需将web管理的端口也复用,需要配置`web_host`也就是一个二级域名以便区分
## 多路复用
nps主要通信默认基于多路复用,无需开启。
多路复用基于TCP滑动窗口原理设计,动态计算延迟以及带宽来算出应该往网络管道中打入的流量。
由于主要通信大多采用TCP协议,并无法探测其实时丢包情况,对于产生丢包重传的情况,采用较大的宽容度,
5分钟的等待时间,超时将会关闭当前隧道连接并重新建立,这将会抛弃当前所有的连接。
在Linux上,可以通过调节内核参数来适应不同应用场景。
对于需求大带宽又有一定的丢包的场景,可以保持默认参数不变,尽可能少抛弃连接
高并发下可根据[Linux系统限制](## Linux系统限制) 调整
对于延迟敏感而又有一定丢包的场景,可以适当调整TCP重传次数
`tcp_syn_retries`, `tcp_retries1`, `tcp_retries2`
高并发同上
nps会在系统主动关闭连接的时候拿到报错,进而重新建立隧道连接
## 环境变量渲染
npc支持环境变量渲染以适应在某些特殊场景下的要求。
**在无配置文件启动模式下:**
设置环境变量
```
export NPC_SERVER_ADDR=1.1.1.1:8024
export NPC_SERVER_VKEY=xxxxx
```
直接执行./npc即可运行
**在配置文件启动模式下:**
```ini
[common]
server_addr={{.NPC_SERVER_ADDR}}
conn_type=tcp
vkey={{.NPC_SERVER_VKEY}}
auto_reconnection=true
[web]
host={{.NPC_WEB_HOST}}
target_addr={{.NPC_WEB_TARGET}}
```
在配置文件中填入相应的环境变量名称,npc将自动进行渲染配置文件替换环境变量
## 健康检查
当客户端以配置文件模式启动时,支持多节点的健康检查。配置示例如下
```ini
[health_check_test1]
health_check_timeout=1
health_check_max_failed=3
health_check_interval=1
health_http_url=/
health_check_type=http
health_check_target=127.0.0.1:8083,127.0.0.1:8082
[health_check_test2]
health_check_timeout=1
health_check_max_failed=3
health_check_interval=1
health_check_type=tcp
health_check_target=127.0.0.1:8083,127.0.0.1:8082
```
**health关键词必须在开头存在**
第一种是http模式,也就是以get的方式请求目标+url,返回状态码为200表示成功
第一种是tcp模式,也就是以tcp的方式与目标建立连接,能成功建立连接表示成功
如果失败次数超过`health_check_max_failed`,nps则会移除该npc下的所有该目标,如果失败后目标重新上线,nps将自动将目标重新加入。
项 | 含义
---|---
health_check_timeout | 健康检查超时时间
health_check_max_failed | 健康检查允许失败次数
health_check_interval | 健康检查间隔
health_check_type | 健康检查类型
health_check_target | 健康检查目标,多个以逗号(,)分隔
health_check_type | 健康检查类型
health_http_url | 健康检查url,仅http模式适用
## 日志输出
日志输出级别
**对于npc:**
```
-log_level=0~7 -log_path=npc.log
```
```
LevelEmergency->0 LevelAlert->1
LevelCritical->2 LevelError->3
LevelWarning->4 LevelNotice->5
LevelInformational->6 LevelDebug->7
```
默认为全输出,级别为0到7
**对于nps:**
在`nps.conf`中设置相关配置即可
## pprof性能分析与调试
可在服务端与客户端配置中开启pprof端口,用于性能分析与调试,注释或留空相应参数为关闭。
默认为关闭状态
## 自定义客户端超时检测断开时间
客户端与服务端间会间隔5s相互发送延迟测量包,这个时间间隔不可修改。
可修改延迟测量包丢包的次数,默认为60也就是5分钟都收不到一个延迟测量回包,则会断开客户端连接。
值得注意的是需要客户端的socket关闭,才会进行重连,也就是当客户端无法收到服务端的fin包时,只有客户端自行关闭socket才行。
也就是假如服务端设置为较低值,而客户端设置较高值,而此时服务端断开连接而客户端无法收到服务端的fin包,客户端也会继续等着直到触发客户端的超时设置。
在`nps.conf`或`npc.conf`中设置`disconnect_timeout`即可,客户端还可附带`-disconnect_timeout=60`参数启动
================================================
FILE: docs/index.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
<meta name="description" content="Description">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/vue.css">
</head>
<body>
<div id="app"></div>
<script src="//unpkg.com/docsify-edit-on-github/index.js"></script>
<script>
window.$docsify = {
name: '',
repo: '',
loadSidebar: true,
coverpage: true,
loadNavbar: true,
subMaxLevel: 2,
maxLevel: 4,
search: {
noData: "没有结果",
paths: 'auto',
placeholder: "搜索",
hideOtherSidebarContent: true, // whether or not to hide other sidebar content
},
plugins: [
EditOnGithubPlugin.create("https://github.com/ehang-io/nps/tree/master/docs/", "", "在github上编辑"),
]
}
</script>
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
<script src="//unpkg.com/docsify/lib/plugins/search.min.js"></script>
<script src="//unpkg.com/docsify-copy-code"></script>
</body>
</html>
================================================
FILE: docs/install.md
================================================
# 安装
## 安装包安装
[releases](https://github.com/ehang-io/nps/releases)
下载对应的系统版本即可,服务端和客户端是单独的
## 源码安装
- 安装源码
```go get -u ehang.io/nps```
- 编译
服务端```go build cmd/nps/nps.go```
客户端```go build cmd/npc/npc.go```
## docker安装
> [server](https://hub.docker.com/r/ffdfgdfg/nps)
> [client](https://hub.docker.com/r/ffdfgdfg/npc)
================================================
FILE: docs/introduction.md
================================================

# 介绍
可在网页上配置和管理各个tcp、udp隧道、内网站点代理,http、https解析等,功能强大,操作方便。
================================================
FILE: docs/npc_extend.md
================================================
# 增强功能
## nat类型检测
```
./npc nat -stun_addr=stun.stunprotocol.org:3478
```
如果p2p双方都是Symmetric Nat,肯定不能成功,其他组合都有较大成功率。`stun_addr`可以指定stun服务器地址。
## 状态检查
```
./npc status -config=npc配置文件路径
```
## 重载配置文件
```
./npc restart -config=npc配置文件路径
```
## 通过代理连接nps
有时候运行npc的内网机器无法直接访问外网,此时可以可以通过socks5代理连接nps
对于配置文件方式启动,设置
```ini
[common]
proxy_url=socks5://111:222@127.0.0.1:8024
```
对于无配置文件模式,加上参数
```
-proxy=socks5://111:222@127.0.0.1:8024
```
支持socks5和http两种模式
即socks5://username:password@ip:port
或http://username:password@ip:port
## 群晖支持
可在releases中下载spk群晖套件,例如`npc_x64-6.1_0.19.0-1.spk`
================================================
FILE: docs/npc_sdk.md
================================================
# npc sdk文档
```
命令行模式启动客户端
从v0.26.10开始,此函数会阻塞,直到客户端退出返回,请自行管理是否重连
p0->连接地址
p1->vkey
p2->连接类型(tcp or udp)
p3->连接代理
extern GoInt StartClientByVerifyKey(char* p0, char* p1, char* p2, char* p3);
查看当前启动的客户端状态,在线为1,离线为0
extern GoInt GetClientStatus();
关闭客户端
extern void CloseClient();
获取当前客户端版本
extern char* Version();
获取日志,实时更新
extern char* Logs();
```
================================================
FILE: docs/nps_extend.md
================================================
# 增强功能
## 使用https
**方式一:** 类似于nginx实现https的处理
在配置文件中将https_proxy_port设置为443或者其他你想配置的端口,将`https_just_proxy`设置为false,nps 重启后,在web管理界面,域名新增或修改界面中修改域名证书和密钥。
**此外:** 可以在`nps.conf`中设置一个默认的https配置,当遇到未在web中设置https证书的域名解析时,将自动使用默认证书,另还有一种情况就是对于某些请求的clienthello不携带sni扩展信息,nps也将自动使用默认证书
**方式二:** 在内网对应服务器上设置https
在`nps.conf`中将`https_just_proxy`设置为true,并且打开`https_proxy_port`端口,然后nps将直接转发https请求到内网服务器上,由内网服务器进行https处理
## 与nginx配合
有时候我们还需要在云服务器上运行nginx来保证静态文件缓存等,本代理可和nginx配合使用,在配置文件中将httpProxyPort设置为非80端口,并在nginx中配置代理,例如httpProxyPort为8010时
```
server {
listen 80;
server_name *.proxy.com;
location / {
proxy_set_header Host $http_host;
proxy_pass http://127.0.0.1:8010;
}
}
```
如需使用https也可在nginx监听443端口并配置ssl,并将本代理的httpsProxyPort设置为空关闭https即可,例如httpProxyPort为8020时
```
server {
listen 443;
server_name *.proxy.com;
ssl on;
ssl_certificate certificate.crt;
ssl_certificate_key private.key;
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
location / {
proxy_set_header Host $http_host;
proxy_pass http://127.0.0.1:8020;
}
}
```
## web管理使用https
如果web管理需要使用https,可以在配置文件`nps.conf`中设置`web_open_ssl=true`,并配置`web_cert_file`和`web_key_file`
## web使用Caddy代理
如果将web配置到Caddy代理,实现子路径访问nps,可以这样配置.
假设我们想通过 `http://caddy_ip:caddy_port/nps` 来访问后台, Caddyfile 这样配置:
```Caddyfile
caddy_ip:caddy_port/nps {
##server_ip 为 nps 服务器IP
##web_port 为 nps 后台端口
proxy / http://server_ip:web_port/nps {
transparent
}
}
```
nps.conf 修改 `web_base_url` 为 `/nps` 即可
```
web_base_url=/nps
```
## 关闭代理
如需关闭http代理可在配置文件中将http_proxy_port设置为空,如需关闭https代理可在配置文件中将https_proxy_port设置为空。
## 流量数据持久化
服务端支持将流量数据持久化,默认情况下是关闭的,如果有需求可以设置`nps.conf`中的`flow_store_interval`参数,单位为分钟
**注意:** nps不会持久化通过公钥连接的客户端
## 系统信息显示
nps服务端支持在web上显示和统计服务器的相关信息,但默认一些统计图表是关闭的,如需开启请在`nps.conf`中设置`system_info_display=true`
## 自定义客户端连接密钥
web上可以自定义客户端连接的密钥,但是必须具有唯一性
## 关闭公钥访问
可以将`nps.conf`中的`public_vkey`设置为空或者删除
## 关闭web管理
可以将`nps.conf`中的`web_port`设置为空或者删除
## 服务端多用户登陆
如果将`nps.conf`中的`allow_user_login`设置为true,服务端web将支持多用户登陆,登陆用户名为user,默认密码为每个客户端的验证密钥,登陆后可以进入客户端编辑修改web登陆的用户名和密码,默认该功能是关闭的。
## 用户注册功能
nps服务端支持用户注册功能,可将`nps.conf`中的`allow_user_register`设置为true,开启后登陆页将会有有注册功能,
## 监听指定ip
nps支持每个隧道监听不同的服务端端口,在`nps.conf`中设置`allow_multi_ip=true`后,可在web中控制,或者npc配置文件中(可忽略,默认为0.0.0.0)
```ini
server_ip=xxx
```
## 代理到服务端本地
在使用nps监听80或者443端口时,默认是将所有的请求都会转发到内网上,但有时候我们的nps服务器的上一些服务也需要使用这两个端口,nps提供类似于`nginx` `proxy_pass` 的功能,支持将代理到服务器本地,该功能支持域名解析,tcp、udp隧道,默认关闭。
**即:** 假设在nps的vps服务器上有一个服务使用5000端口,这时候nps占用了80端口和443,我们想能使用一个域名通过http(s)访问到5000的服务。
**使用方式:** 在`nps.conf`中设置`allow_local_proxy=true`,然后在web上设置想转发的隧道或者域名然后选择转发到本地选项即可成功。
================================================
FILE: docs/nps_use.md
================================================
# 使用
**提示:使用web模式时,服务端执行文件必须在项目根目录,否则无法正确加载配置文件**
## web管理
进入web界面,公网ip:web界面端口(默认8080),密码默认为123
进入web管理界面,有详细的说明
## 服务端配置文件重载
对于linux、darwin
```shell
sudo nps reload
```
对于windows
```shell
nps.exe reload
```
**说明:** 仅支持部分配置重载,例如`allow_user_login` `auth_crypt_key` `auth_key` `web_username` `web_password` 等,未来将支持更多
## 服务端停止或重启
对于linux、darwin
```shell
sudo nps stop|restart
```
对于windows
```shell
nps.exe stop|restart
```
## 服务端更新
请首先执行 `sudo nps stop` 或者 `nps.exe stop` 停止运行,然后
对于linux
```shell
sudo nps-update update
```
对于windows
```shell
nps-update.exe update
```
更新完成后,执行执行 `sudo nps start` 或者 `nps.exe start` 重新运行即可完成升级
如果无法更新成功,可以直接自行下载releases压缩包然后覆盖原有的nps二进制文件和web目录
注意:`nps install` 之后的 nps 不在原位置,请使用 `whereis nps` 查找具体目录覆盖 nps 二进制文件
================================================
FILE: docs/run.md
================================================
# 启动
## 服务端
下载完服务器压缩包后,解压,然后进入解压后的文件夹
- 执行安装命令
对于linux|darwin ```sudo ./nps install```
对于windows,管理员身份运行cmd,进入安装目录 ```nps.exe install```
- 启动
对于linux|darwin ```sudo nps start```
对于windows,管理员身份运行cmd,进入程序目录 ```nps.exe start```
```安装后windows配置文件位于 C:\Program Files\nps,linux和darwin位于/etc/nps```
停止和重启可用,stop和restart
**如果发现没有启动成功,可以使用`nps(.exe) stop`,然后运行`nps.(exe)`运行调试,或查看日志**(Windows日志文件位于当前运行目录下,linux和darwin位于/var/log/nps.log)
- 访问服务端ip:web服务端口(默认为8080)
- 使用用户名和密码登陆(默认admin/123,正式使用一定要更改)
- 创建客户端
## 客户端
- 下载客户端安装包并解压,进入到解压目录
- 点击web管理中客户端前的+号,复制启动命令
- 执行启动命令,linux直接执行即可,windows将./npc换成npc.exe用**cmd执行**
如果使用`powershell`运行,**请将ip括起来!**
如果需要注册到系统服务可查看[注册到系统服务](/use?id=注册到系统服务)
## 版本检查
- 对客户端以及服务的均可以使用参数`-version`打印版本
- `nps -version`或`./nps -version`
- `npc -version`或`./npc -version`
## 配置
- 客户端连接后,在web中配置对应穿透服务即可
- 可以查看[使用示例](/example)
================================================
FILE: docs/server_config.md
================================================
# 服务端配置文件
- /etc/nps/conf/nps.conf
名称 | 含义
---|---
web_port | web管理端口
web_password | web界面管理密码
web_username | web界面管理账号
web_base_url | web管理主路径,用于将web管理置于代理子路径后面
bridge_port | 服务端客户端通信端口
https_proxy_port | 域名代理https代理监听端口
http_proxy_port | 域名代理http代理监听端口
auth_key|web api密钥
bridge_type|客户端与服务端连接方式kcp或tcp
public_vkey|客户端以配置文件模式启动时的密钥,设置为空表示关闭客户端配置文件连接模式
ip_limit|是否限制ip访问,true或false或忽略
flow_store_interval|服务端流量数据持久化间隔,单位分钟,忽略表示不持久化
log_level|日志输出级别
auth_crypt_key | 获取服务端authKey时的aes加密密钥,16位
p2p_ip| 服务端Ip,使用p2p模式必填
p2p_port|p2p模式开启的udp端口
pprof_ip|debug pprof 服务端ip
pprof_port|debug pprof 端口
disconnect_timeout|客户端连接超时,单位 5s,默认值 60,即 300s = 5mins
================================================
FILE: docs/thanks.md
================================================
Thanks [jetbrains](https://www.jetbrains.com/?from=nps) for providing development tools for nps
<html>
<img src="https://ftp.bmp.ovh/imgs/2019/12/6435398b0c7402b1.png" width="300" align=center />
</html>
================================================
FILE: docs/use.md
================================================
# 基本使用
## 无配置文件模式
此模式的各种配置在服务端web管理中完成,客户端除运行一条命令外无需任何其他设置
```
./npc -server=ip:port -vkey=web界面中显示的密钥
```
## 注册到系统服务(开机启动、守护进程)
对于linux、darwin
- 注册:`sudo ./npc install 其他参数(例如-server=xx -vkey=xx或者-config=xxx)`
- 启动:`sudo npc start`
- 停止:`sudo npc stop`
- 如果需要更换命令内容需要先卸载`./npc uninstall`,再重新注册
对于windows,使用管理员身份运行cmd
- 注册:`npc.exe install 其他参数(例如-server=xx -vkey=xx或者-config=xxx)`
- 启动:`npc.exe start`
- 停止:`npc.exe stop`
- 如果需要更换命令内容需要先卸载`npc.exe uninstall`,再重新注册
- 如果需要当客户端退出时自动重启客户端,请按照如图所示配置

注册到服务后,日志文件windows位于当前目录下,linux和darwin位于/var/log/npc.log
## 客户端更新
首先进入到对于的客户端二进制文件目录
请首先执行`sudo npc stop`或者`npc.exe stop`停止运行,然后
对于linux
```shell
sudo npc-update update
```
对于windows
```shell
npc-update.exe update
```
更新完成后,执行执行`sudo npc start`或者`npc.exe start`重新运行即可完成升级
如果无法更新成功,可以直接自行下载releases压缩包然后覆盖原有的npc二进制文件
## 配置文件模式
此模式使用nps的公钥或者客户端私钥验证,各种配置在客户端完成,同时服务端web也可以进行管理
```
./npc -config=npc配置文件路径
```
## 配置文件说明
[示例配置文件](https://github.com/ehang-io/nps/tree/master/conf/npc.conf)
#### 全局配置
```ini
[common]
server_addr=1.1.1.1:8024
conn_type=tcp
vkey=123
username=111
password=222
compress=true
crypt=true
rate_limit=10000
flow_limit=100
remark=test
max_conn=10
#pprof_addr=0.0.0.0:9999
```
项 | 含义
---|---
server_addr | 服务端ip/域名:port
conn_type | 与服务端通信模式(tcp或kcp)
vkey|服务端配置文件中的密钥(非web)
username|socks5或http(s)密码保护用户名(可忽略)
password|socks5或http(s)密码保护密码(可忽略)
compress|是否压缩传输(true或false或忽略)
crypt|是否加密传输(true或false或忽略)
rate_limit|速度限制,可忽略
flow_limit|流量限制,可忽略
remark|客户端备注,可忽略
max_conn|最大连接数,可忽略
pprof_addr|debug pprof ip:port
#### 域名代理
```ini
[common]
server_addr=1.1.1.1:8024
vkey=123
[web1]
host=a.proxy.com
target_addr=127.0.0.1:8080,127.0.0.1:8082
host_change=www.proxy.com
header_set_proxy=nps
```
项 | 含义
---|---
web1 | 备注
host | 域名(http|https都可解析)
target_addr|内网目标,负载均衡时多个目标,逗号隔开
host_change|请求host修改
header_xxx|请求header修改或添加,header_proxy表示添加header proxy:nps
#### tcp隧道模式
```ini
[common]
server_addr=1.1.1.1:8024
vkey=123
[tcp]
mode=tcp
target_addr=127.0.0.1:8080
server_port=9001
```
项 | 含义
---|---
mode | tcp
server_port | 在服务端的代理端口
tartget_addr|内网目标
#### udp隧道模式
```ini
[common]
server_addr=1.1.1.1:8024
vkey=123
[udp]
mode=udp
target_addr=127.0.0.1:8080
server_port=9002
```
项 | 含义
---|---
mode | udp
server_port | 在服务端的代理端口
target_addr|内网目标
#### http代理模式
```ini
[common]
server_addr=1.1.1.1:8024
vkey=123
[http]
mode=httpProxy
server_port=9003
```
项 | 含义
---|---
mode | httpProxy
server_port | 在服务端的代理端口
#### socks5代理模式
```ini
[common]
server_addr=1.1.1.1:8024
vkey=123
[socks5]
mode=socks5
server_port=9004
multi_account=multi_account.conf
```
项 | 含义
---|---
mode | socks5
server_port | 在服务端的代理端口
multi_account | socks5多账号配置文件(可选),配置后使用basic_username和basic_password无法通过认证
#### 私密代理模式
```ini
[common]
server_addr=1.1.1.1:8024
vkey=123
[secret_ssh]
mode=secret
password=ssh2
target_addr=10.1.50.2:22
```
项 | 含义
---|---
mode | secret
password | 唯一密钥
target_addr|内网目标
#### p2p代理模式
```ini
[common]
server_addr=1.1.1.1:8024
vkey=123
[p2p_ssh]
mode=p2p
password=ssh2
target_addr=10.1.50.2:22
```
项 | 含义
---|---
mode | p2p
password | 唯一密钥
target_addr|内网目标
#### 文件访问模式
利用nps提供一个公网可访问的本地文件服务,此模式仅客户端使用配置文件模式方可启动
```ini
[common]
server_addr=1.1.1.1:8024
vkey=123
[file]
mode=file
server_port=9100
local_path=/tmp/
strip_pre=/web/
````
项 | 含义
---|---
mode | file
server_port | 服务端开启的端口
local_path|本地文件目录
strip_pre|前缀
对于`strip_pre`,访问公网`ip:9100/web/`相当于访问`/tmp/`目录
#### 断线重连
```ini
[common]
auto_reconnection=true
```
================================================
FILE: docs/webapi.md
================================================
获取客户端列表
```
POST /client/list/
```
| 参数 | 含义 |
| --- | --- |
| search | 搜索 |
| order | 排序asc 正序 desc倒序 |
| offset | 分页(第几页) |
| limit | 条数(分页显示的条数) |
***
获取单个客户端
```
POST /client/getclient/
```
| 参数 | 含义 |
| --- | --- |
| id | 客户端id |
***
添加客户端
```
POST /client/add/
```
| 参数 | 含义 |
| --- | --- |
| remark | 备注 |
| u | basic权限认证用户名 |
| p | basic权限认证密码 |
| limit | 条数(分页显示的条数) |
| vkey | 客户端验证密钥 |
| config\_conn\_allow | 是否允许客户端以配置文件模式连接 1允许 0不允许 |
| compress | 压缩1允许 0不允许 |
| crypt | 是否加密(1或者0)1允许 0不允许 |
| rate\_limit | 带宽限制 单位KB/S 空则为不限制 |
| flow\_limit | 流量限制 单位M 空则为不限制 |
| max\_conn | 客户端最大连接数量 空则为不限制 |
| max\_tunnel | 客户端最大隧道数量 空则为不限制 |
***
修改客户端
```
POST /client/edit/
```
| 参数 | 含义 |
| --- | --- |
| remark | 备注 |
| u | basic权限认证用户名 |
| p | basic权限认证密码 |
| limit | 条数(分页显示的条数) |
| vkey | 客户端验证密钥 |
| config\_conn\_allow | 是否允许客户端以配置文件模式连接 1允许 0不允许 |
| compress | 压缩1允许 0不允许 |
| crypt | 是否加密(1或者0)1允许 0不允许 |
| rate\_limit | 带宽限制 单位KB/S 空则为不限制 |
| flow\_limit | 流量限制 单位M 空则为不限制 |
| max\_conn | 客户端最大连接数量 空则为不限制 |
| max\_tunnel | 客户端最大隧道数量 空则为不限制 |
| id | 要修改的客户端id |
***
删除客户端
```
POST /client/del/
```
| 参数 | 含义 |
| --- | --- |
| id | 要删除的客户端id |
***
获取域名解析列表
```
POST /index/hostlist/
```
| 参数 | 含义 |
| --- | --- |
| search | 搜索(可以搜域名/备注什么的) |
| offset | 分页(第几页) |
| limit | 条数(分页显示的条数) |
***
添加域名解析
```
POST /index/addhost/
```
| 参数 | 含义 |
| --- | --- |
| remark | 备注 |
| host | 域名 |
| scheme | 协议类型(三种 all http https) |
| location | url路由 空则为不限制 |
| client\_id | 客户端id |
| target | 内网目标(ip:端口) |
| header | request header 请求头 |
| hostchange | request host 请求主机 |
***
修改域名解析
```
POST /index/edithost/
```
| 参数 | 含义 |
| --- | --- |
| remark | 备注 |
| host | 域名 |
| scheme | 协议类型(三种 all http https) |
| location | url路由 空则为不限制 |
| client\_id | 客户端id |
| target | 内网目标(ip:端口) |
| header | request header 请求头 |
| hostchange | request host 请求主机 |
| id | 需要修改的域名解析id |
***
删除域名解析
```
POST /index/delhost/
```
| 参数 | 含义 |
| --- | --- |
| id | 需要删除的域名解析id |
***
获取单条隧道信息
```
POST /index/getonetunnel/
```
| 参数 | 含义 |
| --- | --- |
| id | 隧道的id |
***
获取隧道列表
```
POST /index/gettunnel/
```
| 参数 | 含义 |
| --- | --- |
| client\_id | 穿透隧道的客户端id |
| type | 类型tcp udp httpProx socks5 secret p2p |
| search | 搜索 |
| offset | 分页(第几页) |
| limit | 条数(分页显示的条数) |
***
添加隧道
```
POST /index/add/
```
| 参数 | 含义 |
| --- | --- |
| type | 类型tcp udp httpProx socks5 secret p2p |
| remark | 备注 |
| port | 服务端端口 |
| target | 目标(ip:端口) |
| client\_id | 客户端id |
***
修改隧道
```
POST /index/edit/
```
| 参数 | 含义 |
| --- | --- |
| type | 类型tcp udp httpProx socks5 secret p2p |
| remark | 备注 |
| port | 服务端端口 |
| target | 目标(ip:端口) |
| client\_id | 客户端id |
| id | 隧道id |
***
删除隧道
```
POST /index/del/
```
| 参数 | 含义 |
| --- | --- |
| id | 隧道id |
***
隧道停止工作
```
POST /index/stop/
```
| 参数 | 含义 |
| --- | --- |
| id | 隧道id |
***
隧道开始工作
```
POST /index/start/
```
| 参数 | 含义 |
| --- | --- |
| id | 隧道id |
================================================
FILE: go.mod
================================================
module ehang.io/nps
go 1.15
require (
ehang.io/nps-mux v0.0.0-20210407130203-4afa0c10c992
fyne.io/fyne/v2 v2.0.2
github.com/astaxie/beego v1.12.0
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 // indirect
github.com/c4milo/unpackit v0.0.0-20170704181138-4ed373e9ef1c
github.com/ccding/go-stun v0.0.0-20180726100737-be486d185f3d
github.com/dsnet/compress v0.0.1 // indirect
github.com/golang/snappy v0.0.3
github.com/hooklift/assert v0.0.0-20170704181755-9d1defd6d214 // indirect
github.com/kardianos/service v1.2.0
github.com/klauspost/cpuid v1.3.1 // indirect
github.com/klauspost/cpuid/v2 v2.0.6 // indirect
github.com/klauspost/pgzip v1.2.1 // indirect
github.com/klauspost/reedsolomon v1.9.12 // indirect
github.com/panjf2000/ants/v2 v2.4.2
github.com/pkg/errors v0.9.1
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 // indirect
github.com/shirou/gopsutil/v3 v3.21.3
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 // indirect
github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b // indirect
github.com/tjfoc/gmsm v1.4.0 // indirect
github.com/xtaci/kcp-go v5.4.20+incompatible
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae // indirect
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 // indirect
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 // indirect
)
replace github.com/astaxie/beego => github.com/exfly/beego v1.12.0-export-init
================================================
FILE: go.sum
================================================
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
ehang.io/nps-mux v0.0.0-20210407130203-4afa0c10c992 h1:LvlcB+8JveSBprHnva0g+OyLwAH8CRxEwtWzTe6ocoE=
ehang.io/nps-mux v0.0.0-20210407130203-4afa0c10c992/go.mod h1:v54y/8ICChiM/aVUuKxGIcWwjm4HGNRyyAwbgLBoMbI=
fyne.io/fyne/v2 v2.0.2 h1:6pDvFuCmL1odyT/fPI+2L54hMJW1Zt9Dno41HmLInRs=
fyne.io/fyne/v2 v2.0.2/go.mod h1:3+FYmLJVgeb8EvTPJ5YzZeo7LkAq4bbuY3Zrir6xHbg=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/Kodeworks/golang-image-ico v0.0.0-20141118225523-73f0f4cfade9/go.mod h1:7uhhqiBaR4CpN0k9rMjOtjpcfGd6DG2m04zQxKnWQ0I=
github.com/OwnLocal/goes v1.0.0/go.mod h1:8rIFjBGTue3lCU0wplczcUgt9Gxgrkkrw7etMIcn8TM=
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk=
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkYwXMUU0OhQqGvsY2Bvgr4j6jfT699wyZKQ=
github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542/go.mod h1:kSeGC/p1AbBiEp5kat81+DSQrZenVBZXklMLaELspWU=
github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 h1:GKTyiRCL6zVf5wWaqKnf+7Qs6GbEPfd4iMOitWzXJx8=
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8/go.mod h1:spo1JLcs67NmW1aVLEgtA8Yy1elc+X8y5SRW1sFW4Og=
github.com/c4milo/unpackit v0.0.0-20170704181138-4ed373e9ef1c h1:aprLqMn7gSPT+vdDSl+/E6NLEuArwD/J7IWd8bJt5lQ=
github.com/c4milo/unpackit v0.0.0-20170704181138-4ed373e9ef1c/go.mod h1:Ie6SubJv/NTO9Q0UBH0QCl3Ve50lu9hjbi5YJUw03TE=
github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE=
github.com/ccding/go-stun v0.0.0-20180726100737-be486d185f3d h1:As4937T5NVbJ/DmZT9z33pyLEprMd6CUSfhbmMY57Io=
github.com/ccding/go-stun v0.0.0-20180726100737-be486d185f3d/go.mod h1:3FK1bMar37f7jqVY7q/63k3OMX1c47pGCufzt3X0sYE=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/couchbase/go-couchbase v0.0.0-20181122212707-3e9b6e1258bb/go.mod h1:TWI8EKQMs5u5jLKW/tsb9VwauIrMIxQG1r5fMsswK5U=
github.com/couchbase/gomemcached v0.0.0-20181122193126-5125a94a666c/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c=
github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs=
github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q=
github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo=
github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3CKKpKinvZLFk=
github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/exfly/beego v1.12.0-export-init h1:VQNYKdXhAwZGUaFmQv8Aj921O3rQJZRIF8xeGrhsjrI=
github.com/exfly/beego v1.12.0-export-init/go.mod h1:fysx+LZNZKnvh4GED/xND7jWtjCR6HzydR2Hh2Im57o=
github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3 h1:FDqhDm7pcsLhhWl1QtD8vlzI4mm59llRvNzrFg6/LAA=
github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3/go.mod h1:CzM2G82Q9BDUvMTGHnXf/6OExw/Dz2ivDj48nVg7Lg8=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fyne-io/mobile v0.1.3-0.20210318200029-09e9c4e13a8f h1:rguJ/t99j/6zRSFzsBKlsmmyl+vOvCeTJ+2uTBvuXFI=
github.com/fyne-io/mobile v0.1.3-0.20210318200029-09e9c4e13a8f/go.mod h1:/kOrWrZB6sasLbEy2JIvr4arEzQTXBTZGb3Y96yWbHY=
github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7 h1:SCYMcCJ89LjRGwEa0tRluNRiMjZHalQZrVrvTbPh+qw=
github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7/go.mod h1:482civXOzJJCPzJ4ZOX/pwvXBWSnzD4OKMdH4ClKGbk=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20210311203641-62640a716d48 h1:QrUfZrT8n72FUuiABt4tbu8PwDnOPAbnj3Mql1UhdRI=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20210311203641-62640a716d48/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI=
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/godbus/dbus/v5 v5.0.3 h1:ZqHaoEF7TBzh4jzPmqVhE/5A1z9of6orkAe5uHoAeME=
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff h1:W71vTCKoxtdXgnm1ECDFkfQnpdqAO00zzGXLA5yaEX8=
github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff/go.mod h1:wfqRWLHRBsRgkp5dmbG56SA0DmVtwrF5N3oPdI8t+Aw=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA=
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/hooklift/assert v0.0.0-20170704181755-9d1defd6d214 h1:WgfvpuKg42WVLkxNwzfFraXkTXPK36bMqXvMFN67clI=
github.com/hooklift/assert v0.0.0-20170704181755-9d1defd6d214/go.mod h1:kj6hFWqfwSjFjLnYW5PK1DoxZ4O0uapwHRmd9jhln4E=
github.com/jackmordaunt/icns v0.0.0-20181231085925-4f16af745526/go.mod h1:UQkeMHVoNcyXYq9otUupF7/h/2tmHlhrS2zw7ZVvUqc=
github.com/josephspurrier/goversioninfo v0.0.0-20200309025242-14b0ab84c6ca/go.mod h1:eJTEwMjXb7kZ633hO3Ln9mBUCOjX2+FlTljvpl9SYdE=
github.com/kardianos/service v1.2.0 h1:bGuZ/epo3vrt8IPC7mnKQolqFeYJb7Cs8Rk4PSOBB/g=
github.com/kardianos/service v1.2.0/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM=
github.com/klauspost/compress v1.4.1 h1:8VMb5+0wMgdBykOV96DwNwKFQ+WTI4pzYURP99CcB9E=
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/cpuid v1.3.1 h1:5JNjFYYQrZeKRJ0734q51WCEEn2huer72Dc7K+R/b6s=
github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4=
github.com/klauspost/cpuid/v2 v2.0.2 h1:pd2FBxFydtPn2ywTLStbFg9CJKrojATnpeJWSP7Ys4k=
github.com/klauspost/cpuid/v2 v2.0.2/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.6 h1:dQ5ueTiftKxp0gyjKSx5+8BtPWkyQbd95m8Gys/RarI=
github.com/klauspost/cpuid/v2 v2.0.6/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/pgzip v1.2.1 h1:oIPZROsWuPHpOdMVWLuJZXwgjhrW8r1yEX8UqMyeNHM=
github.com/klauspost/pgzip v1.2.1/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/klauspost/reedsolomon v1.9.12 h1:EyOucRmcrLH+2hqKGdoA5SM8pwPKR6BJsf3r6zpYOA0=
github.com/klauspost/reedsolomon v1.9.12/go.mod h1:nLvuzNvy1ZDNQW30IuMc2ZWCbiqrJgdLoUS2X8HAUVg=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lucor/goinfo v0.0.0-20200401173949-526b5363a13a/go.mod h1:ORP3/rB5IsulLEBwQZCJyyV6niqmI7P4EWSmkug+1Ng=
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/panjf2000/ants/v2 v2.4.2 h1:kesjjo8JipN3vNNg1XaiXaeSs6xJweBTgenkBtsrHf8=
github.com/panjf2000/ants/v2 v2.4.2/go.mod h1:f6F0NZVFsGCp5A7QW/Zj/m92atWwOkY0OIhFxRNFr4A=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI+b2qND5gpH8YhURn0k8OCaeRnkINo=
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
github.com/shirou/gopsutil/v3 v3.21.3 h1:wgcdAHZS2H6qy4JFewVTtqfiYxFzCeEJod/mLztdPG8=
github.com/shirou/gopsutil/v3 v3.21.3/go.mod h1:ghfMypLDrFSWN2c9cDYFLHyynQ+QUht0cv/18ZqVczw=
github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=
github.com/siddontang/ledisdb v0.0.0-20181029004158-becf5f38d373/go.mod h1:mF1DpOSOUiJRMR+FDqaqu3EBqrybQtrDDszLUZ6oxPg=
github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564 h1:HunZiaEKNGVdhTRQOVpMmj5MQnGnv+e8uZNu3xFLgyM=
github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564/go.mod h1:afMbS0qvv1m5tfENCwnOdZGOF8RGR/FsZ7bvBxQGZG4=
github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9 h1:m59mIOBO4kfcNCEzJNy71UkeF4XIx2EVmL9KLwDQdmM=
github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9/go.mod h1:mvWM0+15UqyrFKqdRjY6LuAVJR0HOVhJlEgZ5JWtSWU=
github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 h1:89CEmDvlq/F7SJEOqkIdNDGJXrQIhuIx9D2DBXjavSU=
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU=
github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b h1:fj5tQ8acgNUr6O8LEplsxDhUIe2573iLkJc+PqnzZTI=
github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4=
github.com/tjfoc/gmsm v1.4.0 h1:8nbaiZG+iVdh+fXVw0DZoZZa7a4TGm3Qab+xdrdzj8s=
github.com/tjfoc/gmsm v1.4.0/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
github.com/tklauser/go-sysconf v0.3.4 h1:HT8SVixZd3IzLdfs/xlpq0jeSfTX57g1v6wB1EuzV7M=
github.com/tklauser/go-sysconf v0.3.4/go.mod h1:Cl2c8ZRWfHD5IrfHo9VN+FX9kCFjIOyVklgXycLB6ek=
github.com/tklauser/numcpus v0.2.1 h1:ct88eFm+Q7m2ZfXJdan1xYoXKlmwsfP+k88q05KvlZc=
github.com/tklauser/numcpus v0.2.1/go.mod h1:9aU+wOc6WjUIZEwWMP62PL/41d65P+iks1gBkr4QyP8=
github.com/ulikunitz/xz v0.5.6 h1:jGHAfXawEGZQ3blwU5wnWKQJvAraT7Ftq9EXjnXYgt8=
github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc=
github.com/xtaci/kcp-go v5.4.20+incompatible h1:TN1uey3Raw0sTz0Fg8GkfM0uH3YwzhnZWQ1bABv5xAg=
github.com/xtaci/kcp-go v5.4.20+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae h1:J0GxkO96kL4WF+AIT3M4mfUVinOCPgf2uUWYFUzN0sM=
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85 h1:et7+NAX3lLIk5qUCTA9QelBjGE/NkhzYw/mhnr0s7nI=
golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20200430140353-33d19683fad8 h1:6WW6V3x1P/jokJBpRQYUJnMHRP6isStQwCozxnU7XQw=
golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a h1:gOpx8G595UYyvj8UK4+OFyY4rx037g3fmfhe5SasG3U=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200720211630-cb9d2d5c5666/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211 h1:9UQO31fZ+0aKQOFldThf7BKPMJTiBfWycGh/u3UoO88=
golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210217105451-b926d437f341/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 h1:F5Gozwx4I1xtr/sr/8CFbb57iKi3297KFs0QDbGN60A=
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190808195139-e713427fea3f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200328031815-3db5fc6bac03/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
================================================
FILE: lib/cache/lru.go
================================================
package cache
import (
"container/list"
"sync"
)
// Cache is an LRU cache. It is safe for concurrent access.
type Cache struct {
// MaxEntries is the maximum number of cache entries before
// an item is evicted. Zero means no limit.
MaxEntries int
//Execute this callback function when an element is culled
OnEvicted func(key Key, value interface{})
ll *list.List //list
cache sync.Map
}
// A Key may be any value that is comparable. See http://golang.org/ref/spec#Comparison_operators
type Key interface{}
type entry struct {
key Key
value interface{}
}
// New creates a new Cache.
// If maxEntries is 0, the cache has no length limit.
// that eviction is done by the caller.
func New(maxEntries int) *Cache {
return &Cache{
MaxEntries: maxEntries,
ll: list.New(),
//cache: make(map[interface{}]*list.Element),
}
}
// If the key value already exists, move the key to the front
func (c *Cache) Add(key Key, value interface{}) {
if ee, ok := c.cache.Load(key); ok {
c.ll.MoveToFront(ee.(*list.Element)) // move to the front
ee.(*list.Element).Value.(*entry).value = value
return
}
ele := c.ll.PushFront(&entry{key, value})
c.cache.Store(key, ele)
if c.MaxEntries != 0 && c.ll.Len() > c.MaxEntries { // Remove the oldest element if the limit is exceeded
c.RemoveOldest()
}
}
// Get looks up a key's value from the cache.
func (c *Cache) Get(key Key) (value interface{}, ok bool) {
if ele, hit := c.cache.Load(key); hit {
c.ll.MoveToFront(ele.(*list.Element))
return ele.(*list.Element).Value.(*entry).value, true
}
return
}
// Remove removes the provided key from the cache.
func (c *Cache) Remove(key Key) {
if ele, hit := c.cache.Load(key); hit {
c.removeElement(ele.(*list.Element))
}
}
// RemoveOldest removes the oldest item from the cache.
func (c *Cache) RemoveOldest() {
ele := c.ll.Back()
if ele != nil {
c.removeElement(ele)
}
}
func (c *Cache) removeElement(e *list.Element) {
c.ll.Remove(e)
kv := e.Value.(*entry)
c.cache.Delete(kv.key)
if c.OnEvicted != nil {
c.OnEvicted(kv.key, kv.value)
}
}
// Len returns the number of items in the cache.
func (c *Cache) Len() int {
return c.ll.Len()
}
// Clear purges all stored items from the cache.
func (c *Cache) Clear() {
if c.OnEvicted != nil {
c.cache.Range(func(key, value interface{}) bool {
kv := value.(*list.Element).Value.(*entry)
c.OnEvicted(kv.key, kv.value)
return true
})
}
c.ll = nil
}
================================================
FILE: lib/common/const.go
================================================
package common
const (
CONN_DATA_SEQ = "*#*" //Separator
VERIFY_EER = "vkey"
VERIFY_SUCCESS = "sucs"
WORK_MAIN = "main"
WORK_CHAN = "chan"
WORK_CONFIG = "conf"
WORK_REGISTER = "rgst"
WORK_SECRET = "sert"
WORK_FILE = "file"
WORK_P2P = "p2pm"
WORK_P2P_VISITOR = "p2pv"
WORK_P2P_PROVIDER = "p2pp"
WORK_P2P_CONNECT = "p2pc"
WORK_P2P_SUCCESS = "p2ps"
WORK_P2P_END = "p2pe"
WORK_P2P_LAST = "p2pl"
WORK_STATUS = "stus"
RES_MSG = "msg0"
RES_CLOSE = "clse"
NEW_UDP_CONN = "udpc" //p2p udp conn
NEW_TASK = "task"
NEW_CONF = "conf"
NEW_HOST = "host"
CONN_TCP = "tcp"
CONN_UDP = "udp"
CONN_TEST = "TST"
UnauthorizedBytes = `HTTP/1.1 401 Unauthorized
Content-Type: text/plain; charset=utf-8
WWW-Authenticate: Basic realm="easyProxy"
401 Unauthorized`
ConnectionFailBytes = `HTTP/1.1 404 Not Found
`
)
================================================
FILE: lib/common/logs.go
================================================
package common
import (
"github.com/astaxie/beego/logs"
"time"
)
const MaxMsgLen = 5000
var logMsgs string
func init() {
logs.Register("store", func() logs.Logger {
return new(StoreMsg)
})
}
func GetLogMsg() string {
return logMsgs
}
type StoreMsg struct {
}
func (lg *StoreMsg) Init(config string) error {
return nil
}
func (lg *StoreMsg) WriteMsg(when time.Time, msg string, level int) error {
m := when.Format("2006-01-02 15:04:05") + " " + msg + "\r\n"
if len(logMsgs) > MaxMsgLen {
start := MaxMsgLen - len(m)
if start <= 0 {
start = MaxMsgLen
}
logMsgs = logMsgs[start:]
}
logMsgs += m
return nil
}
func (lg *StoreMsg) Destroy() {
return
}
func (lg *StoreMsg) Flush() {
return
}
================================================
FILE: lib/common/netpackager.go
================================================
package common
import (
"bytes"
"encoding/binary"
"errors"
"io"
"io/ioutil"
"net"
"strconv"
)
type NetPackager interface {
Pack(writer io.Writer) (err error)
UnPack(reader io.Reader) (err error)
}
const (
ipV4 = 1
domainName = 3
ipV6 = 4
)
type UDPHeader struct {
Rsv uint16
Frag uint8
Addr *Addr
}
func NewUDPHeader(rsv uint16, frag uint8, addr *Addr) *UDPHeader {
return &UDPHeader{
Rsv: rsv,
Frag: frag,
Addr: addr,
}
}
type Addr struct {
Type uint8
Host string
Port uint16
}
func (addr *Addr) String() string {
return net.JoinHostPort(addr.Host, strconv.Itoa(int(addr.Port)))
}
func (addr *Addr) Decode(b []byte) error {
addr.Type = b[0]
pos := 1
switch addr.Type {
case ipV4:
addr.Host = net.IP(b[pos : pos+net.IPv4len]).String()
pos += net.IPv4len
case ipV6:
addr.Host = net.IP(b[pos : pos+net.IPv6len]).String()
pos += net.IPv6len
case domainName:
addrlen := int(b[pos])
pos++
addr.Host = string(b[pos : pos+addrlen])
pos += addrlen
default:
return errors.New("decode error")
}
addr.Port = binary.BigEndian.Uint16(b[pos:])
return nil
}
func (addr *Addr) Encode(b []byte) (int, error) {
b[0] = addr.Type
pos := 1
switch addr.Type {
case ipV4:
ip4 := net.ParseIP(addr.Host).To4()
if ip4 == nil {
ip4 = net.IPv4zero.To4()
}
pos += copy(b[pos:], ip4)
case domainName:
b[pos] = byte(len(addr.Host))
pos++
pos += copy(b[pos:], []byte(addr.Host))
case ipV6:
ip16 := net.ParseIP(addr.Host).To16()
if ip16 == nil {
ip16 = net.IPv6zero.To16()
}
pos += copy(b[pos:], ip16)
default:
b[0] = ipV4
copy(b[pos:pos+4], net.IPv4zero.To4())
pos += 4
}
binary.BigEndian.PutUint16(b[pos:], addr.Port)
pos += 2
return pos, nil
}
func (h *UDPHeader) Write(w io.Writer) error {
b := BufPoolUdp.Get().([]byte)
defer BufPoolUdp.Put(b)
binary.BigEndian.PutUint16(b[:2], h.Rsv)
b[2] = h.Frag
addr := h.Addr
if addr == nil {
addr = &Addr{}
}
length, _ := addr.Encode(b[3:])
_, err := w.Write(b[:3+length])
return err
}
type UDPDatagram struct {
Header *UDPHeader
Data []byte
}
func ReadUDPDatagram(r io.Reader) (*UDPDatagram, error) {
b := BufPoolUdp.Get().([]byte)
defer BufPoolUdp.Put(b)
// when r is a streaming (such as TCP connection), we may read more than the required data,
// but we don't know how to handle it. So we use io.ReadFull to instead of io.ReadAtLeast
// to make sure that no redundant data will be discarded.
n, err := io.ReadFull(r, b[:5])
if err != nil {
return nil, err
}
header := &UDPHeader{
Rsv: binary.BigEndian.Uint16(b[:2]),
Frag: b[2],
}
atype := b[3]
hlen := 0
switch atype {
case ipV4:
hlen = 10
case ipV6:
hlen = 22
case domainName:
hlen = 7 + int(b[4])
default:
return nil, errors.New("addr not support")
}
dlen := int(header.Rsv)
if dlen == 0 { // standard SOCKS5 UDP datagram
extra, err := ioutil.ReadAll(r) // we assume no redundant data
if err != nil {
return nil, err
}
copy(b[n:], extra)
n += len(extra) // total length
dlen = n - hlen // data length
} else { // extended feature, for UDP over TCP, using reserved field as data length
if _, err := io.ReadFull(r, b[n:hlen+dlen]); err != nil {
return nil, err
}
n = hlen + dlen
}
header.Addr = new(Addr)
if err := header.Addr.Decode(b[3:hlen]); err != nil {
return nil, err
}
data := make([]byte, dlen)
copy(data, b[hlen:n])
d := &UDPDatagram{
Header: header,
Data: data,
}
return d, nil
}
func NewUDPDatagram(header *UDPHeader, data []byte) *UDPDatagram {
return &UDPDatagram{
Header: header,
Data: data,
}
}
func (d *UDPDatagram) Write(w io.Writer) error {
h := d.Header
if h == nil {
h = &UDPHeader{}
}
buf := bytes.Buffer{}
if err := h.Write(&buf); err != nil {
return err
}
if _, err := buf.Write(d.Data); err != nil {
return err
}
_, err := buf.WriteTo(w)
return err
}
func ToSocksAddr(addr net.Addr) *Addr {
host := "0.0.0.0"
port := 0
if addr != nil {
h, p, _ := net.SplitHostPort(addr.String())
host = h
port, _ = strconv.Atoi(p)
}
return &Addr{
Type: ipV4,
Host: host,
Port: uint16(port),
}
}
================================================
FILE: lib/common/pool.go
================================================
package common
import (
"sync"
)
const PoolSize = 64 * 1024
const PoolSizeSmall = 100
const PoolSizeUdp = 1472 + 200
const PoolSizeCopy = 32 << 10
var BufPool = sync.Pool{
New: func() interface{} {
return make([]byte, PoolSize)
},
}
var BufPoolUdp = sync.Pool{
New: func() interface{} {
return make([]byte, PoolSizeUdp)
},
}
var BufPoolMax = sync.Pool{
New: func() interface{} {
return make([]byte, PoolSize)
},
}
var BufPoolSmall = sync.Pool{
New: func() interface{} {
return make([]byte, PoolSizeSmall)
},
}
var BufPoolCopy = sync.Pool{
New: func() interface{} {
return make([]byte, PoolSizeCopy)
},
}
func PutBufPoolUdp(buf []byte) {
if cap(buf) == PoolSizeUdp {
BufPoolUdp.Put(buf[:PoolSizeUdp])
}
}
func PutBufPoolCopy(buf []byte) {
if cap(buf) == PoolSizeCopy {
BufPoolCopy.Put(buf[:PoolSizeCopy])
}
}
func GetBufPoolCopy() []byte {
return (BufPoolCopy.Get().([]byte))[:PoolSizeCopy]
}
func PutBufPoolMax(buf []byte) {
if cap(buf) == PoolSize {
BufPoolMax.Put(buf[:PoolSize])
}
}
type copyBufferPool struct {
pool sync.Pool
}
func (Self *copyBufferPool) New() {
Self.pool = sync.Pool{
New: func() interface{} {
return make([]byte, PoolSizeCopy, PoolSizeCopy)
},
}
}
func (Self *copyBufferPool) Get() []byte {
buf := Self.pool.Get().([]byte)
return buf[:PoolSizeCopy] // just like make a new slice, but data may not be 0
}
func (Self *copyBufferPool) Put(x []byte) {
if len(x) == PoolSizeCopy {
Self.pool.Put(x)
} else {
x = nil // buf is not full, not allowed, New method returns a full buf
}
}
var once = sync.Once{}
var CopyBuff = copyBufferPool{}
func newPool() {
CopyBuff.New()
}
func init() {
once.Do(newPool)
}
================================================
FILE: lib/common/pprof.go
================================================
package common
import (
"github.com/astaxie/beego"
"github.com/astaxie/beego/logs"
"net/http"
_ "net/http/pprof"
)
func InitPProfFromFile() {
ip := beego.AppConfig.String("pprof_ip")
p := beego.AppConfig.String("pprof_port")
if len(ip) > 0 && len(p) > 0 && IsPort(p) {
runPProf(ip + ":" + p)
}
}
func InitPProfFromArg(arg string) {
if len(arg) > 0 {
runPProf(arg)
}
}
func runPProf(ipPort string) {
go func() {
_ = http.ListenAndServe(ipPort, nil)
}()
logs.Info("PProf debug listen on", ipPort)
}
================================================
FILE: lib/common/run.go
================================================
package common
import (
"os"
"path/filepath"
"runtime"
)
//Get the currently selected configuration file directory
//For non-Windows systems, select the /etc/nps as config directory if exist, or select ./
//windows system, select the C:\Program Files\nps as config directory if exist, or select ./
func GetRunPath() string {
var path string
if path = GetInstallPath(); !FileExists(path) {
return GetAppPath()
}
return path
}
//Different systems get different installation paths
func GetInstallPath() string {
var path string
if IsWindows() {
path = `C:\Program Files\nps`
} else {
path = "/etc/nps"
}
return path
}
//Get the absolute path to the running directory
func GetAppPath() string {
if path, err := filepath.Abs(filepath.Dir(os.Args[0])); err == nil {
return path
}
return os.Args[0]
}
//Determine whether the current system is a Windows system?
func IsWindows() bool {
if runtime.GOOS == "windows" {
return true
}
return false
}
//interface log file path
func GetLogPath() string {
var path string
if IsWindows() {
path = filepath.Join(GetAppPath(), "nps.log")
} else {
path = "/var/log/nps.log"
}
return path
}
//interface npc log file path
func GetNpcLogPath() string {
var path string
if IsWindows() {
path = filepath.Join(GetAppPath(), "npc.log")
} else {
path = "/var/log/npc.log"
}
return path
}
//interface pid file path
func GetTmpPath() string {
var path string
if IsWindows() {
path = GetAppPath()
} else {
path = "/tmp"
}
return path
}
//config file path
func GetConfigPath() string {
var path string
if IsWindows() {
path = filepath.Join(GetAppPath(), "conf/npc.conf")
} else {
path = "conf/npc.conf"
}
return path
}
================================================
FILE: lib/common/util.go
================================================
package common
import (
"bytes"
"ehang.io/nps/lib/version"
"encoding/base64"
"encoding/binary"
"errors"
"fmt"
"html/template"
"io"
"io/ioutil"
"net"
"net/http"
"os"
"regexp"
"strconv"
"strings"
"sync"
"ehang.io/nps/lib/crypt"
)
//Get the corresponding IP address through domain name
func GetHostByName(hostname string) string {
if !DomainCheck(hostname) {
return hostname
}
ips, _ := net.LookupIP(hostname)
if ips != nil {
for _, v := range ips {
if v.To4() != nil {
return v.String()
}
}
}
return ""
}
//Check the legality of domain
func DomainCheck(domain string) bool {
var match bool
IsLine := "^((http://)|(https://))?([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,6}(/)"
NotLine := "^((http://)|(https://))?([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,6}"
match, _ = regexp.MatchString(IsLine, domain)
if !match {
match, _ = regexp.MatchString(NotLine, domain)
}
return match
}
//Check if the Request request is validated
func CheckAuth(r *http.Request, user, passwd string) bool {
s := strings.SplitN(r.Header.Get("Authorization"), " ", 2)
if len(s) != 2 {
s = strings.SplitN(r.Header.Get("Proxy-Authorization"), " ", 2)
if len(s) != 2 {
return false
}
}
b, err := base64.StdEncoding.DecodeString(s[1])
if err != nil {
return false
}
pair := strings.SplitN(string(b), ":", 2)
if len(pair) != 2 {
return false
}
return pair[0] == user && pair[1] == passwd
}
//get bool by str
func GetBoolByStr(s string) bool {
switch s {
case "1", "true":
return true
}
return false
}
//get str by bool
func GetStrByBool(b bool) string {
if b {
return "1"
}
return "0"
}
//int
func GetIntNoErrByStr(str string) int {
i, _ := strconv.Atoi(strings.TrimSpace(str))
return i
}
//Get verify value
func Getv
gitextract_d7ijj7nu/
├── .gitattributes
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ └── feature_request.md
│ └── workflows/
│ └── release.yml
├── .gitignore
├── .travis.yml
├── Dockerfile.npc
├── Dockerfile.nps
├── LICENSE
├── Makefile
├── README.md
├── README_zh.md
├── bridge/
│ └── bridge.go
├── build.android.sh
├── build.assets.sh
├── build.sh
├── client/
│ ├── client.go
│ ├── control.go
│ ├── health.go
│ ├── local.go
│ └── register.go
├── conf/
│ ├── clients.json
│ ├── hosts.json
│ ├── multi_account.conf
│ ├── npc.conf
│ ├── nps.conf
│ ├── server.key
│ ├── server.pem
│ └── tasks.json
├── docs/
│ ├── .nojekyll
│ ├── README.md
│ ├── _coverpage.md
│ ├── _navbar.md
│ ├── _sidebar.md
│ ├── api.md
│ ├── contribute.md
│ ├── description.md
│ ├── discuss.md
│ ├── donate.md
│ ├── example.md
│ ├── faq.md
│ ├── feature.md
│ ├── index.html
│ ├── install.md
│ ├── introduction.md
│ ├── npc_extend.md
│ ├── npc_sdk.md
│ ├── nps_extend.md
│ ├── nps_use.md
│ ├── run.md
│ ├── server_config.md
│ ├── thanks.md
│ ├── use.md
│ └── webapi.md
├── go.mod
├── go.sum
├── lib/
│ ├── cache/
│ │ └── lru.go
│ ├── common/
│ │ ├── const.go
│ │ ├── logs.go
│ │ ├── netpackager.go
│ │ ├── pool.go
│ │ ├── pprof.go
│ │ ├── run.go
│ │ └── util.go
│ ├── config/
│ │ ├── config.go
│ │ └── config_test.go
│ ├── conn/
│ │ ├── conn.go
│ │ ├── link.go
│ │ ├── listener.go
│ │ └── snappy.go
│ ├── crypt/
│ │ ├── clientHello.go
│ │ ├── crypt.go
│ │ └── tls.go
│ ├── daemon/
│ │ ├── daemon.go
│ │ └── reload.go
│ ├── file/
│ │ ├── db.go
│ │ ├── file.go
│ │ ├── obj.go
│ │ └── sort.go
│ ├── goroutine/
│ │ └── pool.go
│ ├── install/
│ │ └── install.go
│ ├── pmux/
│ │ ├── pconn.go
│ │ ├── plistener.go
│ │ ├── pmux.go
│ │ └── pmux_test.go
│ ├── rate/
│ │ ├── conn.go
│ │ └── rate.go
│ ├── sheap/
│ │ └── heap.go
│ └── version/
│ └── version.go
├── server/
│ ├── connection/
│ │ └── connection.go
│ ├── proxy/
│ │ ├── base.go
│ │ ├── http.go
│ │ ├── https.go
│ │ ├── p2p.go
│ │ ├── socks5.go
│ │ ├── tcp.go
│ │ ├── transport.go
│ │ ├── transport_windows.go
│ │ └── udp.go
│ ├── server.go
│ ├── test/
│ │ └── test.go
│ └── tool/
│ └── utils.go
└── web/
├── controllers/
│ ├── auth.go
│ ├── base.go
│ ├── client.go
│ ├── index.go
│ └── login.go
├── routers/
│ └── router.go
├── static/
│ ├── css/
│ │ ├── datatables.css
│ │ └── style.css
│ ├── js/
│ │ ├── inspinia.js
│ │ └── language.js
│ └── page/
│ ├── error.html
│ └── languages.xml
└── views/
├── client/
│ ├── add.html
│ ├── edit.html
│ └── list.html
├── index/
│ ├── add.html
│ ├── edit.html
│ ├── hadd.html
│ ├── hedit.html
│ ├── help.html
│ ├── hlist.html
│ ├── index.html
│ └── list.html
├── login/
│ ├── index.html
│ └── register.html
└── public/
├── error.html
└── layout.html
SYMBOL INDEX (605 symbols across 60 files)
FILE: bridge/bridge.go
type Client (line 26) | type Client struct
function NewClient (line 34) | func NewClient(t, f *nps_mux.Mux, s *conn.Conn, vs string) *Client {
type Bridge (line 43) | type Bridge struct
method StartTunnel (line 71) | func (s *Bridge) StartTunnel() error {
method GetHealthFromClient (line 93) | func (s *Bridge) GetHealthFromClient(id int, c *conn.Conn) {
method verifyError (line 158) | func (s *Bridge) verifyError(c *conn.Conn) {
method verifySuccess (line 162) | func (s *Bridge) verifySuccess(c *conn.Conn) {
method cliProcess (line 166) | func (s *Bridge) cliProcess(c *conn.Conn) {
method DelClient (line 212) | func (s *Bridge) DelClient(id int) {
method typeDeal (line 228) | func (s *Bridge) typeDeal(typeVal string, c *conn.Conn, id int, vs str...
method register (line 307) | func (s *Bridge) register(c *conn.Conn) {
method SendLinkInfo (line 314) | func (s *Bridge) SendLinkInfo(clientId int, link *conn.Link, t *file.T...
method ping (line 361) | func (s *Bridge) ping() {
method getConfig (line 391) | func (s *Bridge) getConfig(c *conn.Conn, isPub bool, client *file.Clie...
function NewTunnel (line 57) | func NewTunnel(tunnelPort int, tunnelType string, ipVerify bool, runList...
FILE: client/client.go
type TRPClient (line 22) | type TRPClient struct
method Start (line 54) | func (s *TRPClient) Start() {
method handleMain (line 88) | func (s *TRPClient) handleMain() {
method newUdpConn (line 121) | func (s *TRPClient) newUdpConn(localAddr, rAddr string, md5Password st...
method newChan (line 155) | func (s *TRPClient) newChan() {
method handleChan (line 173) | func (s *TRPClient) handleChan(src net.Conn) {
method handleUdp (line 221) | func (s *TRPClient) handleUdp(serverConn net.Conn) {
method ping (line 281) | func (s *TRPClient) ping() {
method Close (line 295) | func (s *TRPClient) Close() {
method closing (line 299) | func (s *TRPClient) closing() {
function NewRPClient (line 37) | func NewRPClient(svraddr string, vKey string, bridgeConnType string, pro...
FILE: client/control.go
function GetTaskStatus (line 32) | func GetTaskStatus(path string) {
function StartFromFile (line 90) | func StartFromFile(path string) {
function NewConn (line 184) | func NewConn(tp string, vkey string, server string, connType string, pro...
function NewHttpProxyConn (line 255) | func NewHttpProxyConn(url *url.URL, remoteAddr string) (net.Conn, error) {
function basicAuth (line 282) | func basicAuth(username, password string) string {
function getRemoteAddressFromServer (line 287) | func getRemoteAddressFromServer(rAddr string, localConn *net.UDPConn, md...
function handleP2PUdp (line 303) | func handleP2PUdp(localAddr, rAddr, md5Password, role string) (remoteAdd...
function sendP2PTestMsg (line 352) | func sendP2PTestMsg(localConn *net.UDPConn, remoteAddr1, remoteAddr2, re...
function newUdpConnByAddr (line 453) | func newUdpConnByAddr(addr string) (*net.UDPConn, error) {
function getNextAddr (line 465) | func getNextAddr(addr string, n int) (string, error) {
function getAddrInterval (line 477) | func getAddrInterval(addr1, addr2, addr3 string) (int, error) {
function getRandomPortArr (line 509) | func getRandomPortArr(min, max int) []int {
FILE: client/health.go
function heathCheck (line 20) | func heathCheck(healths []*file.Health, c *conn.Conn) bool {
function session (line 41) | func session(healths []*file.Health, h *sheap.IntHeap) {
function check (line 68) | func check(t *file.Health) {
FILE: client/local.go
type p2pBridge (line 32) | type p2pBridge struct
method SendLinkInfo (line 35) | func (p2pBridge *p2pBridge) SendLinkInfo(clientId int, link *conn.Link...
function CloseLocalServer (line 56) | func CloseLocalServer() {
function startLocalFileServer (line 65) | func startLocalFileServer(config *config.CommonConfig, t *file.Tunnel, v...
function StartLocalServer (line 80) | func StartLocalServer(l *config.LocalServer, config *config.CommonConfig...
function handleUdpMonitor (line 128) | func handleUdpMonitor(config *config.CommonConfig, l *config.LocalServer) {
function handleSecret (line 154) | func handleSecret(localTcpConn net.Conn, config *config.CommonConfig, l ...
function handleP2PVisitor (line 167) | func handleP2PVisitor(localTcpConn net.Conn, config *config.CommonConfig...
function newUdpConn (line 185) | func newUdpConn(localAddr string, config *config.CommonConfig, l *config...
FILE: client/register.go
function RegisterLocalIp (line 11) | func RegisterLocalIp(server string, vKey string, tp string, proxyUrl str...
FILE: lib/cache/lru.go
type Cache (line 9) | type Cache struct
method Add (line 41) | func (c *Cache) Add(key Key, value interface{}) {
method Get (line 55) | func (c *Cache) Get(key Key) (value interface{}, ok bool) {
method Remove (line 64) | func (c *Cache) Remove(key Key) {
method RemoveOldest (line 71) | func (c *Cache) RemoveOldest() {
method removeElement (line 78) | func (c *Cache) removeElement(e *list.Element) {
method Len (line 88) | func (c *Cache) Len() int {
method Clear (line 93) | func (c *Cache) Clear() {
type Key (line 22) | type Key interface
type entry (line 24) | type entry struct
function New (line 32) | func New(maxEntries int) *Cache {
FILE: lib/common/const.go
constant CONN_DATA_SEQ (line 4) | CONN_DATA_SEQ = "*#*"
constant VERIFY_EER (line 5) | VERIFY_EER = "vkey"
constant VERIFY_SUCCESS (line 6) | VERIFY_SUCCESS = "sucs"
constant WORK_MAIN (line 7) | WORK_MAIN = "main"
constant WORK_CHAN (line 8) | WORK_CHAN = "chan"
constant WORK_CONFIG (line 9) | WORK_CONFIG = "conf"
constant WORK_REGISTER (line 10) | WORK_REGISTER = "rgst"
constant WORK_SECRET (line 11) | WORK_SECRET = "sert"
constant WORK_FILE (line 12) | WORK_FILE = "file"
constant WORK_P2P (line 13) | WORK_P2P = "p2pm"
constant WORK_P2P_VISITOR (line 14) | WORK_P2P_VISITOR = "p2pv"
constant WORK_P2P_PROVIDER (line 15) | WORK_P2P_PROVIDER = "p2pp"
constant WORK_P2P_CONNECT (line 16) | WORK_P2P_CONNECT = "p2pc"
constant WORK_P2P_SUCCESS (line 17) | WORK_P2P_SUCCESS = "p2ps"
constant WORK_P2P_END (line 18) | WORK_P2P_END = "p2pe"
constant WORK_P2P_LAST (line 19) | WORK_P2P_LAST = "p2pl"
constant WORK_STATUS (line 20) | WORK_STATUS = "stus"
constant RES_MSG (line 21) | RES_MSG = "msg0"
constant RES_CLOSE (line 22) | RES_CLOSE = "clse"
constant NEW_UDP_CONN (line 23) | NEW_UDP_CONN = "udpc"
constant NEW_TASK (line 24) | NEW_TASK = "task"
constant NEW_CONF (line 25) | NEW_CONF = "conf"
constant NEW_HOST (line 26) | NEW_HOST = "host"
constant CONN_TCP (line 27) | CONN_TCP = "tcp"
constant CONN_UDP (line 28) | CONN_UDP = "udp"
constant CONN_TEST (line 29) | CONN_TEST = "TST"
constant UnauthorizedBytes (line 30) | UnauthorizedBytes = `HTTP/1.1 401 Unauthorized
constant ConnectionFailBytes (line 35) | ConnectionFailBytes = `HTTP/1.1 404 Not Found
FILE: lib/common/logs.go
constant MaxMsgLen (line 8) | MaxMsgLen = 5000
function init (line 12) | func init() {
function GetLogMsg (line 18) | func GetLogMsg() string {
type StoreMsg (line 22) | type StoreMsg struct
method Init (line 25) | func (lg *StoreMsg) Init(config string) error {
method WriteMsg (line 29) | func (lg *StoreMsg) WriteMsg(when time.Time, msg string, level int) er...
method Destroy (line 42) | func (lg *StoreMsg) Destroy() {
method Flush (line 46) | func (lg *StoreMsg) Flush() {
FILE: lib/common/netpackager.go
type NetPackager (line 13) | type NetPackager interface
constant ipV4 (line 19) | ipV4 = 1
constant domainName (line 20) | domainName = 3
constant ipV6 (line 21) | ipV6 = 4
type UDPHeader (line 24) | type UDPHeader struct
method Write (line 103) | func (h *UDPHeader) Write(w io.Writer) error {
function NewUDPHeader (line 30) | func NewUDPHeader(rsv uint16, frag uint8, addr *Addr) *UDPHeader {
type Addr (line 38) | type Addr struct
method String (line 44) | func (addr *Addr) String() string {
method Decode (line 48) | func (addr *Addr) Decode(b []byte) error {
method Encode (line 72) | func (addr *Addr) Encode(b []byte) (int, error) {
type UDPDatagram (line 120) | type UDPDatagram struct
method Write (line 189) | func (d *UDPDatagram) Write(w io.Writer) error {
function ReadUDPDatagram (line 125) | func ReadUDPDatagram(r io.Reader) (*UDPDatagram, error) {
function NewUDPDatagram (line 182) | func NewUDPDatagram(header *UDPHeader, data []byte) *UDPDatagram {
function ToSocksAddr (line 206) | func ToSocksAddr(addr net.Addr) *Addr {
FILE: lib/common/pool.go
constant PoolSize (line 7) | PoolSize = 64 * 1024
constant PoolSizeSmall (line 8) | PoolSizeSmall = 100
constant PoolSizeUdp (line 9) | PoolSizeUdp = 1472 + 200
constant PoolSizeCopy (line 10) | PoolSizeCopy = 32 << 10
function PutBufPoolUdp (line 39) | func PutBufPoolUdp(buf []byte) {
function PutBufPoolCopy (line 45) | func PutBufPoolCopy(buf []byte) {
function GetBufPoolCopy (line 51) | func GetBufPoolCopy() []byte {
function PutBufPoolMax (line 55) | func PutBufPoolMax(buf []byte) {
type copyBufferPool (line 61) | type copyBufferPool struct
method New (line 65) | func (Self *copyBufferPool) New() {
method Get (line 73) | func (Self *copyBufferPool) Get() []byte {
method Put (line 78) | func (Self *copyBufferPool) Put(x []byte) {
function newPool (line 89) | func newPool() {
function init (line 93) | func init() {
FILE: lib/common/pprof.go
function InitPProfFromFile (line 10) | func InitPProfFromFile() {
function InitPProfFromArg (line 18) | func InitPProfFromArg(arg string) {
function runPProf (line 24) | func runPProf(ipPort string) {
FILE: lib/common/run.go
function GetRunPath (line 12) | func GetRunPath() string {
function GetInstallPath (line 21) | func GetInstallPath() string {
function GetAppPath (line 32) | func GetAppPath() string {
function IsWindows (line 40) | func IsWindows() bool {
function GetLogPath (line 48) | func GetLogPath() string {
function GetNpcLogPath (line 59) | func GetNpcLogPath() string {
function GetTmpPath (line 70) | func GetTmpPath() string {
function GetConfigPath (line 81) | func GetConfigPath() string {
FILE: lib/common/util.go
function GetHostByName (line 25) | func GetHostByName(hostname string) string {
function DomainCheck (line 41) | func DomainCheck(domain string) bool {
function CheckAuth (line 53) | func CheckAuth(r *http.Request, user, passwd string) bool {
function GetBoolByStr (line 75) | func GetBoolByStr(s string) bool {
function GetStrByBool (line 84) | func GetStrByBool(b bool) string {
function GetIntNoErrByStr (line 92) | func GetIntNoErrByStr(str string) int {
function Getverifyval (line 98) | func Getverifyval(vkey string) string {
function ChangeHostAndHeader (line 103) | func ChangeHostAndHeader(r *http.Request, host string, header string, ad...
function ReadAllFromFile (line 127) | func ReadAllFromFile(filePath string) ([]byte, error) {
function FileExists (line 137) | func FileExists(name string) bool {
function TestTcpPort (line 147) | func TestTcpPort(port int) bool {
function TestUdpPort (line 161) | func TestUdpPort(port int) bool {
function BinaryWrite (line 177) | func BinaryWrite(raw *bytes.Buffer, v ...string) {
function GetWriteStr (line 184) | func GetWriteStr(v ...string) []byte {
function InStrArr (line 196) | func InStrArr(arr []string, val string) bool {
function InIntArr (line 206) | func InIntArr(arr []int, val int) bool {
function GetPorts (line 216) | func GetPorts(p string) []int {
function IsPort (line 240) | func IsPort(p string) bool {
function FormatAddress (line 252) | func FormatAddress(s string) string {
function GetIpByAddr (line 260) | func GetIpByAddr(addr string) string {
function GetPortByAddr (line 266) | func GetPortByAddr(addr string) int {
function CopyBuffer (line 278) | func CopyBuffer(dst io.Writer, src io.Reader, label ...string) (written ...
function GetLocalUdpAddr (line 309) | func GetLocalUdpAddr() (net.Conn, error) {
function ParseStr (line 318) | func ParseStr(str string) (string, error) {
function GetEnvMap (line 332) | func GetEnvMap() map[string]string {
function TrimArr (line 345) | func TrimArr(arr []string) []string {
function IsArrContains (line 356) | func IsArrContains(arr []string, val string) bool {
function RemoveArrVal (line 369) | func RemoveArrVal(arr []string, val string) []string {
function BytesToNum (line 380) | func BytesToNum(b []byte) int {
function GeSynctMapLen (line 390) | func GeSynctMapLen(m sync.Map) int {
function GetExtFromPath (line 399) | func GetExtFromPath(path string) string {
function GetExternalIp (line 410) | func GetExternalIp() string {
function GetIntranetIp (line 424) | func GetIntranetIp() (error, string) {
function IsPublicIP (line 440) | func IsPublicIP(IP net.IP) bool {
function GetServerIpByClientIp (line 459) | func GetServerIpByClientIp(clientIp net.IP) string {
function PrintVersion (line 467) | func PrintVersion() {
FILE: lib/config/config.go
type CommonConfig (line 13) | type CommonConfig struct
type LocalServer (line 23) | type LocalServer struct
type Config (line 31) | type Config struct
function NewConfig (line 41) | func NewConfig(path string) (c *Config, err error) {
function getTitleContent (line 102) | func getTitleContent(s string) string {
function dealCommon (line 107) | func dealCommon(s string) *CommonConfig {
function dealHost (line 158) | func dealHost(s string) *file.Host {
function dealHealth (line 191) | func dealHealth(s string) *file.Health {
function dealTunnel (line 218) | func dealTunnel(s string) *file.Tunnel {
function dealMultiUser (line 266) | func dealMultiUser(s string) map[string]string {
function delLocalService (line 280) | func delLocalService(s string) *LocalServer {
function getAllTitle (line 303) | func getAllTitle(content string) (arr []string, err error) {
function splitStr (line 321) | func splitStr(s string) (configDataArr []string) {
FILE: lib/config/config_test.go
function TestReg (line 9) | func TestReg(t *testing.T) {
function TestDealCommon (line 51) | func TestDealCommon(t *testing.T) {
function TestGetTitleContent (line 64) | func TestGetTitleContent(t *testing.T) {
FILE: lib/conn/conn.go
type Conn (line 28) | type Conn struct
method readRequest (line 38) | func (s *Conn) readRequest(buf []byte) (n int, err error) {
method GetHost (line 61) | func (s *Conn) GetHost() (method, address string, rb []byte, err error...
method GetShortLenContent (line 94) | func (s *Conn) GetShortLenContent() (b []byte, err error) {
method GetShortContent (line 106) | func (s *Conn) GetShortContent(l int) (b []byte, err error) {
method ReadLen (line 112) | func (s *Conn) ReadLen(cLen int, buf []byte) (int, error) {
method GetLen (line 122) | func (s *Conn) GetLen() (int, error) {
method WriteLenContent (line 128) | func (s *Conn) WriteLenContent(buf []byte) (err error) {
method ReadFlag (line 137) | func (s *Conn) ReadFlag() (string, error) {
method SetAlive (line 143) | func (s *Conn) SetAlive(tp string) {
method SetReadDeadlineBySecond (line 158) | func (s *Conn) SetReadDeadlineBySecond(t time.Duration) {
method GetLinkInfo (line 170) | func (s *Conn) GetLinkInfo() (lk *Link, err error) {
method SendHealthInfo (line 176) | func (s *Conn) SendHealthInfo(info, status string) (int, error) {
method GetHealthInfo (line 183) | func (s *Conn) GetHealthInfo() (info string, status bool, err error) {
method GetHostInfo (line 201) | func (s *Conn) GetHostInfo() (h *file.Host, err error) {
method GetConfigInfo (line 210) | func (s *Conn) GetConfigInfo() (c *file.Client, err error) {
method GetTaskInfo (line 222) | func (s *Conn) GetTaskInfo() (t *file.Tunnel, err error) {
method SendInfo (line 231) | func (s *Conn) SendInfo(t interface{}, flag string) (int, error) {
method getInfo (line 257) | func (s *Conn) getInfo(t interface{}) (err error) {
method Close (line 272) | func (s *Conn) Close() error {
method Write (line 277) | func (s *Conn) Write(b []byte) (int, error) {
method Read (line 282) | func (s *Conn) Read(b []byte) (n int, err error) {
method WriteClose (line 296) | func (s *Conn) WriteClose() (int, error) {
method WriteMain (line 301) | func (s *Conn) WriteMain() (int, error) {
method WriteConfig (line 306) | func (s *Conn) WriteConfig() (int, error) {
method WriteChan (line 311) | func (s *Conn) WriteChan() (int, error) {
method GetAddStatus (line 316) | func (s *Conn) GetAddStatus() (b bool) {
method WriteAddOk (line 321) | func (s *Conn) WriteAddOk() error {
method WriteAddFail (line 325) | func (s *Conn) WriteAddFail() error {
method LocalAddr (line 330) | func (s *Conn) LocalAddr() net.Addr {
method RemoteAddr (line 334) | func (s *Conn) RemoteAddr() net.Addr {
method SetDeadline (line 338) | func (s *Conn) SetDeadline(t time.Time) error {
method SetWriteDeadline (line 342) | func (s *Conn) SetWriteDeadline(t time.Time) error {
method SetReadDeadline (line 346) | func (s *Conn) SetReadDeadline(t time.Time) error {
function NewConn (line 34) | func NewConn(conn net.Conn) *Conn {
function GetLenBytes (line 351) | func GetLenBytes(buf []byte) (b []byte, err error) {
function SetUdpSession (line 364) | func SetUdpSession(sess *kcp.UDPSession) {
function CopyWaitGroup (line 376) | func CopyWaitGroup(conn1, conn2 net.Conn, crypt bool, snappy bool, rate ...
function GetConn (line 407) | func GetConn(conn net.Conn, cpt, snappy bool, rt *rate.Rate, isServer bo...
type LenConn (line 419) | type LenConn struct
method Write (line 427) | func (c *LenConn) Write(p []byte) (n int, err error) {
function NewLenConn (line 424) | func NewLenConn(conn io.Writer) *LenConn {
FILE: lib/conn/link.go
type Secret (line 5) | type Secret struct
function NewSecret (line 10) | func NewSecret(p string, conn *Conn) *Secret {
type Link (line 17) | type Link struct
type Option (line 27) | type Option
type Options (line 29) | type Options struct
function NewLink (line 35) | func NewLink(connType string, host string, crypt bool, compress bool, re...
function newOptions (line 49) | func newOptions(opts ...Option) Options {
function LinkTimeout (line 59) | func LinkTimeout(t time.Duration) Option {
FILE: lib/conn/listener.go
function NewTcpListenerAndProcess (line 11) | func NewTcpListenerAndProcess(addr string, f func(c net.Conn), listener ...
function NewKcpListenerAndProcess (line 21) | func NewKcpListenerAndProcess(addr string, f func(c net.Conn)) error {
function Accept (line 39) | func Accept(l net.Listener, f func(c net.Conn)) {
FILE: lib/conn/snappy.go
type SnappyConn (line 10) | type SnappyConn struct
method Write (line 25) | func (s *SnappyConn) Write(b []byte) (n int, err error) {
method Read (line 36) | func (s *SnappyConn) Read(b []byte) (n int, err error) {
method Close (line 40) | func (s *SnappyConn) Close() error {
function NewSnappyConn (line 16) | func NewSnappyConn(conn io.ReadWriteCloser) *SnappyConn {
FILE: lib/crypt/clientHello.go
type CurveID (line 7) | type CurveID
type SignatureScheme (line 8) | type SignatureScheme
constant statusTypeOCSP (line 11) | statusTypeOCSP uint8 = 1
constant extensionServerName (line 12) | extensionServerName uint16 = 0
constant extensionStatusRequest (line 13) | extensionStatusRequest uint16 = 5
constant extensionSupportedCurves (line 14) | extensionSupportedCurves uint16 = 10
constant extensionSupportedPoints (line 15) | extensionSupportedPoints uint16 = 11
constant extensionSignatureAlgorithms (line 16) | extensionSignatureAlgorithms uint16 = 13
constant extensionALPN (line 17) | extensionALPN uint16 = 16
constant extensionSCT (line 18) | extensionSCT uint16 = 18
constant extensionSessionTicket (line 19) | extensionSessionTicket uint16 = 35
constant extensionNextProtoNeg (line 20) | extensionNextProtoNeg uint16 = 13172
constant extensionRenegotiationInfo (line 21) | extensionRenegotiationInfo uint16 = 0xff01
constant scsvRenegotiation (line 22) | scsvRenegotiation uint16 = 0x00ff
type ClientHelloMsg (line 25) | type ClientHelloMsg struct
method GetServerName (line 46) | func (m *ClientHelloMsg) GetServerName() string {
method Unmarshal (line 50) | func (m *ClientHelloMsg) Unmarshal(data []byte) bool {
FILE: lib/crypt/crypt.go
function AesEncrypt (line 15) | func AesEncrypt(origData, key []byte) ([]byte, error) {
function AesDecrypt (line 29) | func AesDecrypt(crypted, key []byte) ([]byte, error) {
function PKCS5Padding (line 43) | func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
function PKCS5UnPadding (line 50) | func PKCS5UnPadding(origData []byte) (error, []byte) {
function Md5 (line 60) | func Md5(s string) string {
function GetRandomString (line 67) | func GetRandomString(l int) string {
FILE: lib/crypt/tls.go
function InitTls (line 23) | func InitTls() {
function NewTlsServerConn (line 33) | func NewTlsServerConn(conn net.Conn) net.Conn {
function NewTlsClientConn (line 44) | func NewTlsClientConn(conn net.Conn) net.Conn {
function generateKeyPair (line 51) | func generateKeyPair(CommonName string) (rawCert, rawKey []byte, err err...
FILE: lib/daemon/daemon.go
function InitDaemon (line 15) | func InitDaemon(f string, runPath string, pidPath string) {
function reload (line 49) | func reload(f string, pidPath string) {
function status (line 69) | func status(f string, pidPath string) bool {
function start (line 86) | func start(osArgs []string, f string, pidPath, runPath string) {
function stop (line 102) | func stop(f string, p string, pidPath string) {
FILE: lib/daemon/reload.go
function init (line 15) | func init() {
FILE: lib/file/db.go
type DbUtils (line 16) | type DbUtils struct
method GetClientList (line 49) | func (s *DbUtils) GetClientList(start, length int, search, sort, order...
method GetIdByVerifyKey (line 76) | func (s *DbUtils) GetIdByVerifyKey(vKey string, addr string) (id int, ...
method NewTask (line 94) | func (s *DbUtils) NewTask(t *Tunnel) (err error) {
method UpdateTask (line 112) | func (s *DbUtils) UpdateTask(t *Tunnel) error {
method DelTask (line 118) | func (s *DbUtils) DelTask(id int) error {
method GetTaskByMd5Password (line 125) | func (s *DbUtils) GetTaskByMd5Password(p string) (t *Tunnel) {
method GetTask (line 136) | func (s *DbUtils) GetTask(id int) (t *Tunnel, err error) {
method DelHost (line 145) | func (s *DbUtils) DelHost(id int) error {
method IsHostExist (line 151) | func (s *DbUtils) IsHostExist(h *Host) bool {
method NewHost (line 164) | func (s *DbUtils) NewHost(t *Host) error {
method GetHost (line 177) | func (s *DbUtils) GetHost(start, length int, id int, search string) ([...
method DelClient (line 200) | func (s *DbUtils) DelClient(id int) error {
method NewClient (line 206) | func (s *DbUtils) NewClient(c *Client) error {
method VerifyVkey (line 239) | func (s *DbUtils) VerifyVkey(vkey string, id int) (res bool) {
method VerifyUserName (line 252) | func (s *DbUtils) VerifyUserName(username string, id int) (res bool) {
method UpdateClient (line 265) | func (s *DbUtils) UpdateClient(t *Client) error {
method IsPubClient (line 274) | func (s *DbUtils) IsPubClient(id int) bool {
method GetClient (line 282) | func (s *DbUtils) GetClient(id int) (c *Client, err error) {
method GetClientIdByVkey (line 291) | func (s *DbUtils) GetClientIdByVkey(vkey string) (id int, err error) {
method GetHostById (line 309) | func (s *DbUtils) GetHostById(id int) (h *Host, err error) {
method GetInfoByHost (line 319) | func (s *DbUtils) GetInfoByHost(host string, r *http.Request) (h *Host...
function GetDb (line 26) | func GetDb() *DbUtils {
function GetMapKeys (line 37) | func GetMapKeys(m sync.Map, isSort bool, sortKey, order string) (keys []...
FILE: lib/file/file.go
function NewJsonDb (line 17) | func NewJsonDb(runPath string) *JsonDb {
type JsonDb (line 26) | type JsonDb struct
method LoadTaskFromJsonFile (line 40) | func (s *JsonDb) LoadTaskFromJsonFile() {
method LoadClientFromJsonFile (line 57) | func (s *JsonDb) LoadClientFromJsonFile() {
method LoadHostFromJsonFile (line 77) | func (s *JsonDb) LoadHostFromJsonFile() {
method GetClient (line 94) | func (s *JsonDb) GetClient(id int) (c *Client, err error) {
method StoreHostToJsonFile (line 105) | func (s *JsonDb) StoreHostToJsonFile() {
method StoreTasksToJsonFile (line 113) | func (s *JsonDb) StoreTasksToJsonFile() {
method StoreClientsToJsonFile (line 121) | func (s *JsonDb) StoreClientsToJsonFile() {
method GetClientId (line 127) | func (s *JsonDb) GetClientId() int32 {
method GetTaskId (line 131) | func (s *JsonDb) GetTaskId() int32 {
method GetHostId (line 135) | func (s *JsonDb) GetHostId() int32 {
function loadSyncMapFromFile (line 139) | func loadSyncMapFromFile(filePath string, f func(value string)) {
function storeSyncMapToFile (line 149) | func storeSyncMapToFile(m sync.Map, filePath string) {
FILE: lib/file/obj.go
type Flow (line 13) | type Flow struct
method Add (line 20) | func (s *Flow) Add(in, out int64) {
type Config (line 27) | type Config struct
type Client (line 34) | type Client struct
method CutConn (line 75) | func (s *Client) CutConn() {
method AddConn (line 79) | func (s *Client) AddConn() {
method GetConn (line 83) | func (s *Client) GetConn() bool {
method HasTunnel (line 91) | func (s *Client) HasTunnel(t *Tunnel) (exist bool) {
method GetTunnelNum (line 103) | func (s *Client) GetTunnelNum() (num int) {
method HasHost (line 114) | func (s *Client) HasHost(h *Host) bool {
function NewClient (line 57) | func NewClient(vKey string, noStore bool, noDisplay bool) *Client {
type Tunnel (line 127) | type Tunnel struct
type Health (line 149) | type Health struct
type Host (line 162) | type Host struct
type Target (line 181) | type Target struct
method GetRandomTarget (line 193) | func (s *Target) GetRandomTarget() (string, error) {
type MultiAccount (line 189) | type MultiAccount struct
FILE: lib/file/sort.go
type Pair (line 10) | type Pair struct
type PairList (line 18) | type PairList
method Swap (line 20) | func (p PairList) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
method Len (line 21) | func (p PairList) Len() int { return len(p) }
method Less (line 22) | func (p PairList) Less(i, j int) bool {
function sortClientByKey (line 30) | func sortClientByKey(m sync.Map, sortKey, order string) (res []int) {
FILE: lib/goroutine/pool.go
type connGroup (line 12) | type connGroup struct
function newConnGroup (line 19) | func newConnGroup(dst, src io.ReadWriteCloser, wg *sync.WaitGroup, n *in...
function copyConnGroup (line 28) | func copyConnGroup(group interface{}) {
type Conns (line 43) | type Conns struct
function NewConns (line 50) | func NewConns(c1 io.ReadWriteCloser, c2 net.Conn, flow *file.Flow, wg *s...
function copyConns (line 59) | func copyConns(group interface{}) {
FILE: lib/install/install.go
constant SysvScript (line 21) | SysvScript = `#!/bin/sh
constant SystemdScript (line 112) | SystemdScript = `[Unit]
function UpdateNps (line 137) | func UpdateNps() {
function UpdateNpc (line 144) | func UpdateNpc() {
type release (line 151) | type release struct
function downloadLatest (line 155) | func downloadLatest(bin string) string {
function copyStaticFile (line 193) | func copyStaticFile(srcPath, bin string) string {
function InstallNpc (line 229) | func InstallNpc() {
function InstallNps (line 240) | func InstallNps() string {
function MkidrDirAll (line 268) | func MkidrDirAll(path string, v ...string) {
function CopyDir (line 276) | func CopyDir(srcPath string, destPath string) error {
function copyFile (line 313) | func copyFile(src, dest string) (w int64, err error) {
function pathExists (line 348) | func pathExists(path string) (bool, error) {
function chMod (line 359) | func chMod(name string, mode os.FileMode) {
FILE: lib/pmux/pconn.go
type PortConn (line 8) | type PortConn struct
method Read (line 23) | func (pConn *PortConn) Read(b []byte) (n int, err error) {
method Write (line 45) | func (pConn *PortConn) Write(b []byte) (n int, err error) {
method Close (line 49) | func (pConn *PortConn) Close() error {
method LocalAddr (line 53) | func (pConn *PortConn) LocalAddr() net.Addr {
method RemoteAddr (line 57) | func (pConn *PortConn) RemoteAddr() net.Addr {
method SetDeadline (line 61) | func (pConn *PortConn) SetDeadline(t time.Time) error {
method SetReadDeadline (line 65) | func (pConn *PortConn) SetReadDeadline(t time.Time) error {
method SetWriteDeadline (line 69) | func (pConn *PortConn) SetWriteDeadline(t time.Time) error {
function newPortConn (line 15) | func newPortConn(conn net.Conn, rs []byte, readMore bool) *PortConn {
FILE: lib/pmux/plistener.go
type PortListener (line 8) | type PortListener struct
method Accept (line 22) | func (pListener *PortListener) Accept() (net.Conn, error) {
method Close (line 33) | func (pListener *PortListener) Close() error {
method Addr (line 42) | func (pListener *PortListener) Addr() net.Addr {
function NewPortListener (line 15) | func NewPortListener(connCh chan *PortConn, addr net.Addr) *PortListener {
FILE: lib/pmux/pmux.go
constant HTTP_GET (line 21) | HTTP_GET = 716984
constant HTTP_POST (line 22) | HTTP_POST = 807983
constant HTTP_HEAD (line 23) | HTTP_HEAD = 726965
constant HTTP_PUT (line 24) | HTTP_PUT = 808585
constant HTTP_DELETE (line 25) | HTTP_DELETE = 686976
constant HTTP_CONNECT (line 26) | HTTP_CONNECT = 677978
constant HTTP_OPTIONS (line 27) | HTTP_OPTIONS = 798084
constant HTTP_TRACE (line 28) | HTTP_TRACE = 848265
constant CLIENT (line 29) | CLIENT = 848384
constant ACCEPT_TIME_OUT (line 30) | ACCEPT_TIME_OUT = 10
type PortMux (line 33) | type PortMux struct
method Start (line 57) | func (pMux *PortMux) Start() error {
method process (line 82) | func (pMux *PortMux) process(conn net.Conn) {
method Close (line 140) | func (pMux *PortMux) Close() error {
method GetClientListener (line 152) | func (pMux *PortMux) GetClientListener() net.Listener {
method GetHttpListener (line 156) | func (pMux *PortMux) GetHttpListener() net.Listener {
method GetHttpsListener (line 160) | func (pMux *PortMux) GetHttpsListener() net.Listener {
method GetManagerListener (line 164) | func (pMux *PortMux) GetManagerListener() net.Listener {
function NewPortMux (line 44) | func NewPortMux(port int, managerHost string) *PortMux {
FILE: lib/pmux/pmux_test.go
function TestPortMux_Close (line 10) | func TestPortMux_Close(t *testing.T) {
FILE: lib/rate/conn.go
type rateConn (line 7) | type rateConn struct
method Read (line 19) | func (s *rateConn) Read(b []byte) (n int, err error) {
method Write (line 27) | func (s *rateConn) Write(b []byte) (n int, err error) {
method Close (line 35) | func (s *rateConn) Close() error {
function NewRateConn (line 12) | func NewRateConn(conn io.ReadWriteCloser, rate *Rate) io.ReadWriteCloser {
FILE: lib/rate/rate.go
type Rate (line 8) | type Rate struct
method Start (line 25) | func (s *Rate) Start() {
method add (line 29) | func (s *Rate) add(size int64) {
method ReturnBucket (line 38) | func (s *Rate) ReturnBucket(size int64) {
method Stop (line 43) | func (s *Rate) Stop() {
method Get (line 47) | func (s *Rate) Get(size int64) {
method session (line 65) | func (s *Rate) session() {
function NewRate (line 16) | func NewRate(addSize int64) *Rate {
FILE: lib/sheap/heap.go
type IntHeap (line 3) | type IntHeap
method Len (line 5) | func (h IntHeap) Len() int { return len(h) }
method Less (line 6) | func (h IntHeap) Less(i, j int) bool { return h[i] < h[j] }
method Swap (line 7) | func (h IntHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
method Push (line 9) | func (h *IntHeap) Push(x interface{}) {
method Pop (line 15) | func (h *IntHeap) Pop() interface{} {
FILE: lib/version/version.go
constant VERSION (line 3) | VERSION = "0.26.10"
function GetVersion (line 6) | func GetVersion() string {
FILE: server/connection/connection.go
function InitConnectionService (line 19) | func InitConnectionService() {
function GetBridgeListener (line 35) | func GetBridgeListener(tp string) (net.Listener, error) {
function GetHttpListener (line 48) | func GetHttpListener() (net.Listener, error) {
function GetHttpsListener (line 57) | func GetHttpsListener() (net.Listener, error) {
function GetWebManagerListener (line 66) | func GetWebManagerListener() (net.Listener, error) {
function getTcpListener (line 75) | func getTcpListener(ip, p string) (net.Listener, error) {
FILE: server/proxy/base.go
type Service (line 16) | type Service interface
type NetBridge (line 21) | type NetBridge interface
type BaseServer (line 26) | type BaseServer struct
method FlowAdd (line 44) | func (s *BaseServer) FlowAdd(in, out int64) {
method FlowAddHost (line 52) | func (s *BaseServer) FlowAddHost(host *file.Host, in, out int64) {
method writeConnFail (line 60) | func (s *BaseServer) writeConnFail(c net.Conn) {
method auth (line 66) | func (s *BaseServer) auth(r *http.Request, c *conn.Conn, u, p string) ...
method CheckFlowAndConnNum (line 76) | func (s *BaseServer) CheckFlowAndConnNum(client *file.Client) error {
method DealClient (line 87) | func (s *BaseServer) DealClient(c *conn.Conn, client *file.Client, add...
function NewBaseServer (line 34) | func NewBaseServer(bridge *bridge.Bridge, task *file.Tunnel) *BaseServer {
FILE: server/proxy/http.go
type httpServer (line 25) | type httpServer struct
method Start (line 57) | func (s *httpServer) Start() error {
method Close (line 91) | func (s *httpServer) Close() error {
method handleTunneling (line 104) | func (s *httpServer) handleTunneling(w http.ResponseWriter, r *http.Re...
method handleHttp (line 117) | func (s *httpServer) handleHttp(c *conn.Conn, r *http.Request) {
method NewServer (line 265) | func (s *httpServer) NewServer(port int, scheme string) *http.Server {
function NewHttp (line 38) | func NewHttp(bridge *bridge.Bridge, c *file.Tunnel, httpPort, httpsPort ...
function resetReqMethod (line 255) | func resetReqMethod(method string) string {
FILE: server/proxy/https.go
type HttpsServer (line 19) | type HttpsServer struct
method Start (line 36) | func (https *HttpsServer) Start() error {
method Close (line 91) | func (https *HttpsServer) Close() error {
method NewHttps (line 96) | func (https *HttpsServer) NewHttps(l net.Listener, certFile string, ke...
method handleHttps (line 103) | func (https *HttpsServer) handleHttps(c net.Conn) {
function NewHttpsServer (line 25) | func NewHttpsServer(l net.Listener, bridge NetBridge, useCache bool, cac...
type HttpsListener (line 131) | type HttpsListener struct
method Accept (line 142) | func (httpsListener *HttpsListener) Accept() (net.Conn, error) {
method Close (line 151) | func (httpsListener *HttpsListener) Close() error {
method Addr (line 156) | func (httpsListener *HttpsListener) Addr() net.Addr {
function NewHttpsListener (line 137) | func NewHttpsListener(l net.Listener) *HttpsListener {
function GetServerNameFromClientHello (line 161) | func GetServerNameFromClientHello(c net.Conn) (string, []byte) {
function buildHttpsRequest (line 178) | func buildHttpsRequest(hostName string) *http.Request {
FILE: server/proxy/p2p.go
type P2PServer (line 12) | type P2PServer struct
method Start (line 31) | func (s *P2PServer) Start() error {
method handleP2P (line 52) | func (s *P2PServer) handleP2P(addr *net.UDPAddr, str string) {
type p2p (line 19) | type p2p struct
function NewP2PServer (line 24) | func NewP2PServer(p2pPort int) *P2PServer {
FILE: server/proxy/socks5.go
constant ipV4 (line 17) | ipV4 = 1
constant domainName (line 18) | domainName = 3
constant ipV6 (line 19) | ipV6 = 4
constant connectMethod (line 20) | connectMethod = 1
constant bindMethod (line 21) | bindMethod = 2
constant associateMethod (line 22) | associateMethod = 3
constant maxUDPPacketSize (line 27) | maxUDPPacketSize = 1476
constant succeeded (line 31) | succeeded uint8 = iota
constant serverFailure (line 32) | serverFailure
constant notAllowed (line 33) | notAllowed
constant networkUnreachable (line 34) | networkUnreachable
constant hostUnreachable (line 35) | hostUnreachable
constant connectionRefused (line 36) | connectionRefused
constant ttlExpired (line 37) | ttlExpired
constant commandNotSupported (line 38) | commandNotSupported
constant addrTypeNotSupported (line 39) | addrTypeNotSupported
constant UserPassAuth (line 43) | UserPassAuth = uint8(2)
constant userAuthVersion (line 44) | userAuthVersion = uint8(1)
constant authSuccess (line 45) | authSuccess = uint8(0)
constant authFailure (line 46) | authFailure = uint8(1)
type Sock5ModeServer (line 49) | type Sock5ModeServer struct
method handleRequest (line 55) | func (s *Sock5ModeServer) handleRequest(c net.Conn) {
method sendReply (line 88) | func (s *Sock5ModeServer) sendReply(c net.Conn, rep uint8) {
method doConnect (line 109) | func (s *Sock5ModeServer) doConnect(c net.Conn, command uint8) {
method handleConnect (line 150) | func (s *Sock5ModeServer) handleConnect(c net.Conn) {
method handleBind (line 155) | func (s *Sock5ModeServer) handleBind(c net.Conn) {
method sendUdpReply (line 157) | func (s *Sock5ModeServer) sendUdpReply(writeConn net.Conn, c net.Conn,...
method handleUDP (line 176) | func (s *Sock5ModeServer) handleUDP(c net.Conn) {
method handleConn (line 284) | func (s *Sock5ModeServer) handleConn(c net.Conn) {
method Auth (line 321) | func (s *Sock5ModeServer) Auth(c net.Conn) error {
method Start (line 371) | func (s *Sock5ModeServer) Start() error {
method Close (line 393) | func (s *Sock5ModeServer) Close() error {
function NewSock5ModeServer (line 385) | func NewSock5ModeServer(bridge NetBridge, task *file.Tunnel) *Sock5ModeS...
FILE: server/proxy/tcp.go
type TunnelModeServer (line 19) | type TunnelModeServer struct
method Start (line 35) | func (s *TunnelModeServer) Start() error {
method Close (line 49) | func (s *TunnelModeServer) Close() error {
function NewTunnelModeServer (line 26) | func NewTunnelModeServer(process process, bridge NetBridge, task *file.T...
type WebServer (line 54) | type WebServer struct
method Start (line 59) | func (s *WebServer) Start() error {
method Close (line 85) | func (s *WebServer) Close() error {
function NewWebServer (line 90) | func NewWebServer(bridge *bridge.Bridge) *WebServer {
type process (line 96) | type process
function ProcessTunnel (line 99) | func ProcessTunnel(c *conn.Conn, s *TunnelModeServer) error {
function ProcessHttp (line 110) | func ProcessHttp(c *conn.Conn, s *TunnelModeServer) error {
FILE: server/proxy/transport.go
function HandleTrans (line 14) | func HandleTrans(c *conn.Conn, s *TunnelModeServer) error {
constant SO_ORIGINAL_DST (line 22) | SO_ORIGINAL_DST = 80
function getAddress (line 24) | func getAddress(conn net.Conn) (string, error) {
FILE: server/proxy/transport_windows.go
function HandleTrans (line 9) | func HandleTrans(c *conn.Conn, s *TunnelModeServer) error {
FILE: server/proxy/udp.go
type UdpModeServer (line 17) | type UdpModeServer struct
method Start (line 31) | func (s *UdpModeServer) Start() error {
method process (line 55) | func (s *UdpModeServer) process(addr *net.UDPAddr, data []byte) {
method Close (line 97) | func (s *UdpModeServer) Close() error {
function NewUdpModeServer (line 23) | func NewUdpModeServer(bridge *bridge.Bridge, task *file.Tunnel) *UdpMode...
FILE: server/server.go
function init (line 31) | func init() {
function InitFromCsv (line 36) | func InitFromCsv() {
function DealBridgeTask (line 54) | func DealBridgeTask() {
function StartNewServer (line 88) | func StartNewServer(bridgePort int, cnf *file.Tunnel, bridgeType string,...
function dealClientFlow (line 114) | func dealClientFlow() {
function NewMode (line 126) | func NewMode(Bridge *bridge.Bridge, c *file.Tunnel) proxy.Service {
function StopServer (line 160) | func StopServer(id int) error {
function AddTask (line 185) | func AddTask(t *file.Tunnel) error {
function StartTask (line 218) | func StartTask(id int) error {
function DelTask (line 230) | func DelTask(id int) error {
function GetTunnel (line 241) | func GetTunnel(start, length int, typeVal string, clientId int, search s...
function GetClientList (line 277) | func GetClientList(start, length int, search, sort, order string, client...
function dealClientData (line 283) | func dealClientData() {
function DelTunnelAndHostByClientId (line 316) | func DelTunnelAndHostByClientId(clientId int, justDelNoStore bool) {
function DelClientConnect (line 348) | func DelClientConnect(clientId int) {
function GetDashboardData (line 352) | func GetDashboardData() map[string]interface{} {
function flowSession (line 449) | func flowSession(m time.Duration) {
FILE: server/test/test.go
function TestServerConfig (line 13) | func TestServerConfig() {
function isInArr (line 67) | func isInArr(arr *[]int, val int, remark string, tp string) {
FILE: server/tool/utils.go
function StartSystemInfo (line 21) | func StartSystemInfo() {
function InitAllowPort (line 28) | func InitAllowPort() {
function TestServerPort (line 33) | func TestServerPort(p int, m string) (b bool) {
function getSeverStatus (line 53) | func getSeverStatus() {
FILE: web/controllers/auth.go
type AuthController (line 11) | type AuthController struct
method GetAuthKey (line 15) | func (s *AuthController) GetAuthKey() {
method GetTime (line 37) | func (s *AuthController) GetTime() {
FILE: web/controllers/base.go
type BaseController (line 17) | type BaseController struct
method Prepare (line 24) | func (s *BaseController) Prepare() {
method display (line 66) | func (s *BaseController) display(tpl ...string) {
method error (line 90) | func (s *BaseController) error() {
method getEscapeString (line 97) | func (s *BaseController) getEscapeString(key string) string {
method GetIntNoErr (line 102) | func (s *BaseController) GetIntNoErr(key string, def ...int) int {
method GetBoolNoErr (line 112) | func (s *BaseController) GetBoolNoErr(key string, def ...bool) bool {
method AjaxOk (line 122) | func (s *BaseController) AjaxOk(str string) {
method AjaxErr (line 129) | func (s *BaseController) AjaxErr(str string) {
method AjaxTable (line 144) | func (s *BaseController) AjaxTable(list interface{}, cnt int, recordsT...
method GetAjaxParams (line 161) | func (s *BaseController) GetAjaxParams() (start, limit int) {
method SetInfo (line 165) | func (s *BaseController) SetInfo(name string) {
method SetType (line 169) | func (s *BaseController) SetType(name string) {
method CheckUserAuth (line 173) | func (s *BaseController) CheckUserAuth() {
function ajax (line 136) | func ajax(str string, status int) map[string]interface{} {
FILE: web/controllers/client.go
type ClientController (line 11) | type ClientController struct
method List (line 15) | func (s *ClientController) List() {
method Add (line 40) | func (s *ClientController) Add() {
method GetClient (line 75) | func (s *ClientController) GetClient() {
method Edit (line 91) | func (s *ClientController) Edit() {
method ChangeStatus (line 153) | func (s *ClientController) ChangeStatus() {
method Del (line 166) | func (s *ClientController) Del() {
FILE: web/controllers/index.go
type IndexController (line 11) | type IndexController struct
method Index (line 15) | func (s *IndexController) Index() {
method Help (line 21) | func (s *IndexController) Help() {
method Tcp (line 26) | func (s *IndexController) Tcp() {
method Udp (line 32) | func (s *IndexController) Udp() {
method Socks5 (line 38) | func (s *IndexController) Socks5() {
method Http (line 44) | func (s *IndexController) Http() {
method File (line 49) | func (s *IndexController) File() {
method Secret (line 55) | func (s *IndexController) Secret() {
method P2p (line 60) | func (s *IndexController) P2p() {
method Host (line 66) | func (s *IndexController) Host() {
method All (line 72) | func (s *IndexController) All() {
method GetTunnel (line 80) | func (s *IndexController) GetTunnel() {
method Add (line 88) | func (s *IndexController) Add() {
method GetOneTunnel (line 128) | func (s *IndexController) GetOneTunnel() {
method Edit (line 140) | func (s *IndexController) Edit() {
method Stop (line 184) | func (s *IndexController) Stop() {
method Del (line 192) | func (s *IndexController) Del() {
method Start (line 200) | func (s *IndexController) Start() {
method HostList (line 208) | func (s *IndexController) HostList() {
method GetHost (line 222) | func (s *IndexController) GetHost() {
method DelHost (line 236) | func (s *IndexController) DelHost() {
method AddHost (line 244) | func (s *IndexController) AddHost() {
method EditHost (line 275) | func (s *IndexController) EditHost() {
FILE: web/controllers/login.go
type LoginController (line 15) | type LoginController struct
method Index (line 26) | func (self *LoginController) Index() {
method Verify (line 37) | func (self *LoginController) Verify() {
method doLogin (line 48) | func (self *LoginController) doLogin(username, password string, explic...
method Register (line 108) | func (self *LoginController) Register() {
method Out (line 140) | func (self *LoginController) Out() {
type record (line 21) | type record struct
function clearIprecord (line 145) | func clearIprecord() {
FILE: web/routers/router.go
function Init (line 8) | func Init() {
FILE: web/static/js/inspinia.js
function localStorageSupport (line 170) | function localStorageSupport() {
function SmoothlyMenu (line 238) | function SmoothlyMenu() {
function WinMove (line 260) | function WinMove() {
FILE: web/static/js/language.js
function xml2json (line 3) | function xml2json(Xml) {
function setCookie (line 21) | function setCookie (c_name, value, expiredays) {
function getCookie (line 27) | function getCookie (c_name) {
function setchartlang (line 40) | function setchartlang (langobj,chartobj) {
function langreply (line 134) | function langreply(langstr) {
function submitform (line 141) | function submitform(action, url, postdata) {
function changeunit (line 167) | function changeunit(limit) {
Condensed preview — 129 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (786K chars).
[
{
"path": ".gitattributes",
"chars": 93,
"preview": "*.js linguist-language=golang\n*.css linguist-language=golang\n*.html linguist-language=golang\n"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.md",
"chars": 846,
"preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: bug\nassignees: ''\n\n---\n\n**Describe the "
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.md",
"chars": 604,
"preview": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: enhancement\nassignees: ''\n\n---\n\n**Is"
},
{
"path": ".github/workflows/release.yml",
"chars": 5091,
"preview": "name: Release\n\non:\n release:\n types: [published]\n branches: [ master ]\n\njobs:\n\n build_assets:\n \n runs-on: "
},
{
"path": ".gitignore",
"chars": 14,
"preview": ".idea\nnps\nnpc\n"
},
{
"path": ".travis.yml",
"chars": 1369,
"preview": "language: go\n\ngo:\n - 1.14.x\nservices:\n - docker\nscript:\n - GOPROXY=direct go test -v ./cmd/nps/\nos:\n - linux\nbefore_"
},
{
"path": "Dockerfile.npc",
"chars": 284,
"preview": "FROM golang:1.15 as builder\nARG GOPROXY=direct\nWORKDIR /go/src/ehang.io/nps\nCOPY . .\nRUN go get -d -v ./... \nRUN CGO_ENA"
},
{
"path": "Dockerfile.nps",
"chars": 327,
"preview": "FROM golang:1.15 as builder\nARG GOPROXY=direct\nWORKDIR /go/src/ehang.io/nps\nCOPY . .\nRUN go get -d -v ./... \nRUN CGO_ENA"
},
{
"path": "LICENSE",
"chars": 35126,
"preview": " GNU GENERAL PUBLIC LICENSE\n Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Found"
},
{
"path": "Makefile",
"chars": 1653,
"preview": "SOURCE_FILES?=./...\nTEST_PATTERN?=.\nTEST_OPTIONS?=\n\nexport PATH := ./bin:$(PATH)\nexport GO111MODULE := on\nexport GOPROXY"
},
{
"path": "README.md",
"chars": 4187,
"preview": "\n# NPS\n  \n\nfunc RegisterLocalIp(server stri"
},
{
"path": "conf/clients.json",
"chars": 0,
"preview": ""
},
{
"path": "conf/hosts.json",
"chars": 0,
"preview": ""
},
{
"path": "conf/multi_account.conf",
"chars": 41,
"preview": "# key -> user | value -> pwd \nnpc=npc.pwd"
},
{
"path": "conf/npc.conf",
"chars": 1228,
"preview": "[common]\nserver_addr=127.0.0.1:8024\nconn_type=tcp\nvkey=123\nauto_reconnection=true\nmax_conn=1000\nflow_limit=1000\nrate_lim"
},
{
"path": "conf/nps.conf",
"chars": 1926,
"preview": "appname = nps\n#Boot mode(dev|pro)\nrunmode = dev\n\n#HTTP(S) proxy port, no startup if empty\nhttp_proxy_ip=0.0.0.0\nhttp_pro"
},
{
"path": "conf/server.key",
"chars": 1679,
"preview": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA2MVLOHvgU8FCp6LgQrPfaWcGygrsRk7TL9hbT8MxbCRUSLV7\nLbt3q5Knz8eTN4NWmwE6L5g"
},
{
"path": "conf/server.pem",
"chars": 1346,
"preview": "-----BEGIN CERTIFICATE-----\nMIIDtTCCAp2gAwIBAgIJAPXRSiP0Fs7sMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV\nBAYTAkFVMRMwEQYDVQQIEwpTb21"
},
{
"path": "conf/tasks.json",
"chars": 0,
"preview": ""
},
{
"path": "docs/.nojekyll",
"chars": 0,
"preview": ""
},
{
"path": "docs/README.md",
"chars": 855,
"preview": "# nps\n \n[\n\n# NPS <small>0.26.10</small>\n\n> 一款轻量级、高性能、功能强大的内网穿透代理服务器\n\n- 几乎支持所有协议\n- 支持内网http代理、内网socks5代理、p2p等\n- 简"
},
{
"path": "docs/_navbar.md",
"chars": 251,
"preview": "* [](https://github.com/ehang-io/nps/starg"
},
{
"path": "docs/_sidebar.md",
"chars": 434,
"preview": "* 入门\n * [安装](install.md)\n * [启动](run.md)\n * [使用示例](example.md)\n* 服务端\n * [介绍](introduction.md)\n * [使用](nps_use.md)\n "
},
{
"path": "docs/api.md",
"chars": 776,
"preview": "# web api\n\n需要开启请先去掉`nps.conf`中`auth_key`的注释并配置一个合适的密钥\n## webAPI验证说明\n- 采用auth_key的验证方式\n- 在提交的每个请求后面附带两个参数,`auth_key` 和`ti"
},
{
"path": "docs/contribute.md",
"chars": 128,
"preview": "# 贡献\n\n- 如果遇到bug可以直接提交至dev分支\n- 使用遇到问题可以通过issues反馈\n- 项目处于开发阶段,还有很多待完善的地方,如果可以贡献代码,请提交 PR 至 dev 分支\n- 如果有新的功能特性反馈,可以通过issues"
},
{
"path": "docs/description.md",
"chars": 569,
"preview": "# 说明\n## 获取用户真实ip\n如需使用需要在`nps.conf`中设置`http_add_origin_header=true`\n\n在域名代理模式中,可以通过request请求 header 中的 X-Forwarded-For 和 X"
},
{
"path": "docs/discuss.md",
"chars": 69,
"preview": "# 交流群\n\n\n"
},
{
"path": "docs/donate.md",
"chars": 229,
"preview": "# 捐助\n如果您觉得nps对你有帮助,欢迎给予我们一定捐助,也是帮助nps更好的发展。\n\n## 支付宝\n\n- 开启服务端,假设公网服务器ip为1.1.1.1,配置文件中`bridge_port`为8024,配置文件中`web_port`为8080\n- 访问1.1.1.1:8080\n- 在客户端管理中创建"
},
{
"path": "docs/faq.md",
"chars": 341,
"preview": "# FAQ\n\n- 服务端无法启动\n```\n服务端默认配置启用了8024,8080,80,443端口,端口冲突无法启动,请修改配置\n```\n- 客户端无法连接服务端\n```\n请检查配置文件中的所有端口是否在安全组,防火墙放行\n请检查vkey是"
},
{
"path": "docs/feature.md",
"chars": 5449,
"preview": "# 扩展功能\n## 缓存支持\n对于web站点来说,一些静态文件往往消耗更大的流量,且在内网穿透中,静态文件还需到客户端获取一次,这将导致更大的流量消耗。nps在域名解析代理中支持对静态文件进行缓存。\n\n即假设一个站点有a.css,nps将只"
},
{
"path": "docs/index.html",
"chars": 1294,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <title>Document</title>\n <meta http-equiv=\"X-U"
},
{
"path": "docs/install.md",
"chars": 324,
"preview": "# 安装\n## 安装包安装\n [releases](https://github.com/ehang-io/nps/releases)\n\n下载对应的系统版本即可,服务端和客户端是单独的\n\n## 源码安装\n- 安装源码\n```go get -"
},
{
"path": "docs/introduction.md",
"chars": 138,
"preview": "\n# 介绍\n\n可在网页上配置和管理各个tcp、udp隧道、内网站点代理,http、ht"
},
{
"path": "docs/npc_extend.md",
"chars": 589,
"preview": "# 增强功能\n## nat类型检测\n```\n ./npc nat -stun_addr=stun.stunprotocol.org:3478\n```\n如果p2p双方都是Symmetric Nat,肯定不能成功,其他组合都有较大成功率。`st"
},
{
"path": "docs/npc_sdk.md",
"chars": 354,
"preview": "# npc sdk文档\n\n```\n命令行模式启动客户端\n从v0.26.10开始,此函数会阻塞,直到客户端退出返回,请自行管理是否重连\np0->连接地址\np1->vkey\np2->连接类型(tcp or udp)\np3->连接代理\n\nexte"
},
{
"path": "docs/nps_extend.md",
"chars": 2807,
"preview": "# 增强功能\n## 使用https\n\n**方式一:** 类似于nginx实现https的处理\n\n在配置文件中将https_proxy_port设置为443或者其他你想配置的端口,将`https_just_proxy`设置为false,nps"
},
{
"path": "docs/nps_use.md",
"chars": 760,
"preview": "# 使用\n**提示:使用web模式时,服务端执行文件必须在项目根目录,否则无法正确加载配置文件**\n\n## web管理\n\n进入web界面,公网ip:web界面端口(默认8080),密码默认为123\n\n进入web管理界面,有详细的说明\n\n##"
},
{
"path": "docs/run.md",
"chars": 858,
"preview": "# 启动\n## 服务端\n下载完服务器压缩包后,解压,然后进入解压后的文件夹\n\n- 执行安装命令\n\n对于linux|darwin ```sudo ./nps install```\n\n对于windows,管理员身份运行cmd,进入安装目录 ``"
},
{
"path": "docs/server_config.md",
"chars": 650,
"preview": "# 服务端配置文件\n- /etc/nps/conf/nps.conf\n\n名称 | 含义\n---|---\nweb_port | web管理端口\nweb_password | web界面管理密码\nweb_username | web界面管理账号"
},
{
"path": "docs/thanks.md",
"chars": 206,
"preview": "Thanks [jetbrains](https://www.jetbrains.com/?from=nps) for providing development tools for nps\n\n<html>\n<img src=\"https:"
},
{
"path": "docs/use.md",
"chars": 3552,
"preview": "# 基本使用\n## 无配置文件模式\n此模式的各种配置在服务端web管理中完成,客户端除运行一条命令外无需任何其他设置\n```\n ./npc -server=ip:port -vkey=web界面中显示的密钥\n```\n## 注册到系统服务(开"
},
{
"path": "docs/webapi.md",
"chars": 3154,
"preview": "获取客户端列表\r\n\r\n```\r\nPOST /client/list/\r\n```\r\n\r\n\r\n| 参数 | 含义 |\r\n| --- | --- |\r\n| search | 搜索 |\r\n| order | 排序asc 正序 desc倒序 |\r\n|"
},
{
"path": "go.mod",
"chars": 1501,
"preview": "module ehang.io/nps\n\ngo 1.15\n\nrequire (\n\tehang.io/nps-mux v0.0.0-20210407130203-4afa0c10c992\n\tfyne.io/fyne/v2 v2.0.2\n\tgi"
},
{
"path": "go.sum",
"chars": 26199,
"preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\nehang.io/nps-mux v0.0.0-2021040713020"
},
{
"path": "lib/cache/lru.go",
"chars": 2459,
"preview": "package cache\n\nimport (\n\t\"container/list\"\n\t\"sync\"\n)\n\n// Cache is an LRU cache. It is safe for concurrent access.\ntype Ca"
},
{
"path": "lib/common/const.go",
"chars": 976,
"preview": "package common\n\nconst (\n\tCONN_DATA_SEQ = \"*#*\" //Separator\n\tVERIFY_EER = \"vkey\"\n\tVERIFY_SUCCESS = \"sucs\"\n\t"
},
{
"path": "lib/common/logs.go",
"chars": 721,
"preview": "package common\n\nimport (\n\t\"github.com/astaxie/beego/logs\"\n\t\"time\"\n)\n\nconst MaxMsgLen = 5000\n\nvar logMsgs string\n\nfunc in"
},
{
"path": "lib/common/netpackager.go",
"chars": 4145,
"preview": "package common\n\nimport (\n\t\"bytes\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"net\"\n\t\"strconv\"\n)\n\ntype NetPackager "
},
{
"path": "lib/common/pool.go",
"chars": 1693,
"preview": "package common\n\nimport (\n\t\"sync\"\n)\n\nconst PoolSize = 64 * 1024\nconst PoolSizeSmall = 100\nconst PoolSizeUdp = 1472 + 200\n"
},
{
"path": "lib/common/pprof.go",
"chars": 520,
"preview": "package common\n\nimport (\n\t\"github.com/astaxie/beego\"\n\t\"github.com/astaxie/beego/logs\"\n\t\"net/http\"\n\t_ \"net/http/pprof\"\n)\n"
},
{
"path": "lib/common/run.go",
"chars": 1711,
"preview": "package common\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n)\n\n//Get the currently selected configuration file directory\n"
},
{
"path": "lib/common/util.go",
"chars": 9236,
"preview": "package common\n\nimport (\n\t\"bytes\"\n\t\"ehang.io/nps/lib/version\"\n\t\"encoding/base64\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"fmt\"\n\t\"h"
},
{
"path": "lib/config/config.go",
"chars": 7892,
"preview": "package config\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"ehang.io/nps/lib/common\"\n\t\"ehang.io/nps/lib/file\"\n)\n\nt"
},
{
"path": "lib/config/config_test.go",
"chars": 1038,
"preview": "package config\n\nimport (\n\t\"log\"\n\t\"regexp\"\n\t\"testing\"\n)\n\nfunc TestReg(t *testing.T) {\n\tcontent := `\n[common]\nserver=127.0"
},
{
"path": "lib/conn/conn.go",
"chars": 9418,
"preview": "package conn\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"ehang.io/nps/lib/goroutine\"\n\t\"encoding/binary\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"g"
},
{
"path": "lib/conn/link.go",
"chars": 1058,
"preview": "package conn\n\nimport \"time\"\n\ntype Secret struct {\n\tPassword string\n\tConn *Conn\n}\n\nfunc NewSecret(p string, conn *Con"
},
{
"path": "lib/conn/listener.go",
"chars": 1024,
"preview": "package conn\n\nimport (\n\t\"net\"\n\t\"strings\"\n\n\t\"github.com/astaxie/beego/logs\"\n\t\"github.com/xtaci/kcp-go\"\n)\n\nfunc NewTcpList"
},
{
"path": "lib/conn/snappy.go",
"chars": 878,
"preview": "package conn\n\nimport (\n\t\"errors\"\n\t\"io\"\n\n\t\"github.com/golang/snappy\"\n)\n\ntype SnappyConn struct {\n\tw *snappy.Writer\n\tr *sn"
},
{
"path": "lib/crypt/clientHello.go",
"chars": 6332,
"preview": "package crypt\n\nimport (\n\t\"strings\"\n)\n\ntype CurveID uint16\ntype SignatureScheme uint16\n\nconst (\n\tstatusTypeOCSP "
},
{
"path": "lib/crypt/crypt.go",
"chars": 1849,
"preview": "package crypt\n\nimport (\n\t\"bytes\"\n\t\"crypto/aes\"\n\t\"crypto/cipher\"\n\t\"crypto/md5\"\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"math/rand\"\n\t\"t"
},
{
"path": "lib/crypt/tls.go",
"chars": 2060,
"preview": "package crypt\n\nimport (\n\t\"crypto/rand\"\n\t\"crypto/rsa\"\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"crypto/x509/pkix\"\n\t\"encoding/pem\"\n\t\""
},
{
"path": "lib/daemon/daemon.go",
"chars": 2754,
"preview": "package daemon\n\nimport (\n\t\"io/ioutil\"\n\t\"log\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"ehang.io/nps/lib"
},
{
"path": "lib/daemon/reload.go",
"chars": 355,
"preview": "// +build !windows\n\npackage daemon\n\nimport (\n\t\"os\"\n\t\"os/signal\"\n\t\"path/filepath\"\n\t\"syscall\"\n\n\t\"ehang.io/nps/lib/common\"\n"
},
{
"path": "lib/file/db.go",
"chars": 7863,
"preview": "package file\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"sort\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"ehang.io/nps/lib/common\"\n\t\"ehang.io/np"
},
{
"path": "lib/file/file.go",
"chars": 4400,
"preview": "package file\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"github.com/astaxie/beego/logs\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"s"
},
{
"path": "lib/file/obj.go",
"chars": 4418,
"preview": "package file\n\nimport (\n\t\"strings\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"ehang.io/nps/lib/rate\"\n\t\"github.com/pkg/errors\"\n)\n\nt"
},
{
"path": "lib/file/sort.go",
"chars": 1135,
"preview": "package file\n\nimport (\n\t\"reflect\"\n\t\"sort\"\n\t\"sync\"\n)\n\n// A data structure to hold a key/value pair.\ntype Pair struct {\n\tk"
},
{
"path": "lib/goroutine/pool.go",
"chars": 1610,
"preview": "package goroutine\n\nimport (\n\t\"ehang.io/nps/lib/common\"\n\t\"ehang.io/nps/lib/file\"\n\t\"github.com/panjf2000/ants/v2\"\n\t\"io\"\n\t\""
},
{
"path": "lib/install/install.go",
"chars": 9702,
"preview": "package install\n\nimport (\n\t\"ehang.io/nps/lib/common\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"github.com/c4milo/unpackit\"\n\t\"i"
},
{
"path": "lib/pmux/pconn.go",
"chars": 1332,
"preview": "package pmux\n\nimport (\n\t\"net\"\n\t\"time\"\n)\n\ntype PortConn struct {\n\tConn net.Conn\n\trs []byte\n\treadMore bool\n\tstar"
},
{
"path": "lib/pmux/plistener.go",
"chars": 787,
"preview": "package pmux\n\nimport (\n\t\"errors\"\n\t\"net\"\n)\n\ntype PortListener struct {\n\tnet.Listener\n\tconnCh chan *PortConn\n\taddr net"
},
{
"path": "lib/pmux/pmux.go",
"chars": 3815,
"preview": "// This module is used for port reuse\n// Distinguish client, web manager , HTTP and HTTPS according to the difference of"
},
{
"path": "lib/pmux/pmux_test.go",
"chars": 695,
"preview": "package pmux\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/astaxie/beego/logs\"\n)\n\nfunc TestPortMux_Close(t *testing.T) {\n\tl"
},
{
"path": "lib/rate/conn.go",
"chars": 559,
"preview": "package rate\n\nimport (\n\t\"io\"\n)\n\ntype rateConn struct {\n\tconn io.ReadWriteCloser\n\trate *Rate\n}\n\nfunc NewRateConn(conn io."
},
{
"path": "lib/rate/rate.go",
"chars": 1430,
"preview": "package rate\n\nimport (\n\t\"sync/atomic\"\n\t\"time\"\n)\n\ntype Rate struct {\n\tbucketSize int64\n\tbucketSurplusSize int64\n\tb"
},
{
"path": "lib/sheap/heap.go",
"chars": 505,
"preview": "package sheap\n\ntype IntHeap []int64\n\nfunc (h IntHeap) Len() int { return len(h) }\nfunc (h IntHeap) Less(i, j i"
},
{
"path": "lib/version/version.go",
"chars": 168,
"preview": "package version\n\nconst VERSION = \"0.26.10\"\n\n// Compulsory minimum version, Minimum downward compatibility to this versio"
},
{
"path": "server/connection/connection.go",
"chars": 2366,
"preview": "package connection\n\nimport (\n\t\"net\"\n\t\"os\"\n\t\"strconv\"\n\n\t\"ehang.io/nps/lib/pmux\"\n\t\"github.com/astaxie/beego\"\n\t\"github.com/"
},
{
"path": "server/proxy/base.go",
"chars": 2524,
"preview": "package proxy\n\nimport (\n\t\"errors\"\n\t\"net\"\n\t\"net/http\"\n\t\"sync\"\n\n\t\"ehang.io/nps/bridge\"\n\t\"ehang.io/nps/lib/common\"\n\t\"ehang."
},
{
"path": "server/proxy/http.go",
"chars": 7118,
"preview": "package proxy\n\nimport (\n\t\"bufio\"\n\t\"crypto/tls\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httputil\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"st"
},
{
"path": "server/proxy/https.go",
"chars": 5219,
"preview": "package proxy\n\nimport (\n\t\"net\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"sync\"\n\n\t\"ehang.io/nps/lib/cache\"\n\t\"ehang.io/nps/lib/common\"\n\t\"eh"
},
{
"path": "server/proxy/p2p.go",
"chars": 1637,
"preview": "package proxy\n\nimport (\n\t\"net\"\n\t\"strings\"\n\t\"time\"\n\n\t\"ehang.io/nps/lib/common\"\n\t\"github.com/astaxie/beego/logs\"\n)\n\ntype P"
},
{
"path": "server/proxy/socks5.go",
"chars": 9256,
"preview": "package proxy\n\nimport (\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"io\"\n\t\"net\"\n\t\"strconv\"\n\n\t\"ehang.io/nps/lib/common\"\n\t\"ehang.io/nps/"
},
{
"path": "server/proxy/tcp.go",
"chars": 3276,
"preview": "package proxy\n\nimport (\n\t\"errors\"\n\t\"net\"\n\t\"net/http\"\n\t\"path/filepath\"\n\t\"strconv\"\n\n\t\"ehang.io/nps/bridge\"\n\t\"ehang.io/nps/"
},
{
"path": "server/proxy/transport.go",
"chars": 961,
"preview": "// +build !windows\n\npackage proxy\n\nimport (\n\t\"net\"\n\t\"strconv\"\n\t\"syscall\"\n\n\t\"ehang.io/nps/lib/common\"\n\t\"ehang.io/nps/lib/"
},
{
"path": "server/proxy/transport_windows.go",
"chars": 145,
"preview": "// +build windows\n\npackage proxy\n\nimport (\n\t\"ehang.io/nps/lib/conn\"\n)\n\nfunc HandleTrans(c *conn.Conn, s *TunnelModeServe"
},
{
"path": "server/proxy/udp.go",
"chars": 2468,
"preview": "package proxy\n\nimport (\n\t\"io\"\n\t\"net\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"ehang.io/nps/bridge\"\n\t\"ehang.io/nps/lib/common\"\n\t\"eha"
},
{
"path": "server/server.go",
"chars": 12232,
"preview": "package server\n\nimport (\n\t\"ehang.io/nps/lib/version\"\n\t\"errors\"\n\t\"math\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"eh"
},
{
"path": "server/test/test.go",
"chars": 2518,
"preview": "package test\n\nimport (\n\t\"log\"\n\t\"path/filepath\"\n\t\"strconv\"\n\n\t\"ehang.io/nps/lib/common\"\n\t\"ehang.io/nps/lib/file\"\n\t\"github."
},
{
"path": "server/tool/utils.go",
"chars": 2142,
"preview": "package tool\n\nimport (\n\t\"math\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"ehang.io/nps/lib/common\"\n\t\"github.com/astaxie/beego\"\n\t\"github.com/s"
},
{
"path": "web/controllers/auth.go",
"chars": 803,
"preview": "package controllers\n\nimport (\n\t\"encoding/hex\"\n\t\"time\"\n\n\t\"ehang.io/nps/lib/crypt\"\n\t\"github.com/astaxie/beego\"\n)\n\ntype Aut"
},
{
"path": "web/controllers/base.go",
"chars": 5632,
"preview": "package controllers\n\nimport (\n\t\"html\"\n\t\"math\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"ehang.io/nps/lib/common\"\n\t\"ehang.io/nps/l"
},
{
"path": "web/controllers/client.go",
"chars": 4882,
"preview": "package controllers\n\nimport (\n\t\"ehang.io/nps/lib/common\"\n\t\"ehang.io/nps/lib/file\"\n\t\"ehang.io/nps/lib/rate\"\n\t\"ehang.io/np"
},
{
"path": "web/controllers/index.go",
"chars": 8735,
"preview": "package controllers\n\nimport (\n\t\"ehang.io/nps/lib/file\"\n\t\"ehang.io/nps/server\"\n\t\"ehang.io/nps/server/tool\"\n\n\t\"github.com/"
},
{
"path": "web/controllers/login.go",
"chars": 4468,
"preview": "package controllers\n\nimport (\n\t\"math/rand\"\n\t\"net\"\n\t\"sync\"\n\t\"time\"\n\n\t\"ehang.io/nps/lib/common\"\n\t\"ehang.io/nps/lib/file\"\n\t"
},
{
"path": "web/routers/router.go",
"chars": 826,
"preview": "package routers\n\nimport (\n\t\"ehang.io/nps/web/controllers\"\n\t\"github.com/astaxie/beego\"\n)\n\nfunc Init() {\n\tweb_base_url := "
},
{
"path": "web/static/css/datatables.css",
"chars": 16205,
"preview": "/*\n * This combined file was created by the DataTables downloader builder:\n * https://datatables.net/download\n *\n * To"
},
{
"path": "web/static/css/style.css",
"chars": 203857,
"preview": "@import url(\"https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700\");\n@import url(\"https://fonts.googleapis."
},
{
"path": "web/static/js/inspinia.js",
"chars": 7921,
"preview": "/*\n *\n * INSPINIA - Responsive Admin Theme\n * version 2.9.3\n *\n */\n\n\n$(document).ready(function () {\n\n // Fast fi"
},
{
"path": "web/static/js/language.js",
"chars": 6263,
"preview": "(function ($) {\n\n\tfunction xml2json(Xml) {\n\t\tvar tempvalue, tempJson = {};\n\t\t$(Xml).each(function() {\n\t\t\tvar tagName = ("
},
{
"path": "web/static/page/error.html",
"chars": 182,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <title>nps error</title>\n</head>\n<body>\n404 not f"
},
{
"path": "web/static/page/languages.xml",
"chars": 24111,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<content>\n\n\t<application>NPS</application>\n\n\t<default>en-US</default>\n\n\t<language"
},
{
"path": "web/views/client/add.html",
"chars": 7228,
"preview": "<div class=\"row\">\n <div class=\"col-md-12 col-md-auto\">\n <div class=\"ibox float-e-margins\">\n <h3 cla"
},
{
"path": "web/views/client/edit.html",
"chars": 8064,
"preview": "<div class=\"row\">\n <div class=\"col-md-12 col-md-auto\">\n <div class=\"ibox float-e-margins\">\n <h3 cla"
},
{
"path": "web/views/client/list.html",
"chars": 9450,
"preview": "<div class=\"wrapper wrapper-content animated fadeInRight\">\n\n <div class=\"row\">\n <div class=\"col-lg-12\">\n "
},
{
"path": "web/views/index/add.html",
"chars": 8326,
"preview": "<div class=\"row tile\">\n <div class=\"col-md-12 col-md-auto\">\n <div class=\"ibox float-e-margins\">\n <h"
},
{
"path": "web/views/index/edit.html",
"chars": 8249,
"preview": "<div class=\"row tile\">\n <div class=\"col-md-12 col-md-auto\">\n <div class=\"ibox float-e-margins\">\n <h"
},
{
"path": "web/views/index/hadd.html",
"chars": 6331,
"preview": "<div class=\"row tile\">\n <div class=\"col-md-12 col-md-auto\">\n <div class=\"ibox float-e-margins\">\n <h"
},
{
"path": "web/views/index/hedit.html",
"chars": 6838,
"preview": "<div class=\"row tile\">\n <div class=\"col-md-12 col-md-auto\">\n <div class=\"ibox float-e-margins\">\n <h"
},
{
"path": "web/views/index/help.html",
"chars": 5399,
"preview": "<div class=\"row\">\n <div class=\"col-md-12\">\n <div class=\"tile\">\n <iframe src=\"https://ghbtns.com/git"
},
{
"path": "web/views/index/hlist.html",
"chars": 6935,
"preview": "<div class=\"wrapper wrapper-content animated fadeInRight\">\n\n <div class=\"row\">\n <div class=\"col-lg-12\">\n "
},
{
"path": "web/views/index/index.html",
"chars": 26855,
"preview": "<div class=\"wrapper wrapper-content\">\n <div class=\"row\">\n <div class=\"col-lg-3\">\n <div class=\"ibox "
},
{
"path": "web/views/index/list.html",
"chars": 9730,
"preview": "<div class=\"wrapper wrapper-content animated fadeInRight\">\n\n <div class=\"row\">\n <div class=\"col-lg-12\">\n "
},
{
"path": "web/views/login/index.html",
"chars": 4255,
"preview": "<!DOCTYPE html>\n<html>\n\n<head>\n\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initia"
},
{
"path": "web/views/login/register.html",
"chars": 3381,
"preview": "<!DOCTYPE html>\n<html>\n\n<head>\n\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initia"
},
{
"path": "web/views/public/error.html",
"chars": 260,
"preview": "<div class=\"page-error tile\">\n <h1><i class=\"fa fa-exclamation-circle\"></i> Error 404: Page not found</h1>\n <p>The"
},
{
"path": "web/views/public/layout.html",
"chars": 7833,
"preview": "<!DOCTYPE html>\n<html>\n\n<head>\n\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initia"
}
]
About this extraction
This page contains the full source code of the ehang-io/nps GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 129 files (710.5 KB), approximately 231.8k tokens, and a symbol index with 605 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.