/*
GoVPN -- simple secure free software virtual private network daemon
-Copyright (C) 2014-2016 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2014-2017 Sergey Matveev <stargrave@stargrave.org>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
import (
"flag"
"fmt"
- "log"
- "net"
- "os"
- "os/signal"
- "time"
+
+ "github.com/Sirupsen/logrus"
"cypherpunks.ru/govpn"
+ "cypherpunks.ru/govpn/server"
)
var (
proxy = flag.String("proxy", "", "Enable HTTP proxy on host:port")
egdPath = flag.String("egd", "", "Optional path to EGD socket")
syslog = flag.Bool("syslog", false, "Enable logging to syslog")
+ version = flag.Bool("version", false, "Print version information")
warranty = flag.Bool("warranty", false, "Print warranty information")
+ logLevel = flag.String("loglevel", "warning", "Logging level")
)
func main() {
+ var err error
+ fields := logrus.Fields{"func": "main"}
+
flag.Parse()
if *warranty {
fmt.Println(govpn.Warranty)
return
}
- timeout := time.Second * time.Duration(govpn.TimeoutDefault)
- log.SetFlags(log.Ldate | log.Lmicroseconds | log.Lshortfile)
- log.Println(govpn.VersionGet())
+ if *version {
+ fmt.Println(govpn.VersionGet())
+ return
+ }
- confInit()
- knownPeers = govpn.KnownPeers(make(map[string]**govpn.Peer))
+ logger, err = govpn.NewLogger(*logLevel, *syslog)
+ if err != nil {
+ logrus.WithFields(
+ fields,
+ ).WithError(err).Fatal("Can not initialize logging")
+ }
+ govpn.SetLogger(logger)
if *egdPath != "" {
- log.Println("Using", *egdPath, "EGD")
+ logger.WithField(
+ "egd_path", *egdPath,
+ ).WithFields(
+ fields,
+ ).Debug("Init EGD")
govpn.EGDInit(*egdPath)
}
- switch *proto {
- case "udp":
- startUDP()
- case "tcp":
- startTCP()
- case "all":
- startUDP()
- startTCP()
- default:
- log.Fatalln("Unknown protocol specified")
- }
+ confInit()
- termSignal := make(chan os.Signal, 1)
- signal.Notify(termSignal, os.Interrupt, os.Kill)
+ serverConfig := server.Configuration{
+ BindAddress: *bindAddr,
+ ProxyAddress: *proxy,
+ Timeout: govpn.TimeoutDefault,
+ }
+ if serverConfig.Protocol, err = govpn.NewProtocolFromString(*proto); err != nil {
+ logger.WithError(err).WithFields(
+ fields,
+ ).WithField(
+ "proto", *proto,
+ ).Fatal("Invalid protocol")
+ }
+ if err = serverConfig.Validate(); err != nil {
+ logger.WithError(err).WithFields(fields).Fatal("Invalid configuration")
+ }
- hsHeartbeat := time.Tick(timeout)
- go func() { <-hsHeartbeat }()
+ srv := server.NewServer(
+ serverConfig,
+ confs,
+ idsCache,
+ logger,
+ govpn.CatchSignalShutdown(),
+ )
if *stats != "" {
- log.Println("Stats are going to listen on", *stats)
- statsPort, err := net.Listen("tcp", *stats)
- if err != nil {
- log.Fatalln("Can not listen on stats port:", err)
- }
- go govpn.StatsProcessor(statsPort, &knownPeers)
- }
- if *proxy != "" {
- go proxyStart()
+ go govpn.StatsProcessor(*stats, srv.KnownPeers())
}
- if *syslog {
- govpn.SyslogEnable()
- }
- log.Println("Server started")
- govpn.Println("Server started")
-
- var needsDeletion bool
-MainCycle:
- for {
- select {
- case <-termSignal:
- log.Println("Terminating")
- govpn.Println("Terminating")
- for _, ps := range peers {
- govpn.ScriptCall(
- confs[*ps.peer.Id].Down,
- ps.tap.Name,
- ps.peer.Addr,
- )
- }
- break MainCycle
- case <-hsHeartbeat:
- now := time.Now()
- hsLock.Lock()
- for addr, hs := range handshakes {
- if hs.LastPing.Add(timeout).Before(now) {
- govpn.Println("Deleting handshake state", addr)
- hs.Zero()
- delete(handshakes, addr)
- }
- }
- peersLock.Lock()
- peersByIdLock.Lock()
- kpLock.Lock()
- for addr, ps := range peers {
- ps.peer.BusyR.Lock()
- needsDeletion = ps.peer.LastPing.Add(timeout).Before(now)
- ps.peer.BusyR.Unlock()
- if needsDeletion {
- govpn.Println("Deleting peer", ps.peer)
- delete(peers, addr)
- delete(knownPeers, addr)
- delete(peersById, *ps.peer.Id)
- go govpn.ScriptCall(
- confs[*ps.peer.Id].Down,
- ps.tap.Name,
- ps.peer.Addr,
- )
- ps.terminator <- struct{}{}
- }
- }
- hsLock.Unlock()
- peersLock.Unlock()
- peersByIdLock.Unlock()
- kpLock.Unlock()
- }
+ go srv.MainCycle()
+ if err = <-srv.Error; err != nil {
+ logger.WithError(err).Fatal("Fatal error")
}
}