update
This commit is contained in:
162
vpnserver.go
162
vpnserver.go
@@ -1,12 +1,12 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
@@ -15,37 +15,50 @@ import (
|
||||
|
||||
// Server represents the server
|
||||
type OpenVpnMgt struct {
|
||||
port string
|
||||
buf map[string]*bufio.ReadWriter
|
||||
m sync.RWMutex
|
||||
ret chan []string
|
||||
syslog bool
|
||||
debug bool
|
||||
hold bool
|
||||
port string
|
||||
m sync.RWMutex
|
||||
debug bool
|
||||
VpnRemotes []string `json:"remotes"`
|
||||
vpnServers map[int]*OpenVpnSrv `json:"sessions"`
|
||||
}
|
||||
|
||||
// NewServer returns a pointer to a new server
|
||||
func NewVPNServer(port string) *OpenVpnMgt {
|
||||
func NewVPNServer(port string, debug bool) *OpenVpnMgt {
|
||||
return &OpenVpnMgt{
|
||||
port: port,
|
||||
ret: make(chan []string),
|
||||
buf: make(map[string]*bufio.ReadWriter),
|
||||
port: port,
|
||||
debug: debug,
|
||||
vpnServers: make(map[int]*OpenVpnSrv),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *OpenVpnMgt) Lock() {
|
||||
s.m.Lock()
|
||||
}
|
||||
|
||||
func (s *OpenVpnMgt) Unlock() {
|
||||
s.m.Unlock()
|
||||
}
|
||||
|
||||
// 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 {
|
||||
log.Println(err)
|
||||
os.Exit(1)
|
||||
return
|
||||
}
|
||||
// start listening to client connections
|
||||
listener, err := net.ListenTCP("tcp", addrs)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
os.Exit(1)
|
||||
return
|
||||
}
|
||||
// Infinite loop since we dont want the server to shut down
|
||||
for {
|
||||
@@ -60,86 +73,59 @@ func (s *OpenVpnMgt) Run() {
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
func (s *OpenVpnMgt) GetSession(remote int) (error, *OpenVpnSrv) {
|
||||
if vpnServer, ok := s.vpnServers[remote]; ok {
|
||||
return nil, vpnServer
|
||||
}
|
||||
for _, line := range msg {
|
||||
if s.debug {
|
||||
log.Println(line)
|
||||
}
|
||||
if _, err := s.buf[remote].WriteString(line + "\r\n"); err != nil {
|
||||
return err, nil
|
||||
}
|
||||
}
|
||||
|
||||
if err := s.buf[remote].Flush(); err != nil {
|
||||
return err, nil
|
||||
}
|
||||
|
||||
// wait for the response
|
||||
ret := <-s.ret
|
||||
|
||||
if s.debug {
|
||||
for _, line := range ret {
|
||||
log.Println(line)
|
||||
}
|
||||
}
|
||||
|
||||
return nil, ret
|
||||
return errors.New(fmt.Sprintf("unknown session %d", vpnServers)), nil
|
||||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return err, ret
|
||||
}
|
||||
for _, line := range msg {
|
||||
match := re.FindStringSubmatch(line)
|
||||
if len(match) == 0 {
|
||||
continue
|
||||
}
|
||||
help[match[1]] = match[2]
|
||||
}
|
||||
ret[remote] = help
|
||||
func (s *OpenVpnMgt) SetRemote(server string, remote int) error {
|
||||
// check if the session is valid
|
||||
err, session := s.GetSession(remote)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil, ret
|
||||
|
||||
for _, r := range s.VpnRemotes {
|
||||
if r != server {
|
||||
continue
|
||||
}
|
||||
return session.SetRemote(server)
|
||||
}
|
||||
|
||||
return errors.New(fmt.Sprintf("unknown remote %s", server))
|
||||
}
|
||||
|
||||
// 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
|
||||
func (s *OpenVpnMgt) Version() (error, map[int][]string) {
|
||||
var err error
|
||||
ret := make(map[int][]string)
|
||||
for remote, srv := range s.vpnServers {
|
||||
err, msg := srv.Version()
|
||||
if err == nil {
|
||||
ret[remote] = msg
|
||||
}
|
||||
ret[remote] = msg
|
||||
}
|
||||
return nil, ret
|
||||
return err, ret
|
||||
}
|
||||
|
||||
// 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()
|
||||
defer delete(s.buf, remote)
|
||||
|
||||
// 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))
|
||||
vpnServer := NewOpenVpnSrv(conn)
|
||||
|
||||
// most response are multilined, use response to concatenate them
|
||||
response := []string{}
|
||||
|
||||
// remove bogus clients
|
||||
line, err := s.buf[remote].ReadString('\n')
|
||||
line, err := vpnServer.session.GetLine()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
@@ -151,8 +137,10 @@ func (s *OpenVpnMgt) handleConn(conn net.Conn) {
|
||||
|
||||
log.Printf("Valid openvpn connected from %s\n", remote)
|
||||
|
||||
go session.sendCommand([]string{"pid"})
|
||||
|
||||
for {
|
||||
line, err := s.buf[remote].ReadString('\n')
|
||||
line, err := session.GetLine()
|
||||
|
||||
// manage basic errors
|
||||
switch {
|
||||
@@ -165,6 +153,10 @@ func (s *OpenVpnMgt) handleConn(conn net.Conn) {
|
||||
}
|
||||
line = strings.Trim(line, "\n\r ")
|
||||
|
||||
if s.debug && strings.Index(line, "password") == -1 {
|
||||
log.Print(line)
|
||||
}
|
||||
|
||||
// manage exit commands
|
||||
for _, terminator := range []string{"quit", "exit"} {
|
||||
if line == terminator || strings.HasPrefix(line, terminator+" ") {
|
||||
@@ -173,28 +165,36 @@ 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) {
|
||||
s.ret <- response
|
||||
vpnServer.Response(response)
|
||||
response = nil
|
||||
line = ""
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
remoteMatch := remoteRegexp.FindStringSubmatch(line)
|
||||
switch {
|
||||
// command successfull, we can ignore
|
||||
case strings.HasPrefix(line, ">SUCCESS: client-deny command succeeded"):
|
||||
case strings.HasPrefix(line, ">HOLD"):
|
||||
s.sendCommand([]string{"hold release"}, remote)
|
||||
case strings.HasPrefix(line, ">REMOTE"):
|
||||
s.sendCommand([]string{"remote ACCEPT"}, remote)
|
||||
go vpnServer.waitForRelase()
|
||||
case len(remoteMatch) > 0:
|
||||
go vpnServer.ValidRemote(remoteMatch[1], remoteMatch[2], remoteMatch[3])
|
||||
default:
|
||||
response = append(response, line)
|
||||
}
|
||||
if s.debug && strings.Index(line, "password") == -1 {
|
||||
log.Print(line)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user