openvpn-mgt/vpnserver.go

258 lines
5.6 KiB
Go
Raw Normal View History

2019-07-08 14:36:56 +00:00
package main
import (
"errors"
2019-08-15 09:19:40 +00:00
"fmt"
2019-07-08 14:36:56 +00:00
"io"
"log"
"net"
"strings"
"sync"
2019-08-16 15:23:19 +00:00
"time"
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-08-15 09:19:40 +00:00
port string
m sync.RWMutex
debug bool
VpnRemotes map[string]*map[string]string `json:"remotes"`
VpnServers map[int]*OpenVpnSrv `json:"sessions"`
LastChange time.Time `json:"last_change"`
2019-07-08 14:36:56 +00:00
}
// NewServer returns a pointer to a new server
2019-08-15 09:19:40 +00:00
func NewVPNServer(port string, debug bool) *OpenVpnMgt {
2019-07-08 14:36:56 +00:00
return &OpenVpnMgt{
2019-08-15 09:19:40 +00:00
port: port,
debug: debug,
2019-08-16 15:23:19 +00:00
VpnServers: make(map[int]*OpenVpnSrv),
VpnRemotes: make(map[string]*map[string]string),
2019-07-08 14:36:56 +00:00
}
}
2019-08-15 09:19:40 +00:00
func (s *OpenVpnMgt) Lock() {
s.m.Lock()
}
func (s *OpenVpnMgt) Unlock() {
s.m.Unlock()
}
2019-08-16 15:23:19 +00:00
func (s *OpenVpnMgt) Change() {
s.LastChange = time.Now().Round(time.Second)
}
2019-08-15 09:19:40 +00:00
2019-08-16 15:23:19 +00:00
func (s *OpenVpnMgt) Debug(v ...interface{}) {
if s.debug {
log.Println(v...)
2019-08-15 09:19:40 +00:00
}
2019-08-16 15:23:19 +00:00
}
2019-08-15 09:19:40 +00:00
2019-08-16 15:23:19 +00:00
// Run starts a the server
func (s *OpenVpnMgt) Run() {
2019-07-08 14:36:56 +00:00
// 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)
2019-08-15 09:19:40 +00:00
return
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)
2019-08-15 09:19:40 +00:00
return
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)
}
}
2019-08-16 15:23:19 +00:00
func (s *OpenVpnMgt) GetSession(pid int) (error, *OpenVpnSrv) {
if openvpn, ok := s.VpnServers[pid]; ok {
return nil, openvpn
}
2019-08-16 22:16:57 +00:00
// if there is only 1 session, ignore the pid parameter
if len(s.VpnServers) == 1 {
for _, openvpn := range s.VpnServers {
return nil, openvpn
}
}
2019-08-16 15:23:19 +00:00
return errors.New(fmt.Sprintf("unknown session %d", pid)), nil
}
func (s *OpenVpnMgt) Restart(pid int) error {
// check if the session is valid
err, session := s.GetSession(pid)
if err != nil {
return err
2019-07-08 23:44:18 +00:00
}
2019-08-16 15:23:19 +00:00
session.Signal("SIGHUP")
return nil
2019-08-15 09:19:40 +00:00
}
2019-07-08 23:44:18 +00:00
2019-08-16 22:16:57 +00:00
func (s *OpenVpnMgt) AuthUserPass(pid int, user, pass string) error {
// check if the session is valid
err, session := s.GetSession(pid)
if err != nil {
return err
}
session.AuthUserPass(user, pass)
return nil
}
2019-08-16 15:23:19 +00:00
func (s *OpenVpnMgt) Kill(pid int) error {
2019-08-15 09:19:40 +00:00
// check if the session is valid
2019-08-16 15:23:19 +00:00
err, session := s.GetSession(pid)
2019-08-15 09:19:40 +00:00
if err != nil {
return err
2019-07-08 23:44:18 +00:00
}
2019-08-16 15:23:19 +00:00
session.Signal("SIGTERM")
return nil
}
2019-07-08 23:44:18 +00:00
2019-08-16 15:23:19 +00:00
func (s *OpenVpnMgt) SetRemote(server string, pid int) error {
// check if the session is valid
err, session := s.GetSession(pid)
if err != nil {
return err
}
if session.Provider == "" {
return errors.New("No server list for this config")
}
if _, ok := s.VpnRemotes[session.Provider]; !ok {
return errors.New("No server list for this provider")
}
for _, r := range *(s.VpnRemotes[session.Provider]) {
2019-08-15 09:19:40 +00:00
if r != server {
continue
2019-07-11 06:14:38 +00:00
}
2019-08-15 09:19:40 +00:00
return session.SetRemote(server)
2019-07-11 06:14:38 +00:00
}
2019-08-16 15:23:19 +00:00
return errors.New(fmt.Sprintf("unknown session %s", server))
}
func (s *OpenVpnMgt) SetPid(openvpn *OpenVpnSrv, pid int) {
s.Lock()
defer s.Unlock()
s.VpnServers[pid] = openvpn
}
func (s *OpenVpnMgt) Remove(openvpn *OpenVpnSrv) {
for pid, v := range s.VpnServers {
if v == openvpn {
delete(s.VpnServers, pid)
}
}
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
2019-08-15 09:19:40 +00:00
func (s *OpenVpnMgt) Version() (error, map[int][]string) {
var err error
ret := make(map[int][]string)
2019-08-16 15:23:19 +00:00
for pid, srv := range s.VpnServers {
2019-08-15 09:19:40 +00:00
err, msg := srv.Version()
if err == nil {
2019-08-16 15:23:19 +00:00
ret[pid] = msg
2019-07-08 14:36:56 +00:00
}
}
2019-08-15 09:19:40 +00:00
return err, ret
2019-07-08 14:36:56 +00:00
}
// 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-08-15 09:19:40 +00:00
remoteRegexp := rcache.Get("^>REMOTE:(.*),([0-9]*),(.*)$")
2019-07-08 14:36:56 +00:00
defer conn.Close()
2019-08-16 15:23:19 +00:00
openvpn := NewOpenVpnSrv(conn, s)
defer s.Remove(openvpn)
2019-07-08 14:36:56 +00:00
// most response are multilined, use response to concatenate them
response := []string{}
// remove bogus clients
2019-08-16 15:23:19 +00:00
line, err := openvpn.GetLine()
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-08-16 15:23:19 +00:00
go openvpn.GetEcho()
go openvpn.GetPid()
s.Change()
defer s.Change()
2019-08-15 09:19:40 +00:00
2019-07-08 14:36:56 +00:00
for {
2019-08-16 15:23:19 +00:00
line, err := openvpn.GetLine()
2019-07-08 14:36:56 +00:00
// manage basic errors
switch {
case err == io.EOF:
2019-08-16 15:23:19 +00:00
log.Println("Reached EOF - close this connection")
2019-07-08 14:36:56 +00:00
return
case err != nil:
2019-08-16 15:23:19 +00:00
log.Printf("Error reading line. Got: '"+line+"'\n", err)
2019-07-08 14:36:56 +00:00
return
}
line = strings.Trim(line, "\n\r ")
2019-08-16 15:23:19 +00:00
if strings.Index(line, "password") == -1 {
s.Debug(line)
2019-08-15 09:19:40 +00:00
}
// 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) {
2019-08-16 15:23:19 +00:00
openvpn.Response(append(response, line))
response = nil
line = ""
2019-08-16 15:23:19 +00:00
s.Change()
break
}
}
2019-08-15 09:19:40 +00:00
remoteMatch := remoteRegexp.FindStringSubmatch(line)
2019-07-08 14:36:56 +00:00
switch {
// command successfull, we can ignore
2019-08-16 22:16:57 +00:00
case strings.HasPrefix(line, ">PASSWORD:"):
go openvpn.NeedPassword(line)
2019-07-30 14:34:12 +00:00
case strings.HasPrefix(line, ">HOLD"):
2019-08-16 15:23:19 +00:00
go openvpn.waitForRelase()
2019-08-15 09:19:40 +00:00
case len(remoteMatch) > 0:
2019-08-16 15:23:19 +00:00
go openvpn.ValidRemote(remoteMatch[1], remoteMatch[2], remoteMatch[3])
2019-07-08 14:36:56 +00:00
default:
response = append(response, line)
}
}
}