/*
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
package govpn
import (
- "log"
+ "encoding/hex"
+ "encoding/json"
+ "io"
"os"
- "os/exec"
+ "os/signal"
"runtime"
+ "strings"
+ "time"
+
+ "github.com/Sirupsen/logrus"
+ "github.com/pkg/errors"
)
const (
- TimeoutDefault = 60
- EtherSize = 14
- MTUMax = 9000 + EtherSize + 1
- MTUDefault = 1500 + EtherSize + 1
+ // ProtocolUDP is UDP transport protocol
+ ProtocolUDP Protocol = iota
+ // ProtocolTCP is TCP transport protocol
+ ProtocolTCP
+ // ProtocolALL is TCP+UDP transport protocol
+ ProtocolALL
+
+ etherSize = 14
+ // MTUMax is maximum MTU size of Ethernet packet
+ MTUMax = 9000 + etherSize + 1
+ // MTUDefault is default MTU size of Ethernet packet
+ MTUDefault = 1500 + etherSize + 1
+
+ environmentKeyInterface = "GOVPN_IFACE"
+ environmentKeyRemote = "GOVPN_REMOTE"
+
+ wrapIoReadFull = "io.ReadFull %q"
+ wrapBlake2bNew256 = "blake2b.New256"
+ wrapEnclessDecode = "EnclessDecode"
+ wrapEnclessEncode = "EnclessEncode"
+ wrapNewProtocolFromString = "NewProtocolFromString"
)
var (
- Version string
+ // Version holds release string set at build time
+ Version string
+ protocolText = map[Protocol]string{
+ ProtocolUDP: "udp",
+ ProtocolTCP: "tcp",
+ ProtocolALL: "all",
+ }
+ logger = logrus.StandardLogger()
+ logFuncPrefix = "govpn."
+ // TimeoutDefault is default timeout value for various network operations
+ TimeoutDefault = 60 * time.Second
)
-// Call external program/script.
-// You have to specify path to it and (inteface name as a rule) something
-// that will be the first argument when calling it. Function will return
-// it's output and possible error.
-func ScriptCall(path, ifaceName string) ([]byte, error) {
- if path == "" {
- return nil, nil
+// Protocol is a GoVPN supported protocol: either UDP, TCP or both
+type Protocol int
+
+// String converts a Protocol into a string
+func (p Protocol) String() string {
+ return protocolText[p]
+}
+
+// MarshalJSON returns a JSON string from a protocol
+func (p Protocol) MarshalJSON() ([]byte, error) {
+ str := p.String()
+ output, err := json.Marshal(&str)
+ return output, errors.Wrap(err, "json.Marshal")
+}
+
+// UnmarshalJSON converts a JSON string into a Protocol
+func (p *Protocol) UnmarshalJSON(encoded []byte) error {
+ var str string
+ if err := json.Unmarshal(encoded, &str); err != nil {
+ return errors.Wrapf(err, "Can't unmarshall to string %q", hex.EncodeToString(encoded))
}
- if _, err := os.Stat(path); err != nil && os.IsNotExist(err) {
- return nil, err
+ proto, err := NewProtocolFromString(str)
+ if err != nil {
+ return errors.Wrap(err, wrapNewProtocolFromString)
}
- out, err := exec.Command(path, ifaceName).CombinedOutput()
+ *p = proto
+ return nil
+}
+
+// UnmarshalYAML converts a YAML string into a Protocol
+func (p *Protocol) UnmarshalYAML(unmarshal func(interface{}) error) error {
+ var str string
+ err := unmarshal(&str)
if err != nil {
- log.Println("Script error", path, err, string(out))
+ return errors.Wrap(err, "unmarshall")
}
- return out, err
+
+ proto, err := NewProtocolFromString(str)
+ if err != nil {
+ return errors.Wrap(err, wrapNewProtocolFromString)
+ }
+ *p = proto
+ return nil
+}
+
+// NewProtocolFromString converts a string into a govpn.Protocol
+func NewProtocolFromString(p string) (Protocol, error) {
+ lowP := strings.ToLower(p)
+ for k, v := range protocolText {
+ if strings.ToLower(v) == lowP {
+ return k, nil
+ }
+ }
+
+ choices := make([]string, len(protocolText))
+ var index = 0
+ for k, v := range protocolText {
+ if v == p {
+ z := k
+ p = &z
+ return nil
+ }
+ choices[index] = v
+ index++
+ }
+
+ return Protocol(-1), errors.Errorf("Invalid protocol %q: %s", p, strings.Join(choices, ","))
}
-// Zero each byte.
+// SliceZero zeros each byte.
func SliceZero(data []byte) {
for i := 0; i < len(data); i++ {
data[i] = 0
}
}
+// VersionGet return version of GoVPN
func VersionGet() string {
return "GoVPN version " + Version + " built with " + runtime.Version()
}
+
+// CatchSignalShutdown return a channel.
+// that channel will get a SIG_INT or SIG_KILL signal is received
+// this is intended to be used to stop a client/server
+func CatchSignalShutdown() chan interface{} {
+ shutdownChan := make(chan interface{}, 1)
+ go func() {
+ termSignal := make(chan os.Signal, 1)
+ signal.Notify(termSignal, os.Interrupt, os.Kill)
+ sig := <-termSignal
+ logger.WithFields(logrus.Fields{
+ "func": logFuncPrefix + "CatchSignalShutdown",
+ "signal": sig.String(),
+ }).Debug("Catch signal, shutting down")
+ shutdownChan <- sig
+ }()
+ return shutdownChan
+}
+
+// SetLogger set the Logger used by this library.
+// by default logrus StdLogger is used.
+func SetLogger(l *logrus.Logger) {
+ logger = l
+}
+
+// CloseLog log an error if a io.Closer fail to Close
+func CloseLog(c io.Closer, l *logrus.Logger, fields logrus.Fields) {
+ if err := c.Close(); err != nil {
+ logrus.WithFields(fields).WithError(err).Error("Couldn't close connection")
+ }
+}