From cdaf0dd68d8dc0008c46e2595711cad54fcbd4e0 Mon Sep 17 00:00:00 2001 From: Xavier Henner Date: Mon, 8 Jul 2019 16:36:56 +0200 Subject: [PATCH] Initial tests --- .gitignore | 3 + httpd.go | 51 +++++++++++++++++ main.go | 7 +++ notes.txt | 11 ++++ tcpserver.go | 159 +++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 231 insertions(+) create mode 100644 .gitignore create mode 100644 httpd.go create mode 100644 main.go create mode 100644 notes.txt create mode 100644 tcpserver.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..39b6aa3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +config.json +test.sh +openvpn-dm-mgt-server diff --git a/httpd.go b/httpd.go new file mode 100644 index 0000000..7fd654d --- /dev/null +++ b/httpd.go @@ -0,0 +1,51 @@ +package main + +import ( + "encoding/json" + "fmt" + "log" + "net/http" +) + +type HttpServer struct { + Port string + ovpn *OpenVpnMgt +} + +func (h *HttpServer) handler(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:]) +} + +func (h *HttpServer) versionHandler(w http.ResponseWriter, r *http.Request) { + err, message := h.ovpn.Version() + if err != nil { + fmt.Fprintf(w, "Error : %s", err) + } + + jsonStr, err := json.Marshal(message) + if err != nil { + fmt.Fprintf(w, "Error : %s", err) + } + fmt.Fprintf(w, "%s", jsonStr) +} + +func (h *HttpServer) helpHandler(w http.ResponseWriter, r *http.Request) { + err, message := h.ovpn.Help() + if err != nil { + fmt.Fprintf(w, "Error : %s", err) + } else { + fmt.Fprintf(w, "%s", message) + } + +} + +func NewHTTPServer(port string, s *OpenVpnMgt) { + h := &HttpServer{ + Port: port, + ovpn: s, + } + http.HandleFunc("/help", h.helpHandler) + http.HandleFunc("/version", h.versionHandler) + http.HandleFunc("/", h.handler) + log.Fatal(http.ListenAndServe(port, nil)) +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..1315a50 --- /dev/null +++ b/main.go @@ -0,0 +1,7 @@ +package main + +func main() { + server := NewVPNServer(":4000") + go server.Run() + NewHTTPServer(":8080", server) +} diff --git a/notes.txt b/notes.txt new file mode 100644 index 0000000..d052f74 --- /dev/null +++ b/notes.txt @@ -0,0 +1,11 @@ + + +client-deny 0 0 "Need OTP" "CRV1:R:blabla:ZXVjbGlkZQ==:OTP Code " + + +client-auth 1 0 +ifconfig-push 10.8.66.3 10.8.66.1 +push "dhcp-option DNS 10.190.32.2" +push "dhcp-option DNS 10.190.32.20" +END + diff --git a/tcpserver.go b/tcpserver.go new file mode 100644 index 0000000..b782005 --- /dev/null +++ b/tcpserver.go @@ -0,0 +1,159 @@ +package main + +import ( + "bufio" + "errors" + "fmt" + "io" + "log" + "net" + "strings" + "sync" +) + +// Server represents the server +type OpenVpnMgt struct { + Port string + buf *bufio.ReadWriter + connected bool + m sync.RWMutex + ret chan []string +} + +// NewServer returns a pointer to a new server +func NewVPNServer(port string) *OpenVpnMgt { + return &OpenVpnMgt{ + Port: port, + ret: make(chan []string), + } +} + +// Run starts a the server +func (s *OpenVpnMgt) Run() { + // Resolve the passed port into an address + addrs, err := net.ResolveTCPAddr("tcp", s.Port) + if err != nil { + return + } + // start listening to client connections + listener, err := net.ListenTCP("tcp", addrs) + if err != nil { + fmt.Println(err) + } + // Infinite loop since we dont want the server to shut down + for { + // Accept the incomming connections + conn, err := listener.Accept() + if err != nil { + // continue accepting connection even if an error occurs (if error occurs dont shut down) + continue + } + // run it as a go routine to allow multiple clients to connect at the same time + go s.handleConn(conn) + } +} + +func (s *OpenVpnMgt) sendCommand(msg []string) (error, []string) { + if !s.connected { + return errors.New("No openvpn server present"), nil + } + for _, line := range msg { + if _, err := s.buf.WriteString(line + "\r\n"); err != nil { + return err, nil + } + } + + if err := s.buf.Flush(); err != nil { + return err, nil + } + + // wait for the response + ret := <-s.ret + return nil, ret +} + +func (s *OpenVpnMgt) Help() (error, []string) { + err, msg := s.sendCommand([]string{"help"}) + if err != nil { + return err, nil + } + return nil, msg +} + +func (s *OpenVpnMgt) Version() (error, []string) { + err, msg := s.sendCommand([]string{"version"}) + if err != nil { + return err, nil + } + return nil, msg +} + +func (s *OpenVpnMgt) ClientDisconnect(line string) { + msg := <-s.ret + log.Println(msg) +} + +func (s *OpenVpnMgt) ClientConnect(line string) { + msg := <-s.ret + log.Println(msg) +} + +func (s *OpenVpnMgt) handleConn(conn net.Conn) { + defer conn.Close() + + // we don't want multiple connexions, only one openvpn server at a time + s.m.Lock() + if s.connected { + conn.Write([]byte("Sorry, only one server allowed\n")) + s.m.Unlock() + return + } + s.connected = true + s.m.Unlock() + + // we store the buffer pointer in the struct, to be accessed from other methods + s.buf = bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + + // most response are multilined, use response to concatenate them + response := []string{} + + for { + line, err := s.buf.ReadString('\n') + + // manage basic errors + switch { + case err == io.EOF: + log.Println("Reached EOF - close this connection.\n") + s.connected = false + return + case err != nil: + log.Println("Error reading line. Got: '"+line+"'\n", err) + s.connected = false + return + } + line = strings.Trim(line, "\n\r ") + + switch { + // a new openvpn server is connected + case strings.HasPrefix(line, ">INFO"): + + // new bloc for a disconnect event. + // We start the receiving handler, which will wait for the Channel message + case strings.HasPrefix(line, ">CLIENT:DISCONNECT"): + go s.ClientDisconnect(line) + + // new bloc for a connect event. + // We start the receiving handler, which will wait for the Channel message + case strings.HasPrefix(line, ">CLIENT:CONNECT"): + go s.ClientConnect(line) + + // write the cumulated lines into the channel to the current handler + case strings.HasPrefix(line, "END") || strings.HasPrefix(line, ">CLIENT:ENV,END"): + s.ret <- response + response = nil + default: + response = append(response, line) + } + log.Print(line) + } +}