diff --git a/cmd/spoof-dpi/main.go b/cmd/spoof-dpi/main.go index 22329f2..1c92e9f 100644 --- a/cmd/spoof-dpi/main.go +++ b/cmd/spoof-dpi/main.go @@ -1,12 +1,22 @@ package main import ( - "fmt" + "flag" + "os" - "github.com/itworksnow/SpoofDPI/hello" + "github.com/xvzc/SpoofDPI/proxy" ) func main() { - fmt.Print("hello") - hello.SayHello() + src := flag.String("src", "localhost:8080", "source-ip:source-port") + dns := flag.String("dns", "8.8.8.8", "DNS server") + debug := flag.Bool("debug", false, "true | false") + mtu := flag.Int("mtu", 100, "int") + + err := proxy.InitConfig(*src, *dns, *mtu, *debug) + if err != nil { + os.Exit(1) + } + + proxy.Start() } diff --git a/cmd/spoof-dpi/spoof-dpi b/cmd/spoof-dpi/spoof-dpi new file mode 100755 index 0000000..a5264bd Binary files /dev/null and b/cmd/spoof-dpi/spoof-dpi differ diff --git a/go.mod b/go.mod index a4497b5..71ac69d 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,5 @@ -module SpoofDPI +module github.com/xvzc/SpoofDPI go 1.17 + +require github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..94a486b --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 h1:4NNbNM2Iq/k57qEu7WfL67UrbPq1uFWxW4qODCohi+0= +github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6/go.mod h1:J29hk+f9lJrblVIfiJOtTFk+OblBawmib4uz/VdKzlg= diff --git a/hello/hello.go b/hello/hello.go deleted file mode 100644 index dce853e..0000000 --- a/hello/hello.go +++ /dev/null @@ -1,9 +0,0 @@ -package hello - -import ( - "fmt" -) - -func SayHello() { - fmt.Print("from module hello: Hello") -} diff --git a/proxy/config.go b/proxy/config.go new file mode 100644 index 0000000..2eeed57 --- /dev/null +++ b/proxy/config.go @@ -0,0 +1,69 @@ +package proxy + +import ( + "errors" + "log" + "strings" + "fmt" + "sync" +) + +type Config struct { + SrcIp string + SrcPort string + DNS string + MTU int + Debug bool +} + +var config *Config +var once sync.Once +var err error + +func tokenizeAddress(srcAddress string) (string, string, error) { + tokens := strings.Split(srcAddress, ":") + if len(tokens) < 2 { + return "", "", errors.New("Error while parsing source address: invalid format.") + } + + ip := tokens[0] + port := tokens[1] + + return ip, port, nil +} + +func InitConfig(srcAddress string, dns string, mtu int, debug bool) error { + err = nil + + once.Do(func() { + ip, port, err := tokenizeAddress(srcAddress) + if err != nil { + log.Fatal(err) + return + } + + config = &Config{ + SrcIp : ip, + SrcPort : port, + DNS : dns, + MTU : mtu, + Debug : debug, + } + }) + + log.Println("source ip : " + config.SrcIp) + log.Println("source port : " + config.SrcPort) + log.Println("dns : " + config.DNS) + log.Println("mtu : " + fmt.Sprint(config.MTU)) + if config.Debug { + log.Println("debug : true") + } else { + log.Println("debug : false") + } + + return err +} + +func getConfig() (*Config) { + return config +} diff --git a/proxy/http.go b/proxy/http.go new file mode 100644 index 0000000..6c876dd --- /dev/null +++ b/proxy/http.go @@ -0,0 +1,45 @@ +package proxy + +import ( + "fmt" + "log" + "net" + + "github.com/xvzc/SpoofDPI/util" +) + +func HandleHttp(clientConn net.Conn, ip string, message []byte) { + remoteConn, err := net.Dial("tcp", ip+":80") // create connection to server + if err != nil { + log.Fatal(err) + return + } + defer remoteConn.Close() + + _, write_err := remoteConn.Write(message) + if write_err != nil { + log.Fatal("failed:", write_err) + return + } + defer remoteConn.(*net.TCPConn).CloseWrite() + + buf, err := util.ReadMessage(remoteConn) + if err != nil { + log.Fatal("failed:", err) + return + } + + fmt.Println() + log.Println() + fmt.Println("##### Response from the server: ") + fmt.Println(string(buf)) + + // Write to client + _, write_err = clientConn.Write(buf) + if write_err != nil { + log.Fatal("failed:", write_err) + return + } + defer clientConn.(*net.TCPConn).CloseWrite() +} + diff --git a/proxy/proxy.go b/proxy/proxy.go new file mode 100644 index 0000000..b7793d7 --- /dev/null +++ b/proxy/proxy.go @@ -0,0 +1,58 @@ +package proxy + +import ( + "log" + "fmt" + "net" + "os" + "github.com/xvzc/SpoofDPI/util" +) + +func Start() { + listener, err := net.Listen("tcp", ":" + config.SrcPort) + if err != nil { + log.Fatal("Error creating listener: ", err) + os.Exit(1) + } + + log.Println("Created a listener") + + for { + clientConn, err := listener.Accept() + if err != nil { + log.Fatal("Error accepting connection: ", err) + continue + } + + log.Println("Accepted a new connection.", clientConn.RemoteAddr()) + + go func() { + defer clientConn.Close() + + message , err := util.ReadMessage(clientConn) + if err != nil { + return + } + + fmt.Println() + log.Println() + fmt.Println("##### Request from client : ") + fmt.Println(string(message)) + + domain := util.ExtractDomain(&message) + + ip, err := util.DnsLookupOverHttps(getConfig().DNS, domain) // Dns lookup over https + if err != nil { + return + } + + log.Println("ip: "+ ip) + + if util.ExtractMethod(&message) == "CONNECT" { + fmt.Println("got a HTTPS Request") + }else { + HandleHttp(clientConn, ip, message) + } + }() + } +} diff --git a/spoof-dpi b/spoof-dpi new file mode 100755 index 0000000..4792e63 Binary files /dev/null and b/spoof-dpi differ diff --git a/util/util.go b/util/util.go new file mode 100644 index 0000000..cdb8ae5 --- /dev/null +++ b/util/util.go @@ -0,0 +1,92 @@ +package util + +import ( + "net" + "log" + "io" + "strings" + "github.com/babolivier/go-doh-client" +) + + +func ReadMessage(conn net.Conn)([]byte, error) { + buf := make([]byte, 0, 4096) // big buffer + tmp := make([]byte, 1024) // using small tmo buffer for demonstrating + for { + n, err := conn.Read(tmp) + if err != nil { + if err != io.EOF { + log.Fatal("ReadRequest error:", err) + } + return nil, err + } + buf = append(buf, tmp[:n]...) + + if n < 1024 { + break + } + } + + return buf, nil +} + +func ExtractDomain(message *[]byte) (string) { + i := 0 + for ; i < len(*message); i++ { + if (*message)[i] == '\n' { + i++ + break; + } + } + + for ; i < len(*message); i++ { + if (*message)[i] == ' ' { + i++ + break; + } + } + + j := i + for ; j < len(*message); j++ { + if (*message)[j] == '\n' { + break; + } + } + + domain := strings.Split(string((*message)[i:j]), ":")[0] + + return strings.TrimSpace(domain) +} + +func DnsLookupOverHttps(dns string, domain string)(string, error) { + // Perform a A lookup on example.com + resolver := doh.Resolver{ + Host: dns, // Change this with your favourite DoH-compliant resolver. + Class: doh.IN, + } + + log.Println(domain) + a, _, err := resolver.LookupA(domain) + if err != nil { + log.Fatal("Error looking up dns. ", err) + return "", err + } + + ip := a[0].IP4 + + return ip, nil +} + +func ExtractMethod(message *[]byte) (string) { + i := 0 + for ; i < len(*message); i++ { + if (*message)[i] == ' ' { + break; + } + } + + method := strings.TrimSpace(string((*message)[:i])) + log.Println(method) + + return strings.ToUpper(method) +}