working prototype
This commit is contained in:
132
vpnserver.go
132
vpnserver.go
@@ -6,9 +6,9 @@ import (
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/pyke369/golang-support/rcache"
|
||||
)
|
||||
@@ -18,8 +18,9 @@ type OpenVpnMgt struct {
|
||||
port string
|
||||
m sync.RWMutex
|
||||
debug bool
|
||||
VpnRemotes []string `json:"remotes"`
|
||||
vpnServers map[int]*OpenVpnSrv `json:"sessions"`
|
||||
VpnRemotes map[string]*[]string `json:"remotes"`
|
||||
VpnServers map[int]*OpenVpnSrv `json:"sessions"`
|
||||
LastChange time.Time `json:"last_change"`
|
||||
}
|
||||
|
||||
// NewServer returns a pointer to a new server
|
||||
@@ -27,7 +28,8 @@ func NewVPNServer(port string, debug bool) *OpenVpnMgt {
|
||||
return &OpenVpnMgt{
|
||||
port: port,
|
||||
debug: debug,
|
||||
vpnServers: make(map[int]*OpenVpnSrv),
|
||||
VpnServers: make(map[int]*OpenVpnSrv),
|
||||
VpnRemotes: make(map[string]*[]string),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,15 +41,18 @@ func (s *OpenVpnMgt) Unlock() {
|
||||
s.m.Unlock()
|
||||
}
|
||||
|
||||
func (s *OpenVpnMgt) Change() {
|
||||
s.LastChange = time.Now().Round(time.Second)
|
||||
}
|
||||
|
||||
func (s *OpenVpnMgt) Debug(v ...interface{}) {
|
||||
if s.debug {
|
||||
log.Println(v...)
|
||||
}
|
||||
}
|
||||
|
||||
// Run starts a the server
|
||||
func (s *OpenVpnMgt) Run() {
|
||||
|
||||
// get the endpoint list
|
||||
if err := s.getServerList(); err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
// Resolve the passed port into an address
|
||||
addrs, err := net.ResolveTCPAddr("tcp", s.port)
|
||||
if err != nil {
|
||||
@@ -73,38 +78,82 @@ func (s *OpenVpnMgt) Run() {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *OpenVpnMgt) GetSession(remote int) (error, *OpenVpnSrv) {
|
||||
if vpnServer, ok := s.vpnServers[remote]; ok {
|
||||
return nil, vpnServer
|
||||
func (s *OpenVpnMgt) GetSession(pid int) (error, *OpenVpnSrv) {
|
||||
if openvpn, ok := s.VpnServers[pid]; ok {
|
||||
return nil, openvpn
|
||||
}
|
||||
return errors.New(fmt.Sprintf("unknown session %d", vpnServers)), nil
|
||||
return errors.New(fmt.Sprintf("unknown session %d", pid)), nil
|
||||
}
|
||||
|
||||
func (s *OpenVpnMgt) SetRemote(server string, remote int) error {
|
||||
func (s *OpenVpnMgt) Restart(pid int) error {
|
||||
// check if the session is valid
|
||||
err, session := s.GetSession(remote)
|
||||
err, session := s.GetSession(pid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
session.Signal("SIGHUP")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *OpenVpnMgt) Kill(pid int) error {
|
||||
// check if the session is valid
|
||||
err, session := s.GetSession(pid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
session.Signal("SIGTERM")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
for _, r := range s.VpnRemotes {
|
||||
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]) {
|
||||
if r != server {
|
||||
continue
|
||||
}
|
||||
return session.SetRemote(server)
|
||||
}
|
||||
|
||||
return errors.New(fmt.Sprintf("unknown remote %s", server))
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// send the version command on all vpn servers. Kind of useless
|
||||
func (s *OpenVpnMgt) Version() (error, map[int][]string) {
|
||||
var err error
|
||||
ret := make(map[int][]string)
|
||||
for remote, srv := range s.vpnServers {
|
||||
for pid, srv := range s.VpnServers {
|
||||
err, msg := srv.Version()
|
||||
if err == nil {
|
||||
ret[remote] = msg
|
||||
ret[pid] = msg
|
||||
}
|
||||
}
|
||||
return err, ret
|
||||
@@ -113,19 +162,17 @@ func (s *OpenVpnMgt) Version() (error, map[int][]string) {
|
||||
// main loop for a given openvpn server
|
||||
func (s *OpenVpnMgt) handleConn(conn net.Conn) {
|
||||
remote := conn.RemoteAddr().String()
|
||||
pidRegexp := rcache.Get("^SUCCESS: pid=([0-9]+)$")
|
||||
// >REMOTE:vpn.example.com,1194,udp
|
||||
remoteRegexp := rcache.Get("^>REMOTE:(.*),([0-9]*),(.*)$")
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
vpnServer := NewOpenVpnSrv(conn)
|
||||
openvpn := NewOpenVpnSrv(conn, s)
|
||||
defer s.Remove(openvpn)
|
||||
|
||||
// most response are multilined, use response to concatenate them
|
||||
response := []string{}
|
||||
|
||||
// remove bogus clients
|
||||
line, err := vpnServer.session.GetLine()
|
||||
line, err := openvpn.GetLine()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
@@ -137,24 +184,27 @@ func (s *OpenVpnMgt) handleConn(conn net.Conn) {
|
||||
|
||||
log.Printf("Valid openvpn connected from %s\n", remote)
|
||||
|
||||
go session.sendCommand([]string{"pid"})
|
||||
go openvpn.GetEcho()
|
||||
go openvpn.GetPid()
|
||||
s.Change()
|
||||
defer s.Change()
|
||||
|
||||
for {
|
||||
line, err := session.GetLine()
|
||||
line, err := openvpn.GetLine()
|
||||
|
||||
// manage basic errors
|
||||
switch {
|
||||
case err == io.EOF:
|
||||
log.Println("Reached EOF - close this connection.\n")
|
||||
log.Println("Reached EOF - close this connection")
|
||||
return
|
||||
case err != nil:
|
||||
log.Println("Error reading line. Got: '"+line+"'\n", err)
|
||||
log.Printf("Error reading line. Got: '"+line+"'\n", err)
|
||||
return
|
||||
}
|
||||
line = strings.Trim(line, "\n\r ")
|
||||
|
||||
if s.debug && strings.Index(line, "password") == -1 {
|
||||
log.Print(line)
|
||||
if strings.Index(line, "password") == -1 {
|
||||
s.Debug(line)
|
||||
}
|
||||
|
||||
// manage exit commands
|
||||
@@ -165,22 +215,13 @@ func (s *OpenVpnMgt) handleConn(conn net.Conn) {
|
||||
}
|
||||
}
|
||||
|
||||
// get the PID
|
||||
match := pidRegexp.FindStringSubmatch(line)
|
||||
if len(match) == 2 {
|
||||
pid, _ := strconv.Atoi(match[1])
|
||||
s.Lock()
|
||||
s.vpnServers[pid] = vpnServer
|
||||
s.Unlock()
|
||||
defer delete(s.vpnServers, pid)
|
||||
}
|
||||
|
||||
// manage all "terminator" lines
|
||||
for _, terminator := range []string{"END", ">CLIENT:ENV,END", "SUCCESS", "ERROR"} {
|
||||
if strings.HasPrefix(line, terminator) {
|
||||
vpnServer.Response(response)
|
||||
openvpn.Response(append(response, line))
|
||||
response = nil
|
||||
line = ""
|
||||
s.Change()
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -188,11 +229,10 @@ func (s *OpenVpnMgt) handleConn(conn net.Conn) {
|
||||
remoteMatch := remoteRegexp.FindStringSubmatch(line)
|
||||
switch {
|
||||
// command successfull, we can ignore
|
||||
case strings.HasPrefix(line, ">SUCCESS: client-deny command succeeded"):
|
||||
case strings.HasPrefix(line, ">HOLD"):
|
||||
go vpnServer.waitForRelase()
|
||||
go openvpn.waitForRelase()
|
||||
case len(remoteMatch) > 0:
|
||||
go vpnServer.ValidRemote(remoteMatch[1], remoteMatch[2], remoteMatch[3])
|
||||
go openvpn.ValidRemote(remoteMatch[1], remoteMatch[2], remoteMatch[3])
|
||||
default:
|
||||
response = append(response, line)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user