├── 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 | --------------------------------------------------------------------------------