diff --git a/cmd/gui/main.go b/cmd/gui/main.go index 9fd6e42..5dba5c7 100644 --- a/cmd/gui/main.go +++ b/cmd/gui/main.go @@ -3,7 +3,7 @@ package main import ( "encoding/json" "fmt" - "io/ioutil" + "io" "log" "net/http" "time" @@ -20,7 +20,7 @@ func main() { defer ui.Close() termWidth, termHeight := ui.TerminalDimensions() title := widgets.NewParagraph() - title.Text = "Welcome to Miniatureby DevGenie, press q to quit" + title.Text = "Welcome to Miniature by DevGenie, press q to quit. Total runtime: n/a" title.TextStyle.Modifier = ui.ModifierBold title.WrapText = true title.TextStyle.Fg = ui.ColorGreen @@ -30,48 +30,46 @@ func main() { title.PaddingRight = 1 title.PaddingLeft = 1 + info := widgets.NewList() + info.BorderStyle.Fg = ui.ColorCyan + info.Title = "Info" + info.TitleStyle.Fg = ui.ColorGreen - systemStats := widgets.NewList() - systemStats.BorderStyle.Fg = ui.ColorCyan - systemStats.Title = "System" - systemStats.TitleStyle.Fg = ui.ColorGreen + networkDataIn := widgets.NewSparkline() + networkDataIn.Title = "Bytes in" + networkDataIn.Data = make([]float64, 0) + networkDataIn.LineColor = ui.ColorGreen + networkDataIn.TitleStyle.Modifier = ui.ModifierBold + networkDataIn.TitleStyle.Fg = ui.ColorGreen - peerStats := widgets.NewList() - peerStats.BorderStyle.Fg = ui.ColorCyan - peerStats.Title = "Peers" - peerStats.TitleStyle.Fg = ui.ColorGreen + networkDataOut := widgets.NewSparkline() + networkDataOut.Title = "Bytes out" + networkDataOut.Data = make([]float64, 0) + networkDataOut.LineColor = ui.ColorCyan + networkDataOut.TitleStyle.Modifier = ui.ModifierBold + networkDataOut.TitleStyle.Fg = ui.ColorCyan - networkStats := widgets.NewList() - networkStats.BorderStyle.Fg = ui.ColorCyan - networkStats.Title = "Network" - networkStats.TitleStyle.Fg = ui.ColorGreen - - networkData := widgets.NewSparkline() - networkData.Title = "Peers connected: 0" - networkData.LineColor = ui.ColorCyan - networkData.Data = make([]float64, 1) - networkData.TitleStyle.Modifier = ui.ModifierBold - networkData.TitleStyle.Fg = ui.ColorGreen - - sparklineGroup := widgets.NewSparklineGroup(networkData) + sparklineGroup := widgets.NewSparklineGroup(networkDataIn, networkDataOut) + sparklineGroup.Title = "Network stats" grid := ui.NewGrid() grid.SetRect(0, 0, termWidth, termHeight) grid.Set( - ui.NewRow(0.4/6,title), + ui.NewRow(0.4/6, title), ui.NewRow(5.6/6, ui.NewCol(1.0/4, - ui.NewRow(2.0/6,systemStats), - ui.NewRow(2.0/6,peerStats), - ui.NewRow(2.0/6,networkStats), + ui.NewRow(2.0/6, info), ), ui.NewCol(3.0/4, sparklineGroup), ), ) ui.Render(grid) - tickerCount := 1 + lastConnIn := new(int) + lastConnOut := new(int) + *lastConnIn = 0 + *lastConnOut = 0 uiEvents := ui.PollEvents() ticker := time.NewTicker(time.Second).C for { @@ -89,21 +87,18 @@ func main() { } case <-ticker: usageStats := callStats() - generalStatsRows := []string{fmt.Sprintf("Available: %d", usageStats.AvailableSlots), - fmt.Sprintf("Total: %d", usageStats.AvailableSlots), - fmt.Sprintf("Connected: %d", usageStats.Peers), - fmt.Sprintf("Bytes in: %d", usageStats.ConnectionsIn), - fmt.Sprintf("Bytes out: %d", usageStats.ConnectionsOut), - } - - systemStatsRows := []string{fmt.Sprintf("Running time: %s", usageStats.TimeElapsed), + title.Text = fmt.Sprintf("Welcome to Miniature by DevGenie, press q to quit. Total runtime: %s", usageStats.TimeElapsed) + generalStatsRows := []string{ + fmt.Sprintf("Available connections: %d", usageStats.AvailableSlots), + fmt.Sprintf("Peers connected: %d", usageStats.Peers), + fmt.Sprintf("Total bytes in: %d", usageStats.ConnectionsIn), + fmt.Sprintf("Total bytes out: %d", usageStats.ConnectionsOut), } - networkData.Data = append(networkData.Data, float64(usageStats.Peers)) - peerStats.Rows = generalStatsRows - systemStats.Rows = systemStatsRows + + networkDataIn.Data = append(networkDataIn.Data, float64(usageStats.ConnectionsIn)) + networkDataOut.Data = append(networkDataOut.Data, float64(usageStats.ConnectionsOut)) + info.Rows = generalStatsRows ui.Render(grid) - tickerCount++ - networkData.Title = fmt.Sprintf("Peers Connected: %d %s", tickerCount, termWidth) } } } @@ -121,11 +116,11 @@ func callStats() miniature.Stats { fmt.Print(err.Error()) } defer resp.Body.Close() - bodyBytes, err := ioutil.ReadAll(resp.Body) + bodyBytes, err := io.ReadAll(resp.Body) if err != nil { fmt.Print(err.Error()) } var responseObject miniature.Stats json.Unmarshal(bodyBytes, &responseObject) return responseObject -} \ No newline at end of file +} diff --git a/cmd/server/main.go b/cmd/server/main.go index 2296f87..c47a4c5 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -31,34 +31,31 @@ func main() { serverConfigFlag := runFlag.String("config", "/etc/miniature/config.yml", "Server configuration file") clientConfig := flag.NewFlagSet("newclient", flag.ExitOnError) - configFile := clientConfig.String("config", "/etc/miniature/config.yml", "Server Configuration File") + username := clientConfig.String("username", "", "Username") + password := clientConfig.String("password", "", "Password") if len(os.Args) > 1 { switch os.Args[1] { case "newclient": - serverConfig := new(miniature.ServerConfig) - if len(os.Args) == 3 { + if len(os.Args) == 4 { err := clientConfig.Parse(os.Args[2:]) if err != nil { log.Fatal(err) } - serverConfigYamlPath := *configFile - err = utilities.FileToYaml(serverConfigYamlPath, serverConfig) + + db := new(miniature.DatabaseObject) + db.Init() + vpnUser := new(miniature.User) + vpnUser.Username = *username + vpnUser.Password = *password + + err = db.AddUser(vpnUser) if err != nil { log.Fatal(err) } } else { - serverConfig.CertificatesDirectory = "/etc/miniature/certs" - serverConfig.Network = "10.2.0.0/24" - } - server := new(miniature.Server) - server.Config = *serverConfig - config, err := server.CreateClientConfig() - if err != nil { - log.Fatal(err) - break + log.Println(os.Args) } - log.Println(config) case "run": startServer(*serverConfigFlag) if len(os.Args) == 3 { diff --git a/dockerfile b/dockerfile index 5a44f13..9731242 100644 --- a/dockerfile +++ b/dockerfile @@ -1,7 +1,8 @@ -FROM golang:1.12.5-alpine +FROM golang:1.21.5-alpine RUN apk update RUN apk upgrade RUN apk add git +RUN apk add sqlite RUN apk add iptables RUN apk add bash RUN apk add curl @@ -12,3 +13,6 @@ RUN mkdir /miniature COPY . /miniature WORKDIR /miniature RUN export GO111MODULE=on +EXPOSE 8080 +EXPOSE 443 +EXPOSE 4321/udp \ No newline at end of file diff --git a/go.mod b/go.mod index cefd96a..d06e143 100644 --- a/go.mod +++ b/go.mod @@ -1,19 +1,53 @@ module github.com/devgenie/miniature -go 1.12 +go 1.21 + +toolchain go1.21.5 require ( + fyne.io/fyne/v2 v2.1.3 github.com/aead/ecdh v0.2.0 - github.com/gizak/termui/v3 v3.1.0 // indirect - github.com/go-chi/chi v1.5.4 // indirect - github.com/google/uuid v1.2.0 // indirect - github.com/lithammer/shortuuid/v3 v3.0.5 + github.com/gizak/termui/v3 v3.1.0 + github.com/go-chi/chi v1.5.4 github.com/pierrec/lz4 v2.6.0+incompatible - github.com/pierrec/lz4/v4 v4.1.3 + github.com/rickb777/date v1.20.5 github.com/robfig/cron v1.2.0 github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 - golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 // indirect - golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d - golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43 // indirect - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b + golang.org/x/net v0.18.0 + gopkg.in/yaml.v3 v3.0.1 +) + +require ( + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + github.com/mattn/go-sqlite3 v1.14.19 // indirect + gorm.io/driver/sqlite v1.5.4 // indirect + gorm.io/gorm v1.25.5 // indirect +) + +require ( + fyne.io/fyne v1.4.3 + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/frankban/quicktest v1.14.2 // indirect + github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3 // indirect + github.com/fsnotify/fsnotify v1.4.9 // indirect + github.com/go-gl/gl v0.0.0-20210813123233-e4099ee2221f // indirect + github.com/go-gl/glfw/v3.3/glfw v0.0.0-20211024062804-40e447a793be // indirect + github.com/godbus/dbus/v5 v5.0.4 // indirect + github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff // indirect + github.com/mattn/go-runewidth v0.0.2 // indirect + github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 // indirect + github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d // indirect + github.com/onsi/gomega v1.30.0 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rickb777/plural v1.4.1 // indirect + github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564 // indirect + github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9 // indirect + github.com/stretchr/testify v1.6.1 // indirect + github.com/yuin/goldmark v1.4.13 // indirect + golang.org/x/crypto v0.15.0 // indirect + golang.org/x/image v0.0.0-20200430140353-33d19683fad8 // indirect + golang.org/x/sys v0.14.0 // indirect + golang.org/x/text v0.14.0 // indirect + gopkg.in/yaml.v2 v2.4.0 ) diff --git a/gui/main.go b/gui/main.go new file mode 100644 index 0000000..8f50fc1 --- /dev/null +++ b/gui/main.go @@ -0,0 +1,129 @@ +package main + +import ( + "bytes" + "encoding/gob" + "encoding/json" + "fmt" + "io/ioutil" + "log" + "net/http" + + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/app" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/widget" + "github.com/aead/ecdh" + "github.com/devgenie/miniature/internal/miniature" + yaml "gopkg.in/yaml.v2" +) + +type UserResponse struct { + Name string `json:"name"` + Password string `json:"password"` +} + +func main() { + a := app.New() + w := a.NewWindow("Miniature VPN") + + serverAddresslabel := widget.NewLabel("Server Address") + serverAddress := widget.NewEntry() + serverAddress.SetPlaceHolder("192.0.0.2 or xyz.com") + + usernameLabel := widget.NewLabel("Username") + username := widget.NewEntry() + username.SetPlaceHolder("Username") + + passwordLabel := widget.NewLabel("Password") + password := widget.NewPasswordEntry() + password.SetPlaceHolder("Password") + + connectButton := widget.NewButton("Connect", nil) + connectButtonLayout := container.New(layout.NewGridLayout(3), layout.NewSpacer(), connectButton, layout.NewSpacer()) + + authArea := container.New(layout.NewFormLayout(), + serverAddresslabel, + serverAddress, + usernameLabel, + username, + passwordLabel, + password) + + w.SetContent(container.New(layout.NewVBoxLayout(), + authArea, + connectButtonLayout)) + w.SetFixedSize(true) + w.Resize(fyne.NewSize(400, 80)) + + connectButton.OnTapped = func() { + serverAddress.Disable() + password.Disable() + loadingLabel := widget.NewLabel("Authenticating") + loadingBar := widget.NewProgressBarInfinite() + cancelButton := widget.NewButton("Cancel", nil) + popup := widget.NewModalPopUp(container.NewVBox(loadingLabel, loadingBar, cancelButton), w.Canvas()) + popup.Resize(fyne.NewSize(200, 100)) + popup.Show() + cancelButton.OnTapped = func() { + popup.Hide() + serverAddress.Enable() + password.Enable() + } + connectClient(serverAddress.Text, username.Text, password.Text) + } + + w.SetPadded(true) + w.CenterOnScreen() + w.ShowAndRun() +} + +func connectClient(serverAddress, username, password string) error { + client := &http.Client{} + gob.Register(ecdh.Point{}) + serverAddr := fmt.Sprintf("http://%s:8080/client/auth", serverAddress) + reqBody := &miniature.User{ + Username: username, + Password: password, + } + payloadBuf := new(bytes.Buffer) + json.NewEncoder(payloadBuf).Encode(reqBody) + fmt.Println(payloadBuf) + req, err := http.NewRequest("POST", serverAddr, payloadBuf) + if err != nil { + fmt.Print(err.Error()) + return err + } + + req.Header.Add("Accept", "application/json") + req.Header.Add("Content-Type", "application/json") + resp, err := client.Do(req) + if err != nil { + fmt.Print(err.Error()) + return err + } + + defer resp.Body.Close() + bodyBytes, err := ioutil.ReadAll(resp.Body) + if err != nil { + fmt.Print(err.Error()) + return err + } + var clientResponse miniature.ClientResponse + json.Unmarshal(bodyBytes, &clientResponse) + clientConfig := new(miniature.ClientConfig) + err = yaml.Unmarshal(clientResponse.Cert, clientConfig) + if err != nil { + log.Fatal(err) + return err + } + vpnClient := new(miniature.Client) + clientConfig.ServerAddress = serverAddress + err = vpnClient.Run(*clientConfig) + if err != nil { + log.Fatal(err) + return err + } + return nil +} diff --git a/internal/miniature/client.go b/internal/miniature/client.go index 6c60c01..c2c801b 100644 --- a/internal/miniature/client.go +++ b/internal/miniature/client.go @@ -102,7 +102,8 @@ func (client *Client) AuthenticateUser() error { cert, err := tls.X509KeyPair([]byte(client.config.Certificate), []byte(client.config.PrivateKey)) if err != nil { - panic(err) + log.Println(err) + return err } conf := &tls.Config{ RootCAs: certPool, @@ -271,7 +272,7 @@ func (client *Client) handleIncomingConnections() { } } else { if err := client.AuthenticateUser(); err != nil { - log.Println(err) + log.Println("Failed to authenticate client", err) return } } @@ -281,7 +282,7 @@ func (client *Client) handleIncomingConnections() { func (client *Client) writeToIfce(packet []byte) { _, err := client.ifce.Ifce.Write(packet) if err != nil { - fmt.Println(err) + fmt.Println("Failed to write to interface", err) return } } @@ -319,9 +320,6 @@ func (client *Client) handleOutgoingConnections() { log.Println("Error compressing:", err) return } - // log.Printf("Sending %d bytes to %s \n", len(compressedPacket), header.Dst) - // log.Printf("Version %d, Protocol %d \n", header.Version, header.Protocol) - _, err = client.conn.Write(compressedPacket) if err != nil { fmt.Println("Failed to write to tunnel", err) @@ -348,7 +346,7 @@ func (client *Client) HeartBeat() { encryptedData, err := codec.Encrypt(client.secret, encodedPeer) if err != nil { - log.Println(err) + log.Println("Failed to encrypt data", err) return } @@ -380,12 +378,12 @@ func (client *Client) setUpDNS(resolvers []string) error { for _, resolver := range resolvers { content += fmt.Sprintf("nameserver %s\n", resolver) } - return ioutil.WriteFile("/etc/resolv.conf", []byte(content), 0644) + return os.WriteFile("/etc/resolv.conf", []byte(content), 0644) } // ResetDNS resets the resolv.conf file to the one before the vpn client was started func (client *Client) ResetDNS() error { - err := ioutil.WriteFile("/etc/resolv.conf", []byte(client.resolveFile), 0644) + err := os.WriteFile("/etc/resolv.conf", []byte(client.resolveFile), 0644) if err != nil { log.Println("Failed to restore /etc/resolv.conf file, restore the file manually by copying the contents below and pasting them into /etc/resolve.conf file") fmt.Println(client.resolveFile) @@ -411,7 +409,7 @@ func (client *Client) CleanUp() { common.DeleteRoute(route.Destination) err := common.AddRoute(route) if err != nil { - log.Println(err) + log.Println("Failed to add route", err) } } } diff --git a/internal/miniature/database.go b/internal/miniature/database.go new file mode 100644 index 0000000..3e11094 --- /dev/null +++ b/internal/miniature/database.go @@ -0,0 +1,75 @@ +package miniature + +import ( + "fmt" + "log" + + "golang.org/x/crypto/bcrypt" + "gorm.io/driver/sqlite" + "gorm.io/gorm" + + _ "github.com/mattn/go-sqlite3" +) + +type DatabaseObject struct { + DBConn *gorm.DB +} + +type User struct { + ID uint `gorm:"primaryKey"` + Username string `gorm:"unique"` + Password string +} + +func (dbObj *DatabaseObject) Init() (err error) { + dbObj.DBConn, err = gorm.Open(sqlite.Open("/etc/miniature/miniature.db"), &gorm.Config{}) + if err != nil { + return err + } + + err = dbObj.DBConn.AutoMigrate(&User{}) + if err != nil { + log.Fatal("Error adding user to database") + return err + } + return nil +} + +func (dbObj *DatabaseObject) AddUser(user *User) (err error) { + hashedPassword, err := hashPassword(user.Password) + if err != nil { + return err + } + user.Password = hashedPassword + result := dbObj.DBConn.Create(user) + if result.Error != nil { + return result.Error + } + return nil +} + +func (dbObj *DatabaseObject) GetUser(username, password string) (*User, error) { + var user User + result := dbObj.DBConn.First(&user, "username = ?", username) + if result.Error != nil { + return nil, result.Error + } + + err := checkPassword(password, user.Password) + if err != nil { + return nil, err + } + return &user, nil +} + +func hashPassword(password string) (string, error) { + hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) + if err != nil { + return "", fmt.Errorf("failed to hash password: %w", err) + } + return string(hashedPassword), nil +} + +func checkPassword(password string, hashedPassword string) error { + return bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password)) +} diff --git a/internal/miniature/http.go b/internal/miniature/http.go index 39885a9..1b6c78c 100644 --- a/internal/miniature/http.go +++ b/internal/miniature/http.go @@ -8,6 +8,7 @@ import ( "github.com/go-chi/chi" "github.com/go-chi/chi/middleware" + "github.com/rickb777/date/period" ) // HTTPServer ... @@ -27,6 +28,10 @@ type Stats struct { AvailableSlots int `json:"AvailableSlots"` } +type ClientResponse struct { + Cert []byte +} + func startHTTPServer(miniatureServer *Server) error { defer miniatureServer.waiter.Done() router := chi.NewRouter() @@ -36,10 +41,10 @@ func startHTTPServer(miniatureServer *Server) error { httpServer.server = miniatureServer router.Get("/stats", httpServer.handleStats) - router.Post("/client", httpServer.createClientConfig) + router.Post("/client/auth", httpServer.createClientConfig) log.Println("Server started at 8080") - err := http.ListenAndServe("127.0.0.1:8080", router) + err := http.ListenAndServe("0.0.0.0:8080", router) return err } @@ -55,7 +60,8 @@ func (httpServer *HTTPServer) handleStats(w http.ResponseWriter, r *http.Request serverStats.Peers = httpServer.server.connectionPool.ConnectedPeersCount() serverStats.AvailableSlots = httpServer.server.connectionPool.AvailableAddressesCount() timeStarted := time.Unix(0, httpServer.server.metrics.TimeStarted) - serverStats.TimeElapsed = time.Since(timeStarted).String() + timeElapsed, _ := period.NewOf(time.Since(timeStarted)) + serverStats.TimeElapsed = timeElapsed.Format() jsonResponse, _ := json.Marshal(serverStats) w.Write(jsonResponse) } else { @@ -65,11 +71,33 @@ func (httpServer *HTTPServer) handleStats(w http.ResponseWriter, r *http.Request func (httpServer *HTTPServer) createClientConfig(w http.ResponseWriter, r *http.Request) { if r.Method == "POST" { + decoder := json.NewDecoder(r.Body) + user := new(User) + err := decoder.Decode(user) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } + db := new(DatabaseObject) + db.Init() + _, err = db.GetUser(user.Username, user.Password) + if err != nil { + log.Println("Failed to fetch user", err) + w.WriteHeader(http.StatusInternalServerError) + return + } + clientConfig, err := httpServer.server.CreateClientConfig() if err != nil { + log.Println("Failed to create client config", err) w.WriteHeader(http.StatusInternalServerError) + return + } else { + clientResponse := new(ClientResponse) + clientResponse.Cert = []byte(clientConfig) + jsonResponse, _ := json.Marshal(clientResponse) + w.Write(jsonResponse) } - w.Write([]byte(clientConfig)) } else { w.WriteHeader(http.StatusMethodNotAllowed) } diff --git a/internal/miniature/server.go b/internal/miniature/server.go index ba0ff40..3bee5d5 100644 --- a/internal/miniature/server.go +++ b/internal/miniature/server.go @@ -11,7 +11,6 @@ import ( "encoding/gob" "encoding/pem" "fmt" - "io/ioutil" "log" "net" "os" @@ -92,8 +91,7 @@ func (server *Server) Run(config ServerConfig) { _, network, err := net.ParseCIDR(config.Network) if err != nil { - log.Println(err) - log.Println("Failed to parse cidre") + log.Println("Failed to parse cidre", err) return } @@ -102,10 +100,9 @@ func (server *Server) Run(config ServerConfig) { log.Printf("Generated %v ip addresses \n", server.connectionPool.AvailableAddressesCount()) ip := net.ParseIP(server.connectionPool.NetworkAddress) - fmt.Println("TunIP", server.connectionPool.NetworkAddress) err = ifce.Configure(ip, ip, 1300) if err != nil { - log.Printf("Error: %s \n", err) + log.Println("Failed to configure interface:", err) return } @@ -113,11 +110,13 @@ func (server *Server) Run(config ServerConfig) { command := fmt.Sprintf("route add %s dev %s", network.String(), ifce.Ifce.Name()) err = utilities.RunCommand("ip", command) if err != nil { + fmt.Println(err) return } gatewayIfce, _, err := utilities.GetDefaultGateway() if err != nil { + fmt.Println("Failed to get default interface", gatewayIfce, err) return } @@ -240,7 +239,7 @@ func (server *Server) CreateClientConfig() (yamlConfiguration string, errorMessa return "", err } - caCertBytes, err := ioutil.ReadFile(certPath) + caCertBytes, err := os.ReadFile(certPath) if err != nil { return "", err } @@ -358,13 +357,13 @@ func (server *Server) generateServerCerts() error { serverCertFile := fmt.Sprintf("%s/%s", server.Config.CertificatesDirectory, "server.crt") serverPrivatekeyPath := fmt.Sprintf("%s/%s", server.Config.CertificatesDirectory, "server.pem") - err = ioutil.WriteFile(serverCertFile, certBytes, 0644) + err = os.WriteFile(serverCertFile, certBytes, 0644) if err != nil { log.Println("Failed to write Certificate file") return err } - err = ioutil.WriteFile(serverPrivatekeyPath, privateKeyBytes, 0644) + err = os.WriteFile(serverPrivatekeyPath, privateKeyBytes, 0644) if err != nil { log.Println("Failed to write private key") return err @@ -376,11 +375,13 @@ func (server *Server) generateServerCerts() error { func (server *Server) generateCerts(certPath string, privatekeyPath string) (privateKey []byte, cert []byte, err error) { serverCertificate, err := tls.LoadX509KeyPair(certPath, privatekeyPath) if err != nil { + fmt.Println(err) return nil, nil, err } ca, err := x509.ParseCertificate(serverCertificate.Certificate[0]) if err != nil { + fmt.Println(err) return nil, nil, err } clientCertTemplate := *ca @@ -438,7 +439,7 @@ func (server *Server) listenTLS() { crtFile := fmt.Sprintf("%s/%s", server.Config.CertificatesDirectory, "server.crt") privateKey := fmt.Sprintf("%s/%s", server.Config.CertificatesDirectory, "server.pem") - certPem, err := ioutil.ReadFile(caFile) + certPem, err := os.ReadFile(caFile) if err != nil { log.Println(err) } @@ -519,7 +520,7 @@ func (server *Server) handleHandshake(conn net.Conn, payload []byte) error { serverKEX := ecdh.Generic(elliptic.P256()) serverPrivateKey, serverPublicKey, err := serverKEX.GenerateKey(rand.Reader) if err != nil { - log.Println(err) + log.Println("Failed to generate key", err) return err } peer := server.connectionPool.NewPeer() @@ -530,11 +531,9 @@ func (server *Server) handleHandshake(conn net.Conn, payload []byte) error { handshakePacket.ClientIP = clientIP handshakePacket.ServerPublic = serverPublicKey handshakePacket.DNSResolvers = server.Config.DNSResolvers - fmt.Println("DNS resolvers", server.Config.DNSResolvers) handshakePacketBytes, err := utilities.Encode(handshakePacket) if err != nil { - log.Println(err) return err } packetData := utilities.Packet{Flag: utilities.HANDSHAKE_ACCEPTED, Payload: handshakePacketBytes} @@ -576,6 +575,7 @@ func (server *Server) listenAndServe() { headerFlag := headerData[4] peer := server.connectionPool.GetPeer(srcIP.String()) if peer == nil { + fmt.Println("Failed to get peer") return } @@ -590,7 +590,7 @@ func (server *Server) listenAndServe() { case utilities.HEARTBEAT: server.handleHeartbeat(decryptedPayload) case utilities.SESSION: - server.handleConnection(peer, decryptedPayload) + go server.handleConnection(peer, decryptedPayload) default: log.Println("Expected headers not found") } @@ -602,7 +602,7 @@ func (server *Server) handleConnection(peer *Peer, packet []byte) { server.connectionPool.Update(peer.IP, *peer) _, err := server.tunInterface.Ifce.Write(packet) if err != nil { - fmt.Println(err) + fmt.Println("Failed to write to tun interface", err) return } } @@ -627,7 +627,7 @@ func (server *Server) readIfce() { buffer := make([]byte, server.tunInterface.Mtu) length, err := server.tunInterface.Ifce.Read(buffer) if err != nil { - log.Println(err) + log.Println("Failed to read from tun interface", err) continue } @@ -635,7 +635,7 @@ func (server *Server) readIfce() { if length > -4 { header, err := ipv4.ParseHeader(data) if err != nil { - log.Println(err) + log.Println("Error parsing header", err) return } peer := server.connectionPool.GetPeer(header.Dst.String()) @@ -649,13 +649,13 @@ func (server *Server) readIfce() { compressedPacket, err := Compress(sendPacket) if err != nil { - log.Println(err) + log.Println("Failed to compress packet", err) return } _, err = server.socket.WriteTo(compressedPacket, peer.Addr) if err != nil { - fmt.Println(err) + fmt.Println("Failed to write to socket", err) return } go server.metrics.Update(0, len(sendPacket), len(compressedPacket), length) diff --git a/internal/miniature/unix.go b/internal/miniature/unix.go index f545a58..1f6dd02 100644 --- a/internal/miniature/unix.go +++ b/internal/miniature/unix.go @@ -2,7 +2,6 @@ package miniature import ( "fmt" - "io/ioutil" "log" "os" @@ -13,21 +12,22 @@ import ( // SetDarwinClient sets up IP tables on Darwin hosts func SetDarwinClient(defaultGWIface string, defaultGWAddr string, tunnelIface string, tunnelIP string, serverIP string, dnsServer string) error { command := fmt.Sprintf("nat on %s from %s to any -> (%s) \n", defaultGWIface, tunnelIP, defaultGWIface) - tmpFile, err := ioutil.TempFile(os.TempDir(), "minature-") + tmpFile, err := os.CreateTemp(os.TempDir(), "minature-") defer os.Remove(tmpFile.Name()) defer tmpFile.Close() pfctl := []byte(command) _, err = tmpFile.Write(pfctl) + fmt.Println(string(pfctl)) + fmt.Println(string(command)) if err != nil { log.Fatal("Failed to write to temporary file", err) return err } - fmt.Println(command) command = fmt.Sprintf("-f %s", tmpFile.Name()) err = utilities.RunCommand("pfctl", command) if err != nil { - tmpFile.Close() + fmt.Println(err) return err } diff --git a/serverconfig.yaml b/serverconfig.yaml new file mode 100644 index 0000000..6038e19 --- /dev/null +++ b/serverconfig.yaml @@ -0,0 +1,10 @@ +certificatesdirectory: /etc/miniature/certs + +network: 10.114.0.0/24 + +listeningport: 4321 + +publicip: 164.92.160.186 + +dnsresolvers: + - 8.8.8.8 \ No newline at end of file diff --git a/start.sh b/start.sh new file mode 100755 index 0000000..c50a25f --- /dev/null +++ b/start.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +mkdir /etc/miniature/ +cp serverconfig.yaml /etc/miniature/config.yml +./server run -config=/etc/miniature/config.yml \ No newline at end of file