├── Makefile
├── README.md
├── bin
└── redi301
├── config
└── config.go
├── go.mod
├── go.sum
├── http
└── http.go
├── lagran
└── lagran.go
├── main.go
├── redi301.conf
└── redirect
└── redirect.go
/Makefile:
--------------------------------------------------------------------------------
1 | # BINARY FILE
2 | PROJECT="redi301"
3 | # START FILE PATH
4 | MAIN_PATH="main.go"
5 | build:
6 | @go build -ldflags "-linkmode external -extldflags '-static'" -trimpath -o bin/${PROJECT} ${MAIN_PATH}
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ### How to use
2 | - ```mkdir /root/redi301 && cd /root/redi301 && wget https://raw.githubusercontent.com/haha357/redi301/master/bin/redi301 && chmod +x ./redi301```
3 | - ```./redi301```
4 |
5 | ### Instructions
6 | This application is aimed at redirecting urls which have been blocked by GFW to these which have not been blocked, this is a real 301 redirect
7 | application, because it responds 301 status code in the response headers.
8 |
9 | Use```./redi301 -h``` to view more instructions.
10 |
11 | ### Params
12 | - -a Listen address,just like ```ip:port```, exp : ```0.0.0.0:80```, the default value is ```0.0.0.0:80```.
13 | - -t Prefix of the target redirect url, just like:```http://www.whitehouse.gov```,both http and https supported, please do not end with ```/```.
14 |
15 | ### TODO
16 | - [x] Http redirect to Http. (exp: http://blocked.domain -> http://unblocked.domain )
17 | - [x] Http redirect to Https. (exp: http://blocked.domain -> https://unblocked.domain )
18 | - [ ] Https redirect to Http. (exp: https://blocked.domain -> http://unblocked.domain )
19 | - [ ] Https redirect to Https. (exp: https://blocked.domain -> https://unblocked.domain )
20 |
21 | ### Donation
22 |
23 | - If you like this application, you can donate to the author. Thank you so much.
24 | - USDT(TRC20) wallet: TB8meT4Pm9KFXRJ8SNCfxx4yBGPbk3Ekip
25 |
26 |

--------------------------------------------------------------------------------
/bin/redi301:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haha357/redi301/e7934b62a4761d47d4af3bac32bf142e763440f2/bin/redi301
--------------------------------------------------------------------------------
/config/config.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import (
4 | "flag"
5 | "fmt"
6 | "github.com/gookit/color"
7 | "github.com/sirupsen/logrus"
8 | "net/url"
9 | "os"
10 | "strings"
11 | )
12 |
13 | var (
14 | HttpAddr string
15 | Target string
16 | HttpPort string
17 | )
18 |
19 | const (
20 | LogLevel = logrus.FatalLevel
21 | Header = `=========================================================
22 | Welcome to use this application.
23 | If you like this application, you can donate to the author.
24 | USDT(Trc20) wallet: TB8meT4Pm9KFXRJ8SNCfxx4yBGPbk3Ekip
25 | Thank you so much.
26 | =========================================================`
27 | )
28 |
29 | func Init() {
30 | flag.Usage = func() {
31 | color.Redln(Header)
32 | fmt.Printf("Usage of %s:\n", os.Args[0])
33 | flag.PrintDefaults()
34 | }
35 | flag.StringVar(&HttpAddr, "a", "0.0.0.0:80", "The listen address and port.")
36 | flag.StringVar(&Target, "t", "https://www.microsoft.com", "The prefix of target redirect url.")
37 | flag.Parse()
38 | ipAndPort := strings.Split(HttpAddr, ":")
39 | if len(ipAndPort) != 2 {
40 | logrus.Fatalf("http listen address error...")
41 | } else {
42 | HttpPort = ipAndPort[1]
43 | }
44 | if _, err := url.Parse(Target); err != nil {
45 | logrus.Fatalf("prefix of target redirect url error...")
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module redi301
2 |
3 | go 1.19
4 |
5 | require (
6 | github.com/coreos/go-iptables v0.6.0
7 | github.com/dlclark/regexp2 v1.7.0
8 | github.com/florianl/go-nfqueue v1.3.1
9 | github.com/google/gopacket v1.1.19
10 | github.com/gookit/color v1.5.2
11 | github.com/panjf2000/ants/v2 v2.7.1
12 | github.com/sirupsen/logrus v1.9.0
13 | golang.org/x/sys v0.4.0
14 | )
15 |
16 | require (
17 | github.com/google/go-cmp v0.5.7 // indirect
18 | github.com/josharian/native v1.0.0 // indirect
19 | github.com/mdlayher/netlink v1.6.0 // indirect
20 | github.com/mdlayher/socket v0.1.1 // indirect
21 | github.com/pkg/errors v0.9.1 // indirect
22 | github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
23 | golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
24 | golang.org/x/sync v0.1.0 // indirect
25 | )
26 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/coreos/go-iptables v0.6.0 h1:is9qnZMPYjLd8LYqmm/qlE+wwEgJIkTYdhV3rfZo4jk=
2 | github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q=
3 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
4 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
5 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
6 | github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo=
7 | github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
8 | github.com/florianl/go-nfqueue v1.3.1 h1:khQ9fYCrjbu5CF8dZF55G2RTIEIQRI0Aj5k3msJR6Gw=
9 | github.com/florianl/go-nfqueue v1.3.1/go.mod h1:aHWbgkhryJxF5XxYvJ3oRZpdD4JP74Zu/hP1zuhja+M=
10 | github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
11 | github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
12 | github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
13 | github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
14 | github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
15 | github.com/gookit/color v1.5.2 h1:uLnfXcaFjlrDnQDT+NCBcfhrXqYTx/rcCa6xn01Y8yI=
16 | github.com/gookit/color v1.5.2/go.mod h1:w8h4bGiHeeBpvQVePTutdbERIUf3oJE5lZ8HM0UgXyg=
17 | github.com/josharian/native v1.0.0 h1:Ts/E8zCSEsG17dUqv7joXJFybuMLjQfWE04tsBODTxk=
18 | github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
19 | github.com/mdlayher/netlink v1.6.0 h1:rOHX5yl7qnlpiVkFWoqccueppMtXzeziFjWAjLg6sz0=
20 | github.com/mdlayher/netlink v1.6.0/go.mod h1:0o3PlBmGst1xve7wQ7j/hwpNaFaH4qCRyWCdcZk8/vA=
21 | github.com/mdlayher/socket v0.1.1 h1:q3uOGirUPfAV2MUoaC7BavjQ154J7+JOkTWyiV+intI=
22 | github.com/mdlayher/socket v0.1.1/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5Awbj+qDs=
23 | github.com/panjf2000/ants/v2 v2.7.1 h1:qBy5lfSdbxvrR0yUnZfaEDjf0FlCw4ufsbcsxmE7r+M=
24 | github.com/panjf2000/ants/v2 v2.7.1/go.mod h1:KIBmYG9QQX5U2qzFP/yQJaq/nSb6rahS9iEHkrCMgM8=
25 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
26 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
27 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
28 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
29 | github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
30 | github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
31 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
32 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
33 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
34 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
35 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
36 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
37 | github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
38 | github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
39 | github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=
40 | github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
41 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
42 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
43 | golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
44 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
45 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
46 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
47 | golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
48 | golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=
49 | golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
50 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
51 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
52 | golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
53 | golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
54 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
55 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
56 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
57 | golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
58 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
59 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
60 | golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
61 | golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
62 | golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
63 | golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
64 | golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
65 | golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
66 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
67 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
68 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
69 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
70 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
71 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
72 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
73 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
74 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
75 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
76 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
77 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
78 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
79 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
80 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
81 |
--------------------------------------------------------------------------------
/http/http.go:
--------------------------------------------------------------------------------
1 | package http
2 |
3 | import (
4 | "context"
5 | "github.com/sirupsen/logrus"
6 | "golang.org/x/sys/unix"
7 | "net"
8 | "redi301/config"
9 | "redi301/redirect"
10 | "syscall"
11 | )
12 |
13 | func Start() {
14 | cfg := net.ListenConfig{
15 | Control: func(network, address string, c syscall.RawConn) error {
16 | return c.Control(func(fd uintptr) {
17 | //syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, unix.SO_REUSEADDR, 1)
18 | //syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, unix.SO_REUSEPORT, 1)
19 | syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, unix.SO_RCVBUF, 1)
20 | linger := syscall.Linger{
21 | Onoff: 1,
22 | Linger: 0,
23 | }
24 | syscall.SetsockoptLinger(int(fd), syscall.SOL_SOCKET, unix.SO_LINGER, &linger)
25 | syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_NODELAY, 1)
26 | })
27 | },
28 | }
29 | listener, err := cfg.Listen(context.Background(), "tcp", config.HttpAddr)
30 | //listener, err := net.Listen("tcp", ":"+config.HttpPort)
31 | if err != nil {
32 | logrus.Fatalf("[http] listen fail, err: %v\n", err)
33 | }
34 | for {
35 | // 等待连接
36 | conn, err := listener.Accept()
37 | if err != nil {
38 | logrus.Debugf("[http] accept fail, err: %v\n", err)
39 | continue
40 | }
41 | // 对每个新连接创建一个协程进行收发数据
42 | go redirect.Process(conn)
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/lagran/lagran.go:
--------------------------------------------------------------------------------
1 | package lagran
2 |
3 | import (
4 | "context"
5 | "github.com/coreos/go-iptables/iptables"
6 | "github.com/florianl/go-nfqueue"
7 | "github.com/google/gopacket"
8 | "github.com/google/gopacket/layers"
9 | "github.com/panjf2000/ants/v2"
10 | "github.com/sirupsen/logrus"
11 | "redi301/config"
12 | "regexp"
13 | "strings"
14 | "sync"
15 | "time"
16 | )
17 |
18 | const (
19 | EnableSynAck = true
20 | EnableAck = true
21 | EnablePshAck = true
22 | EnableFinAck = true
23 | WindowSizeOfSynAck = 5
24 | WindowSizeOfAck = 5
25 | WindowSizeOfPshAck = 5
26 | WindowSizeOfFinAck = 5
27 | )
28 |
29 | func Run() {
30 | setIptable(config.HttpPort)
31 | var wg sync.WaitGroup
32 | if EnableSynAck {
33 | p1, _ := ants.NewPoolWithFunc(128, func(i interface{}) {
34 | packetHandle(i.(int))
35 | wg.Done()
36 | })
37 | defer p1.Release()
38 | logrus.Debug("[lagran service] Starting Task p1")
39 | for i := 1000; i < 1128; i++ {
40 | wg.Add(1)
41 | _ = p1.Invoke(int(i))
42 | }
43 | }
44 | if EnableAck {
45 | p2, _ := ants.NewPoolWithFunc(128, func(i interface{}) {
46 | packetHandle(i.(int))
47 | wg.Done()
48 | })
49 | defer p2.Release()
50 | logrus.Debug("[lagran service] Starting Task p2")
51 | for i := 2000; i < 2128; i++ {
52 | wg.Add(1)
53 | _ = p2.Invoke(int(i))
54 | }
55 | }
56 | if EnablePshAck {
57 | p3, _ := ants.NewPoolWithFunc(128, func(i interface{}) {
58 | packetHandle(i.(int))
59 | wg.Done()
60 | })
61 | defer p3.Release()
62 | logrus.Debug("[lagran service] Starting Task p3")
63 | for i := 3000; i < 3128; i++ {
64 | wg.Add(1)
65 | _ = p3.Invoke(int(i))
66 | }
67 | }
68 | if EnableFinAck {
69 | p4, _ := ants.NewPoolWithFunc(128, func(i interface{}) {
70 | packetHandle(i.(int))
71 | wg.Done()
72 | })
73 | defer p4.Release()
74 | logrus.Debug("[lagran service] Starting Task p4")
75 | for i := 4000; i < 4128; i++ {
76 | wg.Add(1)
77 | _ = p4.Invoke(int(i))
78 | }
79 | }
80 | }
81 |
82 | func setIptable(sport string) {
83 | ipt, err := iptables.New()
84 | if err != nil {
85 | logrus.Fatalf("[lagran service] Iptabels new error:%v\n", err)
86 | }
87 |
88 | logrus.Debug("Starting to set iptables OUTPUT chain.")
89 | //if err := ipt.ClearChain("filter", "OUTPUT"); err != nil {
90 | // color.Redln("[lagran service] Failed to clear iptables OUTPUT chain.")
91 | //}
92 | if EnableSynAck {
93 | _ = ipt.AppendUnique("filter", "OUTPUT", "-p", "tcp", "-m", "multiport", "--sport", sport, "--tcp-flags", "SYN,RST,ACK,FIN,PSH", "SYN,ACK", "-j", "NFQUEUE", "--queue-balance", "1000:1127")
94 | }
95 | if EnableAck {
96 | _ = ipt.AppendUnique("filter", "OUTPUT", "-p", "tcp", "-m", "multiport", "--sport", sport, "--tcp-flags", "SYN,RST,ACK,FIN,PSH", "ACK", "-j", "NFQUEUE", "--queue-balance", "2000:2127")
97 | }
98 | if EnablePshAck {
99 | _ = ipt.AppendUnique("filter", "OUTPUT", "-p", "tcp", "-m", "multiport", "--sport", sport, "--tcp-flags", "SYN,RST,ACK,FIN,PSH", "PSH,ACK", "-j", "NFQUEUE", "--queue-balance", "3000:3127")
100 | }
101 | if EnableFinAck {
102 | _ = ipt.AppendUnique("filter", "OUTPUT", "-p", "tcp", "-m", "multiport", "--sport", sport, "--tcp-flags", "SYN,RST,ACK,FIN,PSH", "FIN,ACK", "-j", "NFQUEUE", "--queue-balance", "4000:4127")
103 | }
104 | }
105 | func UnsetIptable(sport string) {
106 | ipt, err := iptables.New()
107 | if err != nil {
108 | logrus.Fatalf("[lagran service] Iptabels new error:%v", err)
109 | }
110 | if EnableSynAck {
111 | _ = ipt.Delete("filter", "OUTPUT", "-p", "tcp", "-m", "multiport", "--sport", sport, "--tcp-flags", "SYN,RST,ACK,FIN,PSH", "SYN,ACK", "-j", "NFQUEUE", "--queue-balance", "1000:1127")
112 | }
113 | if EnableAck {
114 | _ = ipt.Delete("filter", "OUTPUT", "-p", "tcp", "-m", "multiport", "--sport", sport, "--tcp-flags", "SYN,RST,ACK,FIN,PSH", "ACK", "-j", "NFQUEUE", "--queue-balance", "2000:2127")
115 | }
116 | if EnablePshAck {
117 | _ = ipt.Delete("filter", "OUTPUT", "-p", "tcp", "-m", "multiport", "--sport", sport, "--tcp-flags", "SYN,RST,ACK,FIN,PSH", "PSH,ACK", "-j", "NFQUEUE", "--queue-balance", "3000:3127")
118 | }
119 | if EnableFinAck {
120 | _ = ipt.Delete("filter", "OUTPUT", "-p", "tcp", "-m", "multiport", "--sport", sport, "--tcp-flags", "SYN,RST,ACK,FIN,PSH", "FIN,ACK", "-j", "NFQUEUE", "--queue-balance", "4000:4127")
121 | }
122 | }
123 | func packetHandle(queueNum int) {
124 | nfqconfig := nfqueue.Config{
125 | NfQueue: uint16(queueNum),
126 | MaxPacketLen: 0xFFFF,
127 | MaxQueueLen: 0xFF,
128 | Copymode: nfqueue.NfQnlCopyPacket,
129 | WriteTimeout: 15 * time.Millisecond,
130 | }
131 |
132 | nf, err := nfqueue.Open(&nfqconfig)
133 | if err != nil {
134 | logrus.Fatalf("[lagran] could not open nfqueue socket:", err)
135 | }
136 |
137 | defer nf.Close()
138 |
139 | ctx, cancelFunc := context.WithCancel(context.Background())
140 | defer cancelFunc()
141 |
142 | fn := func(a nfqueue.Attribute) int {
143 | id := *a.PacketID
144 | packet := gopacket.NewPacket(*a.Payload, layers.LayerTypeIPv4, gopacket.Default)
145 |
146 | if tcpLayer := packet.Layer(layers.LayerTypeTCP); tcpLayer != nil {
147 | tcp, _ := tcpLayer.(*layers.TCP)
148 | ports := strings.Split(config.HttpPort, ",")
149 | reg := regexp.MustCompile(`\d+`)
150 | sport := reg.FindString(tcp.SrcPort.String())
151 | var matchedPort = false
152 | for _, port := range ports {
153 | if port == sport {
154 | matchedPort = true
155 | break
156 | }
157 | }
158 | if matchedPort {
159 | var ok1 = EnableSynAck && tcp.SYN && tcp.ACK
160 | var ok2 = EnableAck && tcp.ACK && !tcp.PSH && !tcp.FIN && !tcp.SYN && !tcp.RST
161 | var ok3 = EnablePshAck && tcp.PSH && tcp.ACK
162 | var ok4 = EnableFinAck && tcp.FIN && tcp.ACK
163 | var windowSize uint16
164 | if ok1 || ok2 || ok3 || ok4 {
165 | if ok1 {
166 | windowSize = WindowSizeOfSynAck
167 | logrus.Debug("[lagran] Handle SYN=1 and ACK=1")
168 | }
169 | if ok2 {
170 | windowSize = WindowSizeOfAck
171 | logrus.Debug("[lagran] Handle ACK=1")
172 | }
173 | if ok3 {
174 | windowSize = WindowSizeOfPshAck
175 | logrus.Debug("[lagran] Handle PSH=1 and ACK=1")
176 | }
177 | if ok4 {
178 | windowSize = WindowSizeOfFinAck
179 | logrus.Debug("[lagran] Handle FIN=1 and ACK=1")
180 | }
181 | packet.TransportLayer().(*layers.TCP).Window = windowSize
182 | err := packet.TransportLayer().(*layers.TCP).SetNetworkLayerForChecksum(packet.NetworkLayer())
183 | if err != nil {
184 | logrus.Errorf("[lagran] SetNetworkLayerForChecksum error: %v\n", err)
185 | }
186 | buffer := gopacket.NewSerializeBuffer()
187 | options := gopacket.SerializeOptions{
188 | ComputeChecksums: true,
189 | FixLengths: true,
190 | }
191 | if err := gopacket.SerializePacket(buffer, options, packet); err != nil {
192 | logrus.Errorf("[lagran] SerializePacket error: %v\n", err)
193 | }
194 | packetBytes := buffer.Bytes()
195 | logrus.Debugf("[lagran] Set TCP window size to %d\n", windowSize)
196 | err = nf.SetVerdictModPacket(id, nfqueue.NfAccept, packetBytes)
197 | if err != nil {
198 | logrus.Errorf("[lagran] SetVerdictModified error: %v\n", err)
199 | }
200 | return 0
201 | }
202 | err := nf.SetVerdict(id, nfqueue.NfAccept)
203 | if err != nil {
204 | logrus.Errorf("[lagran] SetVerdictModified error: %v\n", err)
205 | }
206 | return 0
207 | }
208 | err := nf.SetVerdict(id, nfqueue.NfAccept)
209 | if err != nil {
210 | logrus.Errorf("[lagran] SetVerdictModified error: %v\n", err)
211 | }
212 | return 0
213 | }
214 | err := nf.SetVerdict(id, nfqueue.NfAccept)
215 | if err != nil {
216 | logrus.Errorf("[lagran] SetVerdictModified error: %v\n", err)
217 | }
218 | return 0
219 | }
220 |
221 | // Register your function to listen on nflqueue queue 100
222 | err = nf.RegisterWithErrorFunc(ctx, fn, func(e error) int {
223 | if e != nil {
224 | logrus.Errorf("[lagran] RegisterWithErrorFunc Error:%v\n", e)
225 | }
226 | return 0
227 | })
228 | if err != nil {
229 | logrus.Fatalf("[lagran] error: %v\n", err)
230 | }
231 | <-ctx.Done()
232 | }
233 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/gookit/color"
5 | "github.com/sirupsen/logrus"
6 | "os"
7 | "os/signal"
8 | "redi301/config"
9 | "redi301/http"
10 | "redi301/lagran"
11 | "time"
12 | )
13 |
14 | func init() {
15 | logrus.SetLevel(config.LogLevel)
16 | logrus.SetFormatter(&logrus.TextFormatter{})
17 | config.Init()
18 | }
19 |
20 | func main() {
21 | color.Redln(config.Header)
22 | go lagran.Run()
23 | go http.Start()
24 | color.Greenf("[%v] App is running...\n", time.Now().Format("2006-06-02 15:04:05"))
25 | color.Greenf("[%v] You can use command '%v -h' to view more instructions... \n", time.Now().Format("2006-06-02 15:04:05"), os.Args[0])
26 | sigs := make(chan os.Signal, 1)
27 | done := make(chan bool, 1)
28 | signal.Notify(sigs, os.Interrupt)
29 | go func() {
30 | <-sigs
31 | lagran.UnsetIptable(config.HttpPort)
32 | logrus.Debug("Unset iptables...")
33 | done <- true
34 | }()
35 | <-done
36 | color.Redf("[%v] App terminated...\n", time.Now().Format("2006-06-02 15:04:05"))
37 | }
38 |
--------------------------------------------------------------------------------
/redi301.conf:
--------------------------------------------------------------------------------
1 | # supervisor configuration file
2 | [program:redi301]
3 | process_name=redi301
4 | directory=/root/redi301
5 | command=/root/redi301/redi301 -a :80
6 | autostart=true
7 | autorestart=true
8 | user=root
9 | numprocs=1
10 | redirect_stderr=true
11 | stdout_logfile=/var/log/supervisor/redi301.log
--------------------------------------------------------------------------------
/redirect/redirect.go:
--------------------------------------------------------------------------------
1 | package redirect
2 |
3 | import (
4 | "fmt"
5 | "github.com/dlclark/regexp2"
6 | "github.com/sirupsen/logrus"
7 | "net"
8 | "redi301/config"
9 | "strings"
10 | )
11 |
12 | func Process(conn net.Conn) {
13 | var RequestHead string
14 | var Path string
15 | defer conn.Close()
16 | for {
17 | var buf [128]byte
18 | //接受数据
19 | n, err := conn.Read(buf[:])
20 | if err != nil {
21 | logrus.Errorf("[redirect] read from connect failed, err: %v\n", err)
22 | break
23 | }
24 | logrus.Debugf("Receive data: \n%s\n", string(buf[:n]))
25 | RequestHead += string(buf[:n])
26 | logrus.Debug(RequestHead)
27 | if strings.Contains(RequestHead, "HTTP") {
28 | re := regexp2.MustCompile(`(GET|HEAD?) (.*?) HTTP`, 0)
29 | if matchArr, err := re.FindStringMatch(RequestHead); err != nil {
30 | Path = "/"
31 | } else {
32 | if matchArr != nil {
33 | if len(matchArr.Groups()) > 2 {
34 | Path = matchArr.Groups()[2].String()
35 | } else {
36 | Path = "/"
37 | }
38 | } else {
39 | Path = "/"
40 | }
41 |
42 | }
43 |
44 | if _, err = conn.Write([]byte("HTTP/1.1 301\r\n" +
45 | "Content-Type: text/html\r\n" +
46 | "Cache-Control: max-age=86400\r\n" +
47 | "Content-Length: " + "0" + "\r\n" +
48 | "Connection: close\r\n" +
49 | fmt.Sprintf("Location: %v%v\r\n\r\n", config.Target, Path))); err != nil {
50 | logrus.Errorf("write to client failed, err: %v\n", err)
51 | break
52 | }
53 | logrus.Debug("[redirect] Response sent...")
54 | //break
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------