X-Git-Url: http://www.git.cypherpunks.ru/?a=blobdiff_plain;f=src%2Fcypherpunks.ru%2Fgovpn%2Fcommon.go;h=72873d05f17e716f4064315979dcf7b6ce475727;hb=3fdd922de75e1901e37f75ab182d434f20d64c85;hp=56b0f696527231738a49f1eae7f15988327f76fa;hpb=c259296effa4a44103dcac563c6f7e30e436bb34;p=govpn.git diff --git a/src/cypherpunks.ru/govpn/common.go b/src/cypherpunks.ru/govpn/common.go index 56b0f69..72873d0 100644 --- a/src/cypherpunks.ru/govpn/common.go +++ b/src/cypherpunks.ru/govpn/common.go @@ -19,57 +19,168 @@ along with this program. If not, see . 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 + // 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 + MTUMax = 9000 + etherSize + 1 // MTUDefault is default MTU size of Ethernet packet - MTUDefault = 1500 + EtherSize + 1 + MTUDefault = 1500 + etherSize + 1 - ENV_IFACE = "GOVPN_IFACE" - ENV_REMOTE = "GOVPN_REMOTE" + environmentKeyInterface = "GOVPN_IFACE" + environmentKeyRemote = "GOVPN_REMOTE" + + wrapIoReadFull = "io.ReadFull %q" + wrapBlake2bNew256 = "blake2b.New256" + wrapEnclessDecode = "EnclessDecode" + wrapEnclessEncode = "EnclessEncode" + wrapNewProtocolFromString = "NewProtocolFromString" ) var ( // Version holds release string set at build time - Version string + 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 ) -// ScriptCall calls 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, remoteAddr 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), + ) + } + proto, err := NewProtocolFromString(str) + if err != nil { + return errors.Wrap(err, wrapNewProtocolFromString) } - if _, err := os.Stat(path); err != nil && os.IsNotExist(err) { - return nil, err + *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 { + return errors.Wrap(err, "unmarshall") } - cmd := exec.Command(path) - cmd.Env = append(cmd.Env, ENV_IFACE+"="+ifaceName) - cmd.Env = append(cmd.Env, ENV_REMOTE+"="+remoteAddr) - out, err := cmd.CombinedOutput() + + proto, err := NewProtocolFromString(str) if err != nil { - log.Println("Script error", path, err, string(out)) + return errors.Wrap(err, wrapNewProtocolFromString) + } + *p = proto + return nil +} + +// NewProtocolFromString converts a string into a govpn.Protocol +func NewProtocolFromString(p string) (Protocol, error) { + var k Protocol + var v string + lowP := strings.ToLower(p) + for k, v = range protocolText { + if strings.ToLower(v) == lowP { + return k, nil + } } - return out, err + + choices := make([]string, len(protocolText)) + var index = 0 + for k = range protocolText { + choices[index] = protocolText[k] + 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 returns version of GoVPN func VersionGet() string { return "GoVPN version " + Version + " built with " + runtime.Version() } + +// CatchSignalShutdown returns 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("Can't close connection") + } +}