openvpn-mgt/vpnserver.go

198 lines
4.4 KiB
Go
Raw Normal View History

2019-07-08 14:36:56 +00:00
package main
import (
"bufio"
"errors"
"io"
"log"
"net"
2019-07-08 20:32:12 +00:00
"os"
2019-07-08 14:36:56 +00:00
"strings"
"sync"
2019-07-11 06:14:38 +00:00
"github.com/pyke369/golang-support/rcache"
2019-07-08 14:36:56 +00:00
)
// Server represents the server
type OpenVpnMgt struct {
2019-07-21 17:23:13 +00:00
port string
buf map[string]*bufio.ReadWriter
m sync.RWMutex
ret chan []string
syslog bool
debug bool
hold bool
2019-07-08 14:36:56 +00:00
}
// NewServer returns a pointer to a new server
func NewVPNServer(port string) *OpenVpnMgt {
return &OpenVpnMgt{
2019-07-21 17:23:13 +00:00
port: port,
ret: make(chan []string),
buf: make(map[string]*bufio.ReadWriter),
2019-07-08 14:36:56 +00:00
}
}
// Run starts a the server
func (s *OpenVpnMgt) Run() {
// Resolve the passed port into an address
2019-07-11 06:14:38 +00:00
addrs, err := net.ResolveTCPAddr("tcp", s.port)
2019-07-08 14:36:56 +00:00
if err != nil {
2019-07-08 20:32:12 +00:00
log.Println(err)
os.Exit(1)
2019-07-08 14:36:56 +00:00
}
// start listening to client connections
listener, err := net.ListenTCP("tcp", addrs)
if err != nil {
2019-07-08 20:32:12 +00:00
log.Println(err)
os.Exit(1)
2019-07-08 14:36:56 +00:00
}
// 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)
}
}
// send a command to the server. Set the channel to receive the response
func (s *OpenVpnMgt) sendCommand(msg []string, remote string) (error, []string) {
if len(s.buf) == 0 {
return errors.New("No openvpn server present"), nil
}
for _, line := range msg {
2019-07-11 06:14:38 +00:00
if s.debug {
log.Println(line)
}
if _, err := s.buf[remote].WriteString(line + "\r\n"); err != nil {
return err, nil
}
2019-07-08 23:44:18 +00:00
}
if err := s.buf[remote].Flush(); err != nil {
return err, nil
2019-07-08 23:44:18 +00:00
}
// wait for the response
ret := <-s.ret
2019-07-11 06:14:38 +00:00
if s.debug {
for _, line := range ret {
log.Println(line)
}
}
return nil, ret
}
// send the help command on all vpn servers. Kind of useless
func (s *OpenVpnMgt) Help() (error, map[string]map[string]string) {
ret := make(map[string]map[string]string)
re := rcache.Get("^(.*[^ ]) *: (.*)$")
for remote := range s.buf {
help := make(map[string]string)
err, msg := s.sendCommand([]string{"help"}, remote)
2019-07-09 10:34:45 +00:00
if err != nil {
return err, ret
2019-07-09 10:34:45 +00:00
}
for _, line := range msg {
match := re.FindStringSubmatch(line)
if len(match) == 0 {
2019-07-08 23:44:18 +00:00
continue
}
help[match[1]] = match[2]
2019-07-08 23:44:18 +00:00
}
ret[remote] = help
}
return nil, ret
2019-07-08 23:44:18 +00:00
}
2019-07-11 10:20:08 +00:00
// send the version command on all vpn servers. Kind of useless
func (s *OpenVpnMgt) Version() (error, map[string][]string) {
ret := make(map[string][]string)
for remote := range s.buf {
err, msg := s.sendCommand([]string{"version"}, remote)
if err != nil {
return err, ret
2019-07-08 14:36:56 +00:00
}
ret[remote] = msg
2019-07-08 14:36:56 +00:00
}
return nil, ret
}
// main loop for a given openvpn server
2019-07-08 14:36:56 +00:00
func (s *OpenVpnMgt) handleConn(conn net.Conn) {
remote := conn.RemoteAddr().String()
2019-07-08 14:36:56 +00:00
defer conn.Close()
defer delete(s.buf, remote)
2019-07-08 14:36:56 +00:00
// we store the buffer pointer in the struct, to be accessed from other methods
s.buf[remote] = bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn))
2019-07-08 14:36:56 +00:00
// most response are multilined, use response to concatenate them
response := []string{}
// remove bogus clients
line, err := s.buf[remote].ReadString('\n')
if err != nil {
log.Println(err)
return
}
if line != ">INFO:OpenVPN Management Interface Version 1 -- type 'help' for more info\r\n" {
log.Println("Bogus Client")
return
}
log.Printf("Valid openvpn connected from %s\n", remote)
2019-07-08 14:36:56 +00:00
for {
line, err := s.buf[remote].ReadString('\n')
2019-07-08 14:36:56 +00:00
// manage basic errors
switch {
case err == io.EOF:
log.Println("Reached EOF - close this connection.\n")
return
case err != nil:
log.Println("Error reading line. Got: '"+line+"'\n", err)
return
}
line = strings.Trim(line, "\n\r ")
// manage exit commands
for _, terminator := range []string{"quit", "exit"} {
if line == terminator || strings.HasPrefix(line, terminator+" ") {
log.Println("server disconnected")
return
}
}
// manage all "terminator" lines
2019-07-11 10:20:08 +00:00
for _, terminator := range []string{"END", ">CLIENT:ENV,END", "SUCCESS", "ERROR"} {
if strings.HasPrefix(line, terminator) {
s.ret <- response
response = nil
line = ""
break
}
}
2019-07-08 14:36:56 +00:00
switch {
// command successfull, we can ignore
2019-07-08 16:41:04 +00:00
case strings.HasPrefix(line, ">SUCCESS: client-deny command succeeded"):
2019-07-08 14:36:56 +00:00
default:
response = append(response, line)
}
2019-07-11 06:14:38 +00:00
if s.debug && strings.Index(line, "password") == -1 {
log.Print(line)
}
2019-07-08 14:36:56 +00:00
}
}