Compare commits

...

24 Commits
v0.1 ... master

Author SHA1 Message Date
22397c6815
В deb пакет добавлен файл конфигурации.
All checks were successful
build / build (push) Successful in 1m28s
release / release (push) Successful in 1m10s
2024-11-06 07:38:55 +07:00
7bfa2786db
Исправлена сборка debian-пакеьа.
All checks were successful
build / build (push) Successful in 1m29s
2024-11-06 02:44:28 +07:00
6fdd75fbb0
updated changelog
All checks were successful
build / build (push) Successful in 1m50s
release / release (push) Successful in 1m29s
2024-11-05 14:34:30 +07:00
c692b8881d
Исправлен баг в методе Server.handleConnection
Some checks failed
build / build (push) Has been cancelled
2024-11-05 14:33:11 +07:00
ffbd6b14fa
Fixed bug "too many colons in address".
All checks were successful
build / build (push) Successful in 1m25s
2024-11-04 15:13:12 +07:00
13a9bd1aa1
Исправлены опечатки в makefile.
All checks were successful
build / build (push) Successful in 2m15s
release / release (push) Successful in 1m18s
2024-11-03 19:14:10 +07:00
26ac2ef39c
Исправлена опечатка в makefile.
Some checks failed
release / release (push) Failing after 1m23s
build / build (push) Successful in 2m17s
2024-11-03 19:10:55 +07:00
4b36ccffaa
Изменена сборка пакета для arm32
Some checks failed
build / build (push) Successful in 1m46s
release / release (push) Failing after 1m20s
2024-11-03 19:05:52 +07:00
9792ba4376
update changelog
All checks were successful
release / release (push) Successful in 1m35s
build / build (push) Successful in 1m50s
2024-11-03 18:28:40 +07:00
ba1b89b252
Исправлена сборка пакета для linux arm32.
All checks were successful
build / build (push) Successful in 1m28s
2024-11-03 18:22:22 +07:00
1dff7ec332
В сборку добавлен пакет linux arm32.
Some checks failed
build / build (push) Failing after 1m16s
2024-11-03 18:15:02 +07:00
c429f40125
Оптимизирован release workflow
All checks were successful
build / build (push) Successful in 1m13s
2024-11-02 21:40:14 +07:00
4f265d32ff
Исправлен release workflow
All checks were successful
build / build (push) Successful in 1m31s
release / release (push) Successful in 1m20s
2024-11-02 21:37:27 +07:00
da585626f8
Исправлен changelog
All checks were successful
build / build (push) Successful in 1m33s
release / release (push) Successful in 1m16s
2024-11-02 21:31:43 +07:00
5dabf72007
Исправлен release workflow
All checks were successful
build / build (push) Successful in 1m15s
release / release (push) Successful in 1m6s
2024-11-02 21:24:54 +07:00
5539cd63e0
Улучшен release workflow
All checks were successful
build / build (push) Successful in 1m16s
release / build (push) Successful in 1m18s
2024-11-02 21:19:26 +07:00
2a1ed25ac5
Доработан release workflow
All checks were successful
build / build (push) Successful in 1m11s
release / build (push) Successful in 1m15s
release / deploy (push) Successful in 5s
2024-11-02 01:03:02 +07:00
4b557c52c2
Исправлен workflow
All checks were successful
build / build (push) Successful in 1m19s
release / build (push) Successful in 1m27s
release / deploy (push) Successful in 6s
2024-11-02 00:51:13 +07:00
772861994f
Workflow - полные ссылки на действия.
Some checks failed
build / build (push) Successful in 2m17s
release / build (push) Successful in 2m1s
release / deploy (push) Failing after 7s
2024-11-02 00:45:45 +07:00
565c843c22
Исправлен release workflow.
Some checks failed
release / build (push) Successful in 1m32s
build / build (push) Successful in 1m31s
release / deploy (push) Failing after 10s
2024-11-02 00:35:53 +07:00
95c6d1cbe1
Имена акция теперь стандартные.
Some checks failed
build / build (push) Successful in 1m42s
release / build (push) Failing after 1m1s
release / deploy (push) Has been skipped
2024-11-02 00:07:39 +07:00
7c9d302917
ПЕреименовано задание в workflow.
All checks were successful
build / build (push) Successful in 1m12s
2024-11-01 23:28:26 +07:00
8dd4b1a7d9
Настроена сборка deb пакета.
All checks were successful
build / linux (push) Successful in 1m15s
2024-11-01 23:26:06 +07:00
a59ad95f63
Добавлен build workflow.
All checks were successful
build / build (push) Successful in 1m34s
build / build_windows (push) Successful in 1m24s
2024-11-01 22:43:08 +07:00
19 changed files with 496 additions and 137 deletions

View File

@ -0,0 +1,80 @@
name: build
run-name: ${{ gitea.actor }} build Transocks
on:
push:
branches:
- "**"
tags-ignore:
- "v*"
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: check-out
uses: https://git.mousesoft.ru/actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true
- name: set-up go
uses: https://git.mousesoft.ru/actions/setup-go@v3
with:
go-version: ">=1.22"
- name: set-up dependencies
run: |
go install github.com/kisielk/errcheck@latest
go install honnef.co/go/tools/cmd/staticcheck@latest
go install github.com/sashamelentyev/usestdlibvars@latest
go install golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow@latest
make vendor
- name: lint
run: make lint
- name: golangci-lint
uses: https://github.com/golangci/golangci-lint-action@v6
with:
version: v1.60
- name: build linux amd64
id: build-amd64
run: |
echo "ARTIFACT=transocks-$(make version)_$(go env GOOS)-amd64" >> $GITHUB_OUTPUT
GOARCH=amd64 make clean build
- name: upload linux amd64
uses: https://git.mousesoft.ru/actions/upload-artifact@v3
with:
name: ${{ steps.build-amd64.outputs.ARTIFACT }}
path: out/bin/*
overwrite: true
- name: build linux arm64
id: build-arm64
run: |
echo "ARTIFACT=transocks-$(make version)_$(go env GOOS)-arm64" >> $GITHUB_OUTPUT
GOARCH=arm64 make clean build
- name: upload linux arm64
uses: https://git.mousesoft.ru/actions/upload-artifact@v3
with:
name: ${{ steps.build-arm64.outputs.ARTIFACT }}
path: out/bin/*
overwrite: true
- name: build linux arm32
id: build-arm32
run: |
echo "ARTIFACT=transocks-$(make version)_$(go env GOOS)-arm32" >> $GITHUB_OUTPUT
GOARCH=arm make clean build
- name: upload linux arm32
uses: https://git.mousesoft.ru/actions/upload-artifact@v3
with:
name: ${{ steps.build-arm32.outputs.ARTIFACT }}
path: out/bin/*
overwrite: true

View File

@ -1,5 +1,7 @@
name: release
run-name: ${{ gitea.actor }} release Transocks
on:
push:
tags:
@ -10,44 +12,81 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: check-out
uses: actions/checkout@v4
- name: set-up qemu
uses: https://git.mousesoft.ru/ms/gitea-action-setup-qemu@v3
- name: set-up docker buildx
uses: https://git.mousesoft.ru/ms/gitea-action-docker-setup-buildx@v3
uses: https://git.mousesoft.ru/actions/checkout@v4
with:
buildkitd-flags: --debug
fetch-depth: 0
fetch-tags: true
- name: login to docker hub
uses: https://git.mousesoft.ru/ms/gitea-action-docker-login@v3
- name: set-up go
uses: https://git.mousesoft.ru/actions/setup-go@v3
with:
registry: git.mousesoft.ru
username: ${{ secrets.API_USER }}
password: ${{ secrets.API_TOKEN }}
go-version: ">=1.22"
- name: set-up dependencies
run: |
go install github.com/kisielk/errcheck@latest
go install honnef.co/go/tools/cmd/staticcheck@latest
go install github.com/sashamelentyev/usestdlibvars@latest
go install golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow@latest
make vendor
- name: lint
run: make lint
- name: golangci-lint
uses: https://github.com/golangci/golangci-lint-action@v6
with:
version: v1.60
- name: build linux amd64
run: GOARCH=amd64 make build pkg-deb
- name: build linux arm64
run: GOARCH=arm64 make build pkg-deb
- name: build linux arm32
run: GOARCH=arm make build pkg-deb
- name: meta
id: meta
env:
SSH_HOST: ${{ secrets.DEB_SSH_HOST }}
run: |
echo IMAGE_CREATED=$(date -u +'%Y-%m-%dT%H:%M:%SZ') | tee -a $GITHUB_OUTPUT
echo IMAGE_VERSION=$(./version.sh n) | tee -a $GITHUB_OUTPUT
echo IMAGE_REVISION=$(git rev-parse HEAD) | tee -a $GITHUB_OUTPUT
echo "VERSION=$(make version)" >> $GITHUB_OUTPUT
echo 'CHANGES<<EOF' >> $GITHUB_OUTPUT
gawk -f scripts/changes.awk -v version=$(make version-number) CHANGELOG.md >> $GITHUB_OUTPUT
echo EOF >> $GITHUB_OUTPUT
mkdir -p out
sed -e "s/DEB_SSH_HOST/$SSH_HOST/g" deploy/dput/mousesoft.json.tpl > out/mousesoft.json
mkdir -p /etc/dput.d/profiles
cp out/mousesoft.json /etc/dput.d/profiles/
- name: build and push
uses: https://git.mousesoft.ru/ms/gitea-action-docker-build-push@v6
- name: deploy packages
env:
SSH_HOST: ${{ secrets.DEB_SSH_HOST }}
SSH_PORT: ${{ secrets.DEB_SSH_PORT }}
SSH_USER: ${{ secrets.DEB_SSH_USER }}
SSH_KEY: ${{ secrets.DEB_SSH_KEY }}
run: |
mkdir -p ~/.ssh/
echo "$SSH_KEY" | tr -d '\r' > ~/.ssh/key
chmod 0600 ~/.ssh/key
cat >>~/.ssh/config <<END
Host $SSH_HOST
IdentitiesOnly yes
User $SSH_USER
IdentityFile ~/.ssh/key
Port $SSH_PORT
StrictHostKeyChecking no
END
find -O1 out -name '*.changes' -exec dput mousesoft \{\} \;
- name: release
uses: https://git.mousesoft.ru/actions/gitea-release-action@v1
with:
context: .
file: Dockerfile
platforms: |
linux/amd64
linux/arm64
pull: true
push: true
no-cache: true
build-args: |
IMAGE_VERSION=${{ steps.meta.outputs.IMAGE_VERSION }}
IMAGE_CREATED=${{ steps.meta.outputs.IMAGE_CREATED }}
tags: |
git.mousesoft.ru/alexey/transocks:${{ steps.meta.outputs.IMAGE_VERSION }}
git.mousesoft.ru/alexey/transocks:latest
title: "Transocks ${{ steps.meta.outputs.VERSION }}"
body: "${{ steps.meta.outputs.CHANGES }}"
files: "out/*.deb"
sha256sum: true
prerelease: true
draft: true

2
.gitignore vendored
View File

@ -12,6 +12,8 @@
# Folders
_obj
_test
out
tmp
# Architecture specific extensions/prefixes
*.[568vq]

View File

@ -3,6 +3,5 @@ linters:
- dupl
- goconst
- gofmt
- golint
- typecheck
- unparam

View File

@ -2,33 +2,44 @@
All notable changes to this project will be documented in this file.
## [Unreleased]
## [1.1.4](https://git.mousesoft.ru/alexey/transocks/releases/tag/v1.1.4) - 2024-11-05
- **Fixed**
- Bug in method `Server.handleConnection`.
## [1.1.3](https://git.mousesoft.ru/alexey/transocks/releases/tag/v1.1.3) - 2024-11-03
- **Added**
- Build linux-arm32 package.
## [1.1.2](https://git.mousesoft.ru/alexey/transocks/releases/tag/v1.1.2) - 2024-11-02
- **Added**
- Build debian packages.
## [1.1.1] - 2019-03-16
### Changed
- Replace `syscall` with `golang.org/x/sys/unix`, contriubted by @otariidae (#14).
- **Changed**
- Replace `syscall` with `golang.org/x/sys/unix`, contributed by @otariidae (#14).
## [1.1.0] - 2018-11-13
### Changed
- Update `github.com/cybozu-go/cmd` to `github.com/cybozu-go/well` (#7, #9).
- Replace TravisCI with CircleCI.
- **Changed**
- Update `github.com/cybozu-go/cmd` to `github.com/cybozu-go/well` (#7, #9).
- Replace TravisCI with CircleCI.
## [1.0.0] - 2016-09-01
### Added
- transocks now adopts [github.com/cybozu-go/well][well] framework.
- **Added**
- transocks now adopts [github.com/cybozu-go/well][well] framework.
As a result, it implements [the common spec][spec] including graceful restart.
### Changed
- The default configuration file path is now `/etc/transocks.toml`.
- "listen" config option becomes optional. Default is "localhost:1081".
- Configuration items for logging is changed.
- **Changed**
- The default configuration file path is now `/etc/transocks.toml`.
- "listen" config option becomes optional. Default is "localhost:1081".
- Configuration items for logging is changed.
[well]: https://github.com/cybozu-go/well
[spec]: https://github.com/cybozu-go/well/blob/master/README.md#specifications
[Unreleased]: https://github.com/cybozu-go/transocks/compare/v1.1.1...HEAD
[1.1.1]: https://github.com/cybozu-go/transocks/compare/v1.1.0...v1.1.1
[1.1.0]: https://github.com/cybozu-go/transocks/compare/v1.0.0...v1.1.0
[1.0.0]: https://github.com/cybozu-go/transocks/compare/v0.1...v1.0.0

View File

@ -1,31 +0,0 @@
# Start by building the application.
FROM docker.io/golang:1.22 AS build
WORKDIR /usr/src/transocks
COPY . .
RUN CGO_ENABLED=0 go build -trimpath -o transocks ./cmd/transocks
# Now copy it into our base image.
FROM gcr.io/distroless/static-debian12:nonroot
COPY --from=build /usr/src/transocks/transocks /usr/bin/transocks
VOLUME [ "/etc/transocks" ]
ENTRYPOINT [ "/usr/bin/transocks" ]
ARG IMAGE_CREATED
ARG IMAGE_VERSION
ARG IMAGE_REVISION
LABEL org.opencontainers.image.created="${IMAGE_CREATED}" \
org.opencontainers.image.authors="MouseSoft" \
org.opencontainers.image.url="https://git.mousesoft.ru/alexey/transocks" \
org.opencontainers.image.documentation="https://git.mousesoft.ru/alexey/transocks/src/branch/master/README.md" \
org.opencontainers.image.source="https://git.mousesoft.ru/alexey/transocks" \
org.opencontainers.image.version="${IMAGE_VERSION}" \
org.opencontainers.image.revision="${IMAGE_REVISION}" \
org.opencontainers.image.vendor="MouseSoft" \
org.opencontainers.image.licenses="MIT" \
org.opencontainers.image.title="transocks - a transparent SOCKS5/HTTP proxy" \
org.opencontainers.image.description="transocks is a background service to redirect TCP connections transparently to a SOCKS5 server or a HTTP proxy server like Squid."

View File

@ -0,0 +1,5 @@
transocks (VERSION) mousesoft-stable; urgency=low
* Initial Release.
-- Aleksei Badiaev <aleksei.badiaev@mousesoft.ru> Sun, 9 Apr 2023 21:45:22 +0700

View File

@ -0,0 +1,8 @@
Source: transocks
Maintainer: Aleksei Badiaev <aleksei.badiaev@mousesoft.ru>
Package: transocks
Section: network
Priority: optional
Architecture: ARCH
Description: transocks - a transparent SOCKS5/HTTP proxy

View File

@ -75,10 +75,10 @@ func NewConfig() *Config {
// It returns non-nil error if the configuration is not valid.
func (c *Config) validate() error {
if c.ProxyURL == nil {
return errors.New("ProxyURL is nil")
return errors.New("proxy URL is nil")
}
if c.Mode != ModeNAT {
return fmt.Errorf("Unknown mode: %s", c.Mode)
return fmt.Errorf("unknown mode: %s", c.Mode)
}
return nil
}

View File

@ -0,0 +1,10 @@
# listening address of transocks.
listen = "localhost:1081" # default is "localhost:1081"
#proxy_url = "socks5://10.20.30.40:1080" # for SOCKS5 server
#proxy_url = "http://10.20.30.40:3128" # for HTTP proxy server
[log]
#filename = "/path/to/file" # default to stderr
level = "info" # critical", error, warning, info, debug
#format = "json" # plain, logfmt, json

View File

@ -0,0 +1,12 @@
{
"allow_unsigned_uploads": true,
"full_upload_log": false,
"fqdn": "DEB_SSH_HOST",
"hash": "sha1",
"interface": "cli",
"incoming": "mini-dinstall/incoming/",
"login": "mini-dinstall",
"meta": "boring",
"method": "scp",
"scp_compress": true
}

View File

@ -12,7 +12,6 @@ import (
"bufio"
"bytes"
"encoding/base64"
"errors"
"fmt"
"net"
"net/http"
@ -51,7 +50,7 @@ func httpDialType(u *url.URL, forward proxy.Dialer) (proxy.Dialer, error) {
func (d *httpDialer) Dial(network, addr string) (c net.Conn, err error) {
req := &http.Request{
Method: "CONNECT",
Method: http.MethodConnect,
URL: &url.URL{Opaque: addr},
Host: addr,
Header: d.header,
@ -60,20 +59,24 @@ func (d *httpDialer) Dial(network, addr string) (c net.Conn, err error) {
if err != nil {
return
}
req.Write(c)
if err = req.Write(c); err != nil {
return
}
// Read response until "\r\n\r\n".
// bufio cannot be used as the connected server may not be
// a HTTP(S) server.
c.SetReadDeadline(time.Now().Add(10 * time.Second))
if err = c.SetReadDeadline(time.Now().Add(10 * time.Second)); err != nil {
return
}
buf := make([]byte, 0, 4096)
b := make([]byte, 1)
state := 0
for {
_, e := c.Read(b)
if e != nil {
c.Close()
return nil, errors.New("reset proxy connection")
if _, err = c.Read(b); err != nil {
_ = c.Close()
return nil, fmt.Errorf("reset proxy connection: %w", err)
}
buf = append(buf, b[0])
switch state {
@ -107,15 +110,21 @@ func (d *httpDialer) Dial(network, addr string) (c net.Conn, err error) {
PARSE:
var zero time.Time
c.SetReadDeadline(zero)
resp, e := http.ReadResponse(bufio.NewReader(bytes.NewBuffer(buf)), req)
if e != nil {
c.Close()
return nil, e
if err = c.SetReadDeadline(zero); err != nil {
return nil, err
}
resp.Body.Close()
if resp.StatusCode != 200 {
c.Close()
resp, err := http.ReadResponse(bufio.NewReader(bytes.NewBuffer(buf)), req)
if err != nil {
_ = c.Close()
return nil, err
}
_ = resp.Body.Close()
if resp.StatusCode != http.StatusOK {
_ = c.Close()
return nil, fmt.Errorf("proxy returns %s", resp.Status)
}

View File

@ -23,8 +23,9 @@ func TestHTTPDialer(t *testing.T) {
if err != nil {
t.Fatal(err)
}
defer conn.Close()
conn.Write([]byte("GET / HTTP/1.1\r\nHost: www.yahoo.com:80\r\nConnection: close\r\n\r\n"))
io.Copy(os.Stdout, conn)
defer func() { _ = conn.Close() }()
_, _ = conn.Write([]byte("GET / HTTP/1.1\r\nHost: www.yahoo.com:80\r\nConnection: close\r\n\r\n"))
_, _ = io.Copy(os.Stdout, conn)
}

167
makefile Normal file
View File

@ -0,0 +1,167 @@
# transocks makefile
# ==================
SHELL := /usr/bin/env bash
PROJECT_ID := transocks
PROJECT_NAME ?= Transocks
BIN_SUFFIX :=
TMPDIR ?= $(CURDIR)/tmp
OUTDIR ?= $(CURDIR)/out
BINDIR ?= $(OUTDIR)/bin
VERSION ?= $(strip $(shell ./scripts/version.sh))
VERSION_NUMBER := $(strip $(shell ./scripts/version.sh number))
GOOS ?= $(shell go env GOOS)
GOARCH ?= $(shell go env GOARCH)
GO_LDFLAGS ?=
GO_OPT_V := -X "main.version=$(VERSION)"
GO_OPT_APP := -X "main.appname=$(PROJECT_NAME)"
GO_OPT_BASE := -ldflags '$(GO_OPT_V) $(GO_OPT_APP) $(GO_LDFLAGS)'
GO_OPT ?=
EXPORT_RESULT ?= false # for CI please set EXPORT_RESULT to true
GOCMD := go
GOTEST := $(GOCMD) test
GOVET := $(GOCMD) vet
ECHO_CMD := echo -e
DIST_EXT := .tar.gz
DIST_OPTS := -czf
PKG_NAME := $(PROJECT_ID)_$(VERSION)_$(GOOS)-$(GOARCH)
DIST_FILE := $(PKG_NAME)$(DIST_EXT)
PKG_ARCH := $(GOARCH)
ifeq ($(PKG_ARCH),arm)
PKG_ARCH = armhf
endif
GREEN := $(shell tput -Txterm setaf 2)
YELLOW := $(shell tput -Txterm setaf 3)
WHITE := $(shell tput -Txterm setaf 7)
CYAN := $(shell tput -Txterm setaf 6)
RESET := $(shell tput -Txterm sgr0)
.DEFAULT_GOAL := all
version: ## Version of the project to be built
@echo $(VERSION)
.PHONY:version
version-number: ## Version number of the project to be built
@echo $(VERSION_NUMBER)
.PHONY:version-number
## Build
all: clean vendor build ## Build binary
.PHONY:all
clean: ## Remove build related files
@rm -fr $(TMPDIR)
@rm -fr $(OUTDIR)
@$(ECHO_CMD) "Clean\t\t${GREEN}[OK]${RESET}"
.PHONY:clean
vendor: ## Copy of all packages needed to support builds and tests in the vendor directory
$(GOCMD) mod vendor
@$(ECHO_CMD) "Vendor\t\t${GREEN}[OK]${RESET}"
.PHONY:vendor
APPS := $(patsubst cmd/%/, %, $(dir $(wildcard cmd/*/main.go)))
build: $(addprefix $(BINDIR)/, $(APPS)) ## Build your project and put the output binary in out/bin/
@mkdir -p $(BINDIR)
@$(ECHO_CMD) "Build\t\t${GREEN}[OK]${RESET}"
.PHONY:build
$(BINDIR)/%: cmd/%/main.go $(patsubst cmd/%/main.go,cmd/%/*.go,$<)
@rm -f "$(BINDIR)/$(BIN_PREFIX)$(patsubst cmd/%/main.go,%,$<)$(BIN_SUFFIX)"
$(GOCMD) build $(GO_OPT_BASE) $(GO_OPT) \
-o "$(BINDIR)/$(BIN_PREFIX)$(patsubst cmd/%/main.go,%,$<)$(BIN_SUFFIX)" \
$(patsubst %/main.go,./%,$<)
dist: ## Create binary distro package
@rm -f "$(OUTDIR)/$(DIST_FILE)"
tar $(DIST_OPTS) "$(OUTDIR)/$(DIST_FILE)" -C "$(OUTDIR)" bin
@$(ECHO_CMD) "Dist\t\t${GREEN}[OK]${RESET}"
.PHONY:dist
DEB_NAME := $(PROJECT_ID)_$(VERSION_NUMBER)-1_$(PKG_ARCH)
pkg-deb: ## Build debian package
@rm -rf $(TMPDIR)
@mkdir -p $(TMPDIR)/$(DEB_NAME)/DEBIAN
@mkdir -p $(TMPDIR)/$(DEB_NAME)/etc
@mkdir -p $(TMPDIR)/$(DEB_NAME)/usr/bin
@cp $(CURDIR)/configs/transocks.example.toml $(TMPDIR)/$(DEB_NAME)/etc/transocks.toml
@cp -a $(BINDIR)/* $(TMPDIR)/$(DEB_NAME)/usr/bin/
@sed -e "s/VERSION/$(VERSION_NUMBER)/g" \
$(CURDIR)/build/package/debian/changelog.tpl \
> $(TMPDIR)/changelog
@sed -e "s/ARCH/$(PKG_ARCH)/g" $(CURDIR)/build/package/debian/control.tpl \
> $(TMPDIR)/control
DEB_HOST_ARCH=$(PKG_ARCH) dpkg-gencontrol -v$(VERSION_NUMBER)-1 \
-c$(TMPDIR)/control \
-l$(TMPDIR)/changelog \
-f$(TMPDIR)/$(DEB_NAME)/DEBIAN/files -Ptmp/$(DEB_NAME)
dpkg-deb --build --root-owner-group $(TMPDIR)/$(DEB_NAME)
dpkg-genchanges --build=binary \
-c$(TMPDIR)/control \
-l$(TMPDIR)/changelog \
-f$(TMPDIR)/$(DEB_NAME)/DEBIAN/files \
-u$(TMPDIR) -O$(OUTDIR)/$(DEB_NAME).changes
@mv $(TMPDIR)/*.deb $(OUTDIR)/
@$(ECHO_CMD) "pkg-deb\t\t${GREEN}[OK]${RESET}"
.PHONY:pkg-deb
## Deploy
deploy-deb: ## Deploy debian packages
find -O1 $(OUT_DIR) -name '*.changes' -exec dput mousesoft \{\} \;
.PHONY:deploy-deb
## Test
test: ## Run the tests of the project
ifeq ($(EXPORT_RESULT), true)
@mkdir -p $(OUTDIR)
$(eval OUTPUT_OPTIONS = | go-junit-report -set-exit-code > $(OUTDIR)/junit-report.xml)
endif
$(GOTEST) -v $(GO_OPT) ./... $(OUTPUT_OPTIONS)
@$(ECHO_CMD) "Test\t\t${GREEN}[OK]${RESET}"
.PHONY:test
## Lint
lint: ## Run all available linters.
go vet ./...
errcheck ./...
staticcheck ./...
usestdlibvars ./...
shadow ./...
@$(ECHO_CMD) "Lint\t\t${GREEN}[OK]${RESET}"
.PHONY:lint
golangci-lint: ## Run golangci-lint linter
@golangci-lint run
@$(ECHO_CMD) "GolangCI Lint\t${GREEN}[OK]${RESET}"
.PHONY:golangci-lint
## Help
help: ## Show this help.
@$(ECHO_CMD) ''
@$(ECHO_CMD) 'Usage:'
@$(ECHO_CMD) ' ${YELLOW}make${RESET} ${GREEN}<target>${RESET}'
@$(ECHO_CMD) ''
@$(ECHO_CMD) 'Targets:'
@awk 'BEGIN {FS = ":.*?## "} { \
if (/^[a-zA-Z_-]+:.*?##.*$$/) {printf " ${YELLOW}%-20s${GREEN}%s${RESET}\n", $$1, $$2} \
else if (/^## .*$$/) {printf " ${CYAN}%s${RESET}\n", substr($$1,4)} \
}' $(MAKEFILE_LIST)
.PHONY:help

View File

@ -1,12 +1,14 @@
//go:build linux
// +build linux
package transocks
import (
syscall "golang.org/x/sys/unix"
"net"
"os"
"unsafe"
syscall "golang.org/x/sys/unix"
)
func getsockopt(s int, level int, optname int, optval unsafe.Pointer, optlen *uint32) (err error) {
@ -31,7 +33,7 @@ func GetOriginalDST(conn *net.TCPConn) (*net.TCPAddr, error) {
if err != nil {
return nil, err
}
defer f.Close()
defer func() { _ = f.Close() }()
fd := int(f.Fd())
// revert to non-blocking mode.
@ -43,17 +45,14 @@ func GetOriginalDST(conn *net.TCPConn) (*net.TCPAddr, error) {
v6 := conn.LocalAddr().(*net.TCPAddr).IP.To4() == nil
if v6 {
var addr syscall.RawSockaddrInet6
var len uint32
len = uint32(unsafe.Sizeof(addr))
len := uint32(unsafe.Sizeof(addr))
err = getsockopt(fd, syscall.IPPROTO_IPV6, IP6T_SO_ORIGINAL_DST,
unsafe.Pointer(&addr), &len)
if err != nil {
return nil, os.NewSyscallError("getsockopt", err)
}
ip := make([]byte, 16)
for i, b := range addr.Addr {
ip[i] = b
}
copy(ip, addr.Addr[:])
pb := *(*[2]byte)(unsafe.Pointer(&addr.Port))
return &net.TCPAddr{
IP: ip,
@ -63,17 +62,14 @@ func GetOriginalDST(conn *net.TCPConn) (*net.TCPAddr, error) {
// IPv4
var addr syscall.RawSockaddrInet4
var len uint32
len = uint32(unsafe.Sizeof(addr))
len := uint32(unsafe.Sizeof(addr))
err = getsockopt(fd, syscall.IPPROTO_IP, SO_ORIGINAL_DST,
unsafe.Pointer(&addr), &len)
if err != nil {
return nil, os.NewSyscallError("getsockopt", err)
}
ip := make([]byte, 4)
for i, b := range addr.Addr {
ip[i] = b
}
copy(ip, addr.Addr[:])
pb := *(*[2]byte)(unsafe.Pointer(&addr.Port))
return &net.TCPAddr{
IP: ip,

View File

@ -1,3 +1,4 @@
//go:build linux
// +build linux
package transocks
@ -14,13 +15,14 @@ func TestGetOriginalDST(t *testing.T) {
if err != nil {
t.Fatal(err)
}
defer l.Close()
defer func() { _ = l.Close() }()
c, err := l.Accept()
if err != nil {
t.Fatal(err)
}
defer c.Close()
defer func() { _ = c.Close() }()
origAddr, err := GetOriginalDST(c.(*net.TCPConn))
if err != nil {

20
scripts/changes.awk Normal file
View File

@ -0,0 +1,20 @@
# Get changes of given version number.
{
while (index($0, "## [" version "]") <= 0) {
if (getline <= 0) {
exit
}
}
if (getline <= 0 ) {
exit
}
if (getline <= 0 ) {
exit
}
while (index($0, "## [") <= 0) {
print $0
if (getline <= 0) {
exit
}
}
}

22
scripts/version.sh Executable file
View File

@ -0,0 +1,22 @@
#!/bin/bash
if [ -z ${TAG_NAME+x} ]; then
if [ -z ${BRANCH_NAME+x} ]; then
BRANCH_NAME=$(echo $(git branch --show-current) || \
echo $(git name-rev --name-only HEAD))
fi
GIT_VERSION=$(echo ${BRANCH_NAME} | grep -q 'release/' \
&& echo ${BRANCH_NAME} | sed -e 's|release/|v|' -e 's/$/-RC/' || \
echo $(git describe --always --tags --dirty 2>/dev/null) || echo v0)
else
GIT_VERSION=${TAG_NAME}
fi
if [ -z ${VERSION+x} ]; then
VERSION=$(echo ${GIT_VERSION} | sed -e 's|^origin/||')
fi
if [ -z $1 ]; then
echo "${VERSION}"
else
echo ${VERSION} | sed -e 's/^v//'
fi

View File

@ -85,7 +85,7 @@ func NewServer(c *Config) (*Server, error) {
func (s *Server) handleConnection(ctx context.Context, conn net.Conn) {
tc, ok := conn.(*net.TCPConn)
if !ok {
s.logger.Error("non-TCP connection", map[string]interface{}{
_ = s.logger.Error("non-TCP connection", map[string]interface{}{
"conn": conn,
})
return
@ -101,7 +101,7 @@ func (s *Server) handleConnection(ctx context.Context, conn net.Conn) {
origAddr, err := GetOriginalDST(tc)
if err != nil {
fields[log.FnError] = err.Error()
s.logger.Error("GetOriginalDST failed", fields)
_ = s.logger.Error("GetOriginalDST failed", fields)
return
}
addr = origAddr.String()
@ -109,14 +109,20 @@ func (s *Server) handleConnection(ctx context.Context, conn net.Conn) {
addr = tc.LocalAddr().String()
}
var reader io.Reader = tc
var (
reader io.Reader = tc
isTLS bool
reader_n io.Reader
)
// Check if TLS
isTLS, reader_n, err := peekSSL(tc)
if err != nil {
if isTLSloc, reader_nloc, err := peekSSL(tc); err != nil {
fields[log.FnError] = err.Error()
s.logger.Error("peekSSL failed", fields)
_ = s.logger.Error("peekSSL failed", fields)
return
} else {
isTLS = isTLSloc
reader_n = reader_nloc
}
reader = reader_n
fields["is_tls"] = isTLS
@ -126,7 +132,7 @@ func (s *Server) handleConnection(ctx context.Context, conn net.Conn) {
hello, reader_n2, err := peekClientHello(reader)
if err != nil {
fields[log.FnError] = err.Error()
s.logger.Warn("peekClientHello failed", fields)
_ = s.logger.Warn("peekClientHello failed", fields)
}
if err == nil && hello.ServerName != "" {
addr = hello.ServerName + addr[strings.Index(addr, ":"):]
@ -137,11 +143,12 @@ func (s *Server) handleConnection(ctx context.Context, conn net.Conn) {
host, reader_n3, err := peekHTTP(reader)
if err != nil {
fields[log.FnError] = err.Error()
s.logger.Warn("peekHTTP failed", fields)
} else {
if err == nil && host != "" {
addr = host + addr[strings.Index(addr, ":"):]
_ = s.logger.Warn("peekHTTP failed", fields)
} else if host != "" {
if strings.Contains(host, ":") {
host = host[:strings.Index(host, ":")]
}
addr = host + addr[strings.Index(addr, ":"):]
}
reader = reader_n3
}
@ -151,33 +158,33 @@ func (s *Server) handleConnection(ctx context.Context, conn net.Conn) {
destConn, err := s.dialer.Dial("tcp", addr)
if err != nil {
fields[log.FnError] = err.Error()
s.logger.Error("failed to connect to proxy server", fields)
_ = s.logger.Error("failed to connect to proxy server", fields)
return
}
defer destConn.Close()
defer func() { _ = destConn.Close() }()
s.logger.Info("proxy starts", fields)
_ = s.logger.Info("proxy starts", fields)
// do proxy
st := time.Now()
env := well.NewEnvironment(ctx)
env.Go(func(ctx context.Context) error {
buf := s.pool.Get().([]byte)
_, err := io.CopyBuffer(destConn, reader, buf)
s.pool.Put(buf)
_, err = io.CopyBuffer(destConn, reader, buf)
s.pool.Put(&buf)
if hc, ok := destConn.(netutil.HalfCloser); ok {
hc.CloseWrite()
_ = hc.CloseWrite()
}
tc.CloseRead()
_ = tc.CloseRead()
return err
})
env.Go(func(ctx context.Context) error {
buf := s.pool.Get().([]byte)
_, err := io.CopyBuffer(tc, destConn, buf)
s.pool.Put(buf)
tc.CloseWrite()
_, err = io.CopyBuffer(tc, destConn, buf)
s.pool.Put(&buf)
_ = tc.CloseWrite()
if hc, ok := destConn.(netutil.HalfCloser); ok {
hc.CloseRead()
_ = hc.CloseRead()
}
return err
})
@ -188,10 +195,10 @@ func (s *Server) handleConnection(ctx context.Context, conn net.Conn) {
fields["elapsed"] = time.Since(st).Seconds()
if err != nil {
fields[log.FnError] = err.Error()
s.logger.Error("proxy ends with an error", fields)
_ = s.logger.Error("proxy ends with an error", fields)
return
}
s.logger.Info("proxy ends", fields)
_ = s.logger.Info("proxy ends", fields)
}
// Peek ClientHello message from conn and returns SNI.