diff options
Diffstat (limited to 'vendor/github.com/apparentlymart')
8 files changed, 0 insertions, 1424 deletions
diff --git a/vendor/github.com/apparentlymart/go-openvpn-mgmt/demux/demuxer.go b/vendor/github.com/apparentlymart/go-openvpn-mgmt/demux/demuxer.go deleted file mode 100644 index c57964e..0000000 --- a/vendor/github.com/apparentlymart/go-openvpn-mgmt/demux/demuxer.go +++ /dev/null @@ -1,63 +0,0 @@ -package demux - -import ( - "bufio" - "io" -) - -var readErrSynthEvent = []byte("FATAL:Error reading from OpenVPN") - -// Demultiplex reads from the given io.Reader, assumed to be the client -// end of an OpenVPN Management Protocol connection, and splits it into -// distinct messages from OpenVPN. -// -// It then writes the raw message buffers into either replyCh or eventCh -// depending on whether each message is a reply to a client command or -// an asynchronous event notification. -// -// The buffers written to replyCh are entire raw message lines (without the -// trailing newlines), while the buffers written to eventCh are the raw -// event strings with the prototcol's leading '>' indicator omitted. -// -// The caller should usually provide buffered channels of sufficient buffer -// depth so that the reply channel will not be starved by slow event -// processing. -// -// Once the io.Reader signals EOF, eventCh will be closed, then replyCh -// will be closed, and then this function will return. -// -// As a special case, if a non-EOF error occurs while reading from the -// io.Reader then a synthetic "FATAL" event will be written to eventCh -// before the two buffers are closed and the function returns. This -// synthetic message will have the error message "Error reading from OpenVPN". -func Demultiplex(r io.Reader, replyCh, eventCh chan<- []byte) { - scanner := bufio.NewScanner(r) - for scanner.Scan() { - buf := scanner.Bytes() - - if len(buf) < 1 { - // Should never happen but we'll be robust and ignore this, - // rather than crashing below. - continue - } - - // Asynchronous messages always start with > to differentiate - // them from replies. - if buf[0] == '>' { - // Trim off the > when we post the message, since it's - // redundant after we've demuxed. - eventCh <- buf[1:] - } else { - replyCh <- buf - } - } - - if err := scanner.Err(); err != nil { - // Generate a synthetic FATAL event so that the caller can - // see that the connection was not gracefully closed. - eventCh <- readErrSynthEvent - } - - close(eventCh) - close(replyCh) -} diff --git a/vendor/github.com/apparentlymart/go-openvpn-mgmt/demux/demuxer_test.go b/vendor/github.com/apparentlymart/go-openvpn-mgmt/demux/demuxer_test.go deleted file mode 100644 index 45edac6..0000000 --- a/vendor/github.com/apparentlymart/go-openvpn-mgmt/demux/demuxer_test.go +++ /dev/null @@ -1,218 +0,0 @@ -package demux - -import ( - "bytes" - "fmt" - "io" - "reflect" - "testing" -) - -func TestDemultiplex(t *testing.T) { - type TestCase struct { - Input []string - ExpectedReplies []string - ExpectedEvents []string - } - - testCases := []TestCase{ - { - Input: []string{}, - ExpectedReplies: []string{}, - ExpectedEvents: []string{}, - }, - { - Input: []string{ - "SUCCESS: foo bar baz", - }, - ExpectedReplies: []string{ - "SUCCESS: foo bar baz", - }, - ExpectedEvents: []string{}, - }, - { - Input: []string{ - ">STATE:1234,ASSIGN_IP,,10.0.0.1,", - }, - ExpectedReplies: []string{}, - ExpectedEvents: []string{ - "STATE:1234,ASSIGN_IP,,10.0.0.1,", - }, - }, - { - Input: []string{ - ">STATE:1234,ASSIGN_IP,,10.0.0.1,", - ">STATE:5678,ASSIGN_IP,,10.0.0.1,", - ">STATE:9012,ASSIGN_IP,,10.0.0.1,", - }, - ExpectedReplies: []string{}, - ExpectedEvents: []string{ - "STATE:1234,ASSIGN_IP,,10.0.0.1,", - "STATE:5678,ASSIGN_IP,,10.0.0.1,", - "STATE:9012,ASSIGN_IP,,10.0.0.1,", - }, - }, - { - Input: []string{ - ">STATE:1234,ASSIGN_IP,,10.0.0.1,", - "SUCCESS: foo bar baz", - ">STATE:5678,ASSIGN_IP,,10.0.0.1,", - }, - ExpectedReplies: []string{ - "SUCCESS: foo bar baz", - }, - ExpectedEvents: []string{ - "STATE:1234,ASSIGN_IP,,10.0.0.1,", - "STATE:5678,ASSIGN_IP,,10.0.0.1,", - }, - }, - { - Input: []string{ - "SUCCESS: foo bar baz", - ">STATE:1234,ASSIGN_IP,,10.0.0.1,", - "SUCCESS: baz bar foo", - }, - ExpectedReplies: []string{ - "SUCCESS: foo bar baz", - "SUCCESS: baz bar foo", - }, - ExpectedEvents: []string{ - "STATE:1234,ASSIGN_IP,,10.0.0.1,", - }, - }, - } - - for i, testCase := range testCases { - r := mockReader(testCase.Input) - gotReplies, gotEvents := captureMsgs(r) - - if !reflect.DeepEqual(gotReplies, testCase.ExpectedReplies) { - t.Errorf( - "test %d returned incorrect replies\ngot %#v\nwant %#v", - i, gotReplies, testCase.ExpectedReplies, - ) - } - - if !reflect.DeepEqual(gotEvents, testCase.ExpectedEvents) { - t.Errorf( - "test %d returned incorrect events\ngot %#v\nwant %#v", - i, gotEvents, testCase.ExpectedEvents, - ) - } - } -} - -func TestDemultiplex_error(t *testing.T) { - r := &alwaysErroringReader{} - - gotReplies, gotEvents := captureMsgs(r) - - expectedReplies := []string{} - expectedEvents := []string{ - "FATAL:Error reading from OpenVPN", - } - - if !reflect.DeepEqual(gotReplies, expectedReplies) { - t.Errorf( - "incorrect replies\ngot %#v\nwant %#v", - gotReplies, expectedReplies, - ) - } - - if !reflect.DeepEqual(gotEvents, expectedEvents) { - t.Errorf( - "incorrect events\ngot %#v\nwant %#v", - gotEvents, expectedEvents, - ) - } -} - -func mockReader(msgs []string) io.Reader { - var buf []byte - for _, msg := range msgs { - buf = append(buf, []byte(msg)...) - buf = append(buf, '\n') - } - return bytes.NewReader(buf) -} - -func captureMsgs(r io.Reader) (replies, events []string) { - replyCh := make(chan []byte) - eventCh := make(chan []byte) - - replies = make([]string, 0) - events = make([]string, 0) - - go Demultiplex(r, replyCh, eventCh) - - for replyCh != nil || eventCh != nil { - select { - - case msg, ok := <-replyCh: - if ok { - replies = append(replies, string(msg)) - } else { - replyCh = nil - } - - case msg, ok := <-eventCh: - if ok { - events = append(events, string(msg)) - } else { - eventCh = nil - } - - } - - } - - return replies, events -} - -type alwaysErroringReader struct{} - -func (r *alwaysErroringReader) Read(buf []byte) (int, error) { - return 0, fmt.Errorf("mock error") -} - -// Somewhat-contrived example of blocking for a reply while concurrently -// processing asynchronous events. -func ExampleDemultiplex() { - // In a real caller we would have a net.IPConn as our reader, - // but we'll use a bytes reader here as a test. - r := bytes.NewReader([]byte( - // A reply to a hypothetical command interspersed between - // two asynchronous events. - ">HOLD:Waiting for hold release\nSUCCESS: foo\n>FATAL:baz\n", - )) - - // No strong need for buffering on this channel because usually - // a message sender will immediately block waiting for the - // associated response message. - replyCh := make(chan []byte) - - // Make sure the event channel buffer is deep enough that slow event - // processing won't significantly delay synchronous replies. If you - // process events quickly, or if you aren't sending any commands - // concurrently with acting on events, then this is not so important. - eventCh := make(chan []byte, 10) - - // Start demultiplexing the message stream in the background. - // This goroutine will exit once the reader signals EOF. - go Demultiplex(r, replyCh, eventCh) - - // Some coroutine has sent a hypothetical message to OpenVPN, - // and it can directly block until the associated reply arrives. - // The events will be concurrently handled by our event loop - // below while we wait for the reply to show up. - go func() { - replyMsgBuf := <-replyCh - fmt.Printf("Command reply: %s\n", string(replyMsgBuf)) - }() - - // Main event loop deals with the async events as they arrive, - // independently of any commands that are pending. - for msgBuf := range eventCh { - fmt.Printf("Event: %s\n", string(msgBuf)) - } -} diff --git a/vendor/github.com/apparentlymart/go-openvpn-mgmt/demux/doc.go b/vendor/github.com/apparentlymart/go-openvpn-mgmt/demux/doc.go deleted file mode 100644 index 263a267..0000000 --- a/vendor/github.com/apparentlymart/go-openvpn-mgmt/demux/doc.go +++ /dev/null @@ -1,12 +0,0 @@ -// Package demux implements low-level demultiplexing of the stream of -// messages sent from OpenVPN on the management channel. -// -// OpenVPN's protocol includes two different kinds of message from the OpenVPN -// process: replies to commands sent by the management client, and asynchronous -// event notifications. -// -// This package's purpose is to split these messages into two separate streams, -// so that functions executing command/response sequences can just block -// on the reply channel while an event loop elsewhere deals with any async -// events that might show up. -package demux diff --git a/vendor/github.com/apparentlymart/go-openvpn-mgmt/openvpn/client.go b/vendor/github.com/apparentlymart/go-openvpn-mgmt/openvpn/client.go deleted file mode 100644 index 7768004..0000000 --- a/vendor/github.com/apparentlymart/go-openvpn-mgmt/openvpn/client.go +++ /dev/null @@ -1,303 +0,0 @@ -package openvpn - -import ( - "bytes" - "fmt" - "io" - "net" - "strconv" - "time" - - "github.com/apparentlymart/go-openvpn-mgmt/demux" -) - -var newline = []byte{'\n'} -var successPrefix = []byte("SUCCESS: ") -var errorPrefix = []byte("ERROR: ") -var endMessage = []byte("END") - -type MgmtClient struct { - wr io.Writer - replies <-chan []byte -} - -// NewClient creates a new MgmtClient that communicates via the given -// io.ReadWriter and emits events on the given channel. -// -// eventCh should be a buffered channel with a sufficient buffer depth -// such that it cannot be filled under the expected event volume. Event -// volume depends on which events are enabled and how they are configured; -// some of the event-enabling functions have further discussion how frequently -// events are likely to be emitted, but the caller should also factor in -// how long its own event *processing* will take, since slow event -// processing will create back-pressure that could cause this buffer to -// fill faster. -// -// It probably goes without saying given the previous paragraph, but the -// caller *must* constantly read events from eventCh to avoid its buffer -// becoming full. Events and replies are received on the same channel -// from OpenVPN, so if writing to eventCh blocks then this will also block -// responses from the client's various command methods. -// -// eventCh will be closed to signal the closing of the client connection, -// whether due to graceful shutdown or to an error. In the case of error, -// a FatalEvent will be emitted on the channel as the last event before it -// is closed. Connection errors may also concurrently surface as error -// responses from the client's various command methods, should an error -// occur while we await a reply. -func NewClient(conn io.ReadWriter, eventCh chan<- Event) *MgmtClient { - replyCh := make(chan []byte) - rawEventCh := make(chan []byte) // not buffered because eventCh should be - - go demux.Demultiplex(conn, replyCh, rawEventCh) - - // Get raw events and upgrade them into proper event types before - // passing them on to the caller's event channel. - go func() { - for raw := range rawEventCh { - eventCh <- upgradeEvent(raw) - } - close(eventCh) - }() - - return &MgmtClient{ - // replyCh acts as the reader for our ReadWriter, so we only - // need to retain the io.Writer for it, so we can send commands. - wr: conn, - replies: replyCh, - } -} - -// Dial is a convenience wrapper around NewClient that handles the common -// case of opening an TCP/IP socket to an OpenVPN management port and creating -// a client for it. -// -// See the NewClient docs for discussion about the requirements for eventCh. -// -// OpenVPN will create a suitable management port if launched with the -// following command line option: -// -// --management <ipaddr> <port> -// -// Address may an IPv4 address, an IPv6 address, or a hostname that resolves -// to either of these, followed by a colon and then a port number. -// -// When running on Unix systems it's possible to instead connect to a Unix -// domain socket. To do this, pass an absolute path to the socket as -// the target address, having run OpenVPN with the following options: -// -// --management /path/to/socket unix -// -func Dial(addr string, eventCh chan<- Event) (*MgmtClient, error) { - proto := "tcp" - if len(addr) > 0 && addr[0] == '/' { - proto = "unix" - } - conn, err := net.Dial(proto, addr) - if err != nil { - return nil, err - } - - return NewClient(conn, eventCh), nil -} - -// HoldRelease instructs OpenVPN to release any management hold preventing -// it from proceeding, but to retain the state of the hold flag such that -// the daemon will hold again if it needs to reconnect for any reason. -// -// OpenVPN can be instructed to activate a management hold on startup by -// running it with the following option: -// -// --management-hold -// -// Instructing OpenVPN to hold gives your client a chance to connect and -// do any necessary configuration before a connection proceeds, thus avoiding -// the problem of missed events. -// -// When OpenVPN begins holding, or when a new management client connects while -// a hold is already in effect, a HoldEvent will be emitted on the event -// channel. -func (c *MgmtClient) HoldRelease() error { - _, err := c.simpleCommand("hold release") - return err -} - -// SetStateEvents either enables or disables asynchronous events for changes -// in the OpenVPN connection state. -// -// When enabled, a StateEvent will be emitted from the event channel each -// time the connection state changes. See StateEvent for more information -// on the event structure. -func (c *MgmtClient) SetStateEvents(on bool) error { - var err error - if on { - _, err = c.simpleCommand("state on") - } else { - _, err = c.simpleCommand("state off") - } - return err -} - -// SetEchoEvents either enables or disables asynchronous events for "echo" -// commands sent from a remote server to our managed OpenVPN client. -// -// When enabled, an EchoEvent will be emitted from the event channel each -// time the server sends an echo command. See EchoEvent for more information. -func (c *MgmtClient) SetEchoEvents(on bool) error { - var err error - if on { - _, err = c.simpleCommand("echo on") - } else { - _, err = c.simpleCommand("echo off") - } - return err -} - -// SetByteCountEvents either enables or disables ongoing asynchronous events -// for information on OpenVPN bandwidth usage. -// -// When enabled, a ByteCountEvent will be emitted at given time interval, -// (which may only be whole seconds) describing how many bytes have been -// transferred in each direction See ByteCountEvent for more information. -// -// Set the time interval to zero in order to disable byte count events. -func (c *MgmtClient) SetByteCountEvents(interval time.Duration) error { - msg := fmt.Sprintf("bytecount %d", int(interval.Seconds())) - _, err := c.simpleCommand(msg) - return err -} - -// SendSignal sends a signal to the OpenVPN process via the management -// channel. In effect this causes the OpenVPN process to send a signal to -// itself on our behalf. -// -// OpenVPN accepts a subset of the usual UNIX signal names, including -// "SIGHUP", "SIGTERM", "SIGUSR1" and "SIGUSR2". See the OpenVPN manual -// page for the meaning of each. -// -// Behavior is undefined if the given signal name is not entirely uppercase -// letters. In particular, including newlines in the string is likely to -// cause very unpredictable behavior. -func (c *MgmtClient) SendSignal(name string) error { - msg := fmt.Sprintf("signal %q", name) - _, err := c.simpleCommand(msg) - return err -} - -// LatestState retrieves the most recent StateEvent from the server. This -// can either be used to poll the state or it can be used to determine the -// initial state after calling SetStateEvents(true) but before the first -// state event is delivered. -func (c *MgmtClient) LatestState() (*StateEvent, error) { - err := c.sendCommand([]byte("state")) - if err != nil { - return nil, err - } - - payload, err := c.readCommandResponsePayload() - if err != nil { - return nil, err - } - - if len(payload) != 1 { - return nil, fmt.Errorf("Malformed OpenVPN 'state' response") - } - - return &StateEvent{ - body: payload[0], - }, nil -} - -// Pid retrieves the process id of the connected OpenVPN process. -func (c *MgmtClient) Pid() (int, error) { - raw, err := c.simpleCommand("pid") - if err != nil { - return 0, err - } - - if !bytes.HasPrefix(raw, []byte("pid=")) { - return 0, fmt.Errorf("malformed response from OpenVPN") - } - - pid, err := strconv.Atoi(string(raw[4:])) - if err != nil { - return 0, fmt.Errorf("error parsing pid from OpenVPN: %s", err) - } - - return pid, nil -} - -func (c *MgmtClient) sendCommand(cmd []byte) error { - _, err := c.wr.Write(cmd) - if err != nil { - return err - } - _, err = c.wr.Write(newline) - return err -} - -// sendCommandPayload can be called after sendCommand for -// commands that expect a multi-line input payload. -// -// The buffer given in 'payload' *must* end with a newline, -// or else the protocol will be broken. -func (c *MgmtClient) sendCommandPayload(payload []byte) error { - _, err := c.wr.Write(payload) - if err != nil { - return err - } - _, err = c.wr.Write(endMessage) - if err != nil { - return err - } - _, err = c.wr.Write(newline) - return err -} - -func (c *MgmtClient) readCommandResult() ([]byte, error) { - reply, ok := <-c.replies - if !ok { - return nil, fmt.Errorf("connection closed while awaiting result") - } - - if bytes.HasPrefix(reply, successPrefix) { - result := reply[len(successPrefix):] - return result, nil - } - - if bytes.HasPrefix(reply, errorPrefix) { - message := reply[len(errorPrefix):] - return nil, ErrorFromServer(message) - } - - return nil, fmt.Errorf("malformed result message") -} - -func (c *MgmtClient) readCommandResponsePayload() ([][]byte, error) { - lines := make([][]byte, 0, 10) - - for { - line, ok := <-c.replies - if !ok { - // We'll give the caller whatever we got before the connection - // closed, in case it's useful for debugging. - return lines, fmt.Errorf("connection closed before END recieved") - } - - if bytes.Equal(line, endMessage) { - break - } - - lines = append(lines, line) - } - - return lines, nil -} - -func (c *MgmtClient) simpleCommand(cmd string) ([]byte, error) { - err := c.sendCommand([]byte(cmd)) - if err != nil { - return nil, err - } - return c.readCommandResult() -} diff --git a/vendor/github.com/apparentlymart/go-openvpn-mgmt/openvpn/error.go b/vendor/github.com/apparentlymart/go-openvpn-mgmt/openvpn/error.go deleted file mode 100644 index 554e2ef..0000000 --- a/vendor/github.com/apparentlymart/go-openvpn-mgmt/openvpn/error.go +++ /dev/null @@ -1,11 +0,0 @@ -package openvpn - -type ErrorFromServer []byte - -func (err ErrorFromServer) Error() string { - return string(err) -} - -func (err ErrorFromServer) String() string { - return string(err) -} diff --git a/vendor/github.com/apparentlymart/go-openvpn-mgmt/openvpn/event.go b/vendor/github.com/apparentlymart/go-openvpn-mgmt/openvpn/event.go deleted file mode 100644 index 66625f3..0000000 --- a/vendor/github.com/apparentlymart/go-openvpn-mgmt/openvpn/event.go +++ /dev/null @@ -1,299 +0,0 @@ -package openvpn - -import ( - "bytes" - "fmt" - "strconv" -) - -var eventSep = []byte(":") -var fieldSep = []byte(",") -var byteCountEventKW = []byte("BYTECOUNT") -var byteCountCliEventKW = []byte("BYTECOUNT_CLI") -var clientEventKW = []byte("CLIENT") -var echoEventKW = []byte("ECHO") -var fatalEventKW = []byte("FATAL") -var holdEventKW = []byte("HOLD") -var infoEventKW = []byte("INFO") -var logEventKW = []byte("LOG") -var needOkEventKW = []byte("NEED-OK") -var needStrEventKW = []byte("NEED-STR") -var passwordEventKW = []byte("PASSWORD") -var stateEventKW = []byte("STATE") - -type Event interface { - String() string -} - -// UnknownEvent represents an event of a type that this package doesn't -// know about. -// -// Future versions of this library may learn about new event types, so a -// caller should exercise caution when making use of events of this type -// to access unsupported behavior. Backward-compatibility is *not* -// guaranteed for events of this type. -type UnknownEvent struct { - keyword []byte - body []byte -} - -func (e *UnknownEvent) Type() string { - return string(e.keyword) -} - -func (e *UnknownEvent) Body() string { - return string(e.body) -} - -func (e *UnknownEvent) String() string { - return fmt.Sprintf("%s: %s", e.keyword, e.body) -} - -// MalformedEvent represents a message from the OpenVPN process that is -// presented as an event but does not comply with the expected event syntax. -// -// Events of this type should never be seen but robust callers will accept -// and ignore them, possibly generating some kind of debugging message. -// -// One reason for potentially seeing events of this type is when the target -// program is actually not an OpenVPN process at all, but in fact this client -// has been connected to a different sort of server by mistake. -type MalformedEvent struct { - raw []byte -} - -func (e *MalformedEvent) String() string { - return fmt.Sprintf("Malformed Event %q", e.raw) -} - -// HoldEvent is a notification that the OpenVPN process is in a management -// hold and will not continue connecting until the hold is released, e.g. -// by calling client.HoldRelease() -type HoldEvent struct { - body []byte -} - -func (e *HoldEvent) String() string { - return string(e.body) -} - -// StateEvent is a notification of a change of connection state. It can be -// used, for example, to detect if the OpenVPN connection has been interrupted -// and the OpenVPN process is attempting to reconnect. -type StateEvent struct { - body []byte - - // bodyParts is populated only on first request, giving us the - // separate comma-separated elements of the message. Not all - // fields are populated for all states. - bodyParts [][]byte -} - -func (e *StateEvent) RawTimestamp() string { - parts := e.parts() - return string(parts[0]) -} - -func (e *StateEvent) NewState() string { - parts := e.parts() - return string(parts[1]) -} - -func (e *StateEvent) Description() string { - parts := e.parts() - return string(parts[2]) -} - -// LocalTunnelAddr returns the IP address of the local interface within -// the tunnel, as a string that can be parsed using net.ParseIP. -// -// This field is only populated for events whose NewState returns -// either ASSIGN_IP or CONNECTED. -func (e *StateEvent) LocalTunnelAddr() string { - parts := e.parts() - return string(parts[3]) -} - -// RemoteAddr returns the non-tunnel IP address of the remote -// system that has connected to the local OpenVPN process. -// -// This field is only populated for events whose NewState returns -// CONNECTED. -func (e *StateEvent) RemoteAddr() string { - parts := e.parts() - return string(parts[4]) -} - -func (e *StateEvent) String() string { - newState := e.NewState() - switch newState { - case "ASSIGN_IP": - return fmt.Sprintf("%s: %s", newState, e.LocalTunnelAddr()) - case "CONNECTED": - return fmt.Sprintf("%s: %s", newState, e.RemoteAddr()) - default: - desc := e.Description() - if desc != "" { - return fmt.Sprintf("%s: %s", newState, desc) - } else { - return newState - } - } -} - -func (e *StateEvent) parts() [][]byte { - if e.bodyParts == nil { - // State messages currently have only five segments, but - // we'll ask for 5 so any additional fields that might show - // up in newer versions will gather in an element we're - // not actually using. - e.bodyParts = bytes.SplitN(e.body, fieldSep, 6) - - // Prevent crash if the server has sent us a malformed - // status message. This should never actually happen if - // the server is behaving itself. - if len(e.bodyParts) < 5 { - expanded := make([][]byte, 5) - copy(expanded, e.bodyParts) - e.bodyParts = expanded - } - } - return e.bodyParts -} - -// EchoEvent is emitted by an OpenVPN process running in client mode when -// an "echo" command is pushed to it by the server it has connected to. -// -// The format of the echo message is free-form, since this message type is -// intended to pass application-specific data from the server-side config -// into whatever client is consuming the management prototcol. -// -// This event is emitted only if the management client has turned on events -// of this type using client.SetEchoEvents(true) -type EchoEvent struct { - body []byte -} - -func (e *EchoEvent) RawTimestamp() string { - sepIndex := bytes.Index(e.body, fieldSep) - if sepIndex == -1 { - return "" - } - return string(e.body[:sepIndex]) -} - -func (e *EchoEvent) Message() string { - sepIndex := bytes.Index(e.body, fieldSep) - if sepIndex == -1 { - return "" - } - return string(e.body[sepIndex+1:]) -} - -func (e *EchoEvent) String() string { - return fmt.Sprintf("ECHO: %s", e.Message()) -} - -// ByteCountEvent represents a periodic snapshot of data transfer in bytes -// on a VPN connection. -// -// For OpenVPN *servers*, events are emitted for each client and the method -// ClientId identifies thet client. -// -// For other OpenVPN modes, events are emitted only once per interval for the -// single connection managed by the target process, and ClientId returns -// the empty string. -type ByteCountEvent struct { - hasClient bool - body []byte - - // populated on first call to parts() - bodyParts [][]byte -} - -func (e *ByteCountEvent) ClientId() string { - if !e.hasClient { - return "" - } - - return string(e.parts()[0]) -} - -func (e *ByteCountEvent) BytesIn() int { - index := 0 - if e.hasClient { - index = 1 - } - str := string(e.parts()[index]) - val, _ := strconv.Atoi(str) - // Ignore error, since this should never happen if OpenVPN is - // behaving itself. - return val -} - -func (e *ByteCountEvent) BytesOut() int { - index := 1 - if e.hasClient { - index = 2 - } - str := string(e.parts()[index]) - val, _ := strconv.Atoi(str) - // Ignore error, since this should never happen if OpenVPN is - // behaving itself. - return val -} - -func (e *ByteCountEvent) String() string { - if e.hasClient { - return fmt.Sprintf("Client %s: %d in, %d out", e.ClientId(), e.BytesIn(), e.BytesOut()) - } else { - return fmt.Sprintf("%d in, %d out", e.BytesIn(), e.BytesOut()) - } -} - -func (e *ByteCountEvent) parts() [][]byte { - if e.bodyParts == nil { - e.bodyParts = bytes.SplitN(e.body, fieldSep, 4) - - wantCount := 2 - if e.hasClient { - wantCount = 3 - } - - // Prevent crash if the server has sent us a malformed - // message. This should never actually happen if the - // server is behaving itself. - if len(e.bodyParts) < wantCount { - expanded := make([][]byte, wantCount) - copy(expanded, e.bodyParts) - e.bodyParts = expanded - } - } - return e.bodyParts -} - -func upgradeEvent(raw []byte) Event { - splitIdx := bytes.Index(raw, eventSep) - if splitIdx == -1 { - // Should never happen, but we'll handle it robustly if it does. - return &MalformedEvent{raw} - } - - keyword := raw[:splitIdx] - body := raw[splitIdx+1:] - - switch { - case bytes.Equal(keyword, stateEventKW): - return &StateEvent{body: body} - case bytes.Equal(keyword, holdEventKW): - return &HoldEvent{body} - case bytes.Equal(keyword, echoEventKW): - return &EchoEvent{body} - case bytes.Equal(keyword, byteCountEventKW): - return &ByteCountEvent{hasClient: false, body: body} - case bytes.Equal(keyword, byteCountCliEventKW): - return &ByteCountEvent{hasClient: true, body: body} - default: - return &UnknownEvent{keyword, body} - } -} diff --git a/vendor/github.com/apparentlymart/go-openvpn-mgmt/openvpn/event_test.go b/vendor/github.com/apparentlymart/go-openvpn-mgmt/openvpn/event_test.go deleted file mode 100644 index 81a02e1..0000000 --- a/vendor/github.com/apparentlymart/go-openvpn-mgmt/openvpn/event_test.go +++ /dev/null @@ -1,346 +0,0 @@ -package openvpn - -import ( - "fmt" - "testing" -) - -// A key requirement of our event parsing is that it must never cause a -// panic, even if the OpenVPN process sends us malformed garbage. -// -// Therefore most of the tests in here are testing various tortured error -// cases, which are all expected to produce an event object, though the -// contents of that event object will be nonsensical if the OpenVPN server -// sends something nonsensical. - -func TestMalformedEvent(t *testing.T) { - testCases := [][]byte{ - []byte(""), - []byte("HTTP/1.1 200 OK"), - []byte(" "), - []byte("\x00"), - } - - for i, testCase := range testCases { - event := upgradeEvent(testCase) - - var malformed *MalformedEvent - var ok bool - if malformed, ok = event.(*MalformedEvent); !ok { - t.Errorf("test %d got %T; want %T", i, event, malformed) - continue - } - - wantString := fmt.Sprintf("Malformed Event %q", testCase) - if gotString := malformed.String(); gotString != wantString { - t.Errorf("test %d String returned %q; want %q", i, gotString, wantString) - } - } -} - -func TestUnknownEvent(t *testing.T) { - type TestCase struct { - Input []byte - WantType string - WantBody string - } - testCases := []TestCase{ - { - Input: []byte("DUMMY:baz"), - WantType: "DUMMY", - WantBody: "baz", - }, - { - Input: []byte("DUMMY:"), - WantType: "DUMMY", - WantBody: "", - }, - { - Input: []byte("DUMMY:abc,123,456"), - WantType: "DUMMY", - WantBody: "abc,123,456", - }, - } - - for i, testCase := range testCases { - event := upgradeEvent(testCase.Input) - - var unk *UnknownEvent - var ok bool - if unk, ok = event.(*UnknownEvent); !ok { - t.Errorf("test %d got %T; want %T", i, event, unk) - continue - } - - if got, want := unk.Type(), testCase.WantType; got != want { - t.Errorf("test %d Type returned %q; want %q", i, got, want) - } - if got, want := unk.Body(), testCase.WantBody; got != want { - t.Errorf("test %d Body returned %q; want %q", i, got, want) - } - } -} - -func TestHoldEvent(t *testing.T) { - testCases := [][]byte{ - []byte("HOLD:"), - []byte("HOLD:waiting for hold release"), - } - - for i, testCase := range testCases { - event := upgradeEvent(testCase) - - var hold *HoldEvent - var ok bool - if hold, ok = event.(*HoldEvent); !ok { - t.Errorf("test %d got %T; want %T", i, event, hold) - continue - } - } -} - -func TestEchoEvent(t *testing.T) { - type TestCase struct { - Input []byte - WantTimestamp string - WantMessage string - } - testCases := []TestCase{ - { - Input: []byte("ECHO:123,foo"), - WantTimestamp: "123", - WantMessage: "foo", - }, - { - Input: []byte("ECHO:123,"), - WantTimestamp: "123", - WantMessage: "", - }, - { - Input: []byte("ECHO:,foo"), - WantTimestamp: "", - WantMessage: "foo", - }, - { - Input: []byte("ECHO:,"), - WantTimestamp: "", - WantMessage: "", - }, - { - Input: []byte("ECHO:"), - WantTimestamp: "", - WantMessage: "", - }, - } - - for i, testCase := range testCases { - event := upgradeEvent(testCase.Input) - - var echo *EchoEvent - var ok bool - if echo, ok = event.(*EchoEvent); !ok { - t.Errorf("test %d got %T; want %T", i, event, echo) - continue - } - - if got, want := echo.RawTimestamp(), testCase.WantTimestamp; got != want { - t.Errorf("test %d RawTimestamp returned %q; want %q", i, got, want) - } - if got, want := echo.Message(), testCase.WantMessage; got != want { - t.Errorf("test %d Message returned %q; want %q", i, got, want) - } - } -} - -func TestStateEvent(t *testing.T) { - type TestCase struct { - Input []byte - WantTimestamp string - WantState string - WantDesc string - WantLocalAddr string - WantRemoteAddr string - } - testCases := []TestCase{ - { - Input: []byte("STATE:"), - WantTimestamp: "", - WantState: "", - WantDesc: "", - WantLocalAddr: "", - WantRemoteAddr: "", - }, - { - Input: []byte("STATE:,"), - WantTimestamp: "", - WantState: "", - WantDesc: "", - WantLocalAddr: "", - WantRemoteAddr: "", - }, - { - Input: []byte("STATE:,,,,"), - WantTimestamp: "", - WantState: "", - WantDesc: "", - WantLocalAddr: "", - WantRemoteAddr: "", - }, - { - Input: []byte("STATE:123,CONNECTED,good,172.16.0.1,192.168.4.1"), - WantTimestamp: "123", - WantState: "CONNECTED", - WantDesc: "good", - WantLocalAddr: "172.16.0.1", - WantRemoteAddr: "192.168.4.1", - }, - { - Input: []byte("STATE:123,RECONNECTING,SIGHUP,,"), - WantTimestamp: "123", - WantState: "RECONNECTING", - WantDesc: "SIGHUP", - WantLocalAddr: "", - WantRemoteAddr: "", - }, - { - Input: []byte("STATE:123,RECONNECTING,SIGHUP,,,extra"), - WantTimestamp: "123", - WantState: "RECONNECTING", - WantDesc: "SIGHUP", - WantLocalAddr: "", - WantRemoteAddr: "", - }, - } - - for i, testCase := range testCases { - event := upgradeEvent(testCase.Input) - - var st *StateEvent - var ok bool - if st, ok = event.(*StateEvent); !ok { - t.Errorf("test %d got %T; want %T", i, event, st) - continue - } - - if got, want := st.RawTimestamp(), testCase.WantTimestamp; got != want { - t.Errorf("test %d RawTimestamp returned %q; want %q", i, got, want) - } - if got, want := st.NewState(), testCase.WantState; got != want { - t.Errorf("test %d NewState returned %q; want %q", i, got, want) - } - if got, want := st.Description(), testCase.WantDesc; got != want { - t.Errorf("test %d Description returned %q; want %q", i, got, want) - } - if got, want := st.LocalTunnelAddr(), testCase.WantLocalAddr; got != want { - t.Errorf("test %d LocalTunnelAddr returned %q; want %q", i, got, want) - } - if got, want := st.RemoteAddr(), testCase.WantRemoteAddr; got != want { - t.Errorf("test %d RemoteAddr returned %q; want %q", i, got, want) - } - } -} - -func TestByteCountEvent(t *testing.T) { - type TestCase struct { - Input []byte - WantClientId string - WantBytesIn int - WantBytesOut int - } - testCases := []TestCase{ - { - Input: []byte("BYTECOUNT:"), - WantClientId: "", - WantBytesIn: 0, - WantBytesOut: 0, - }, - { - Input: []byte("BYTECOUNT:123,456"), - WantClientId: "", - WantBytesIn: 123, - WantBytesOut: 456, - }, - { - Input: []byte("BYTECOUNT:,"), - WantClientId: "", - WantBytesIn: 0, - WantBytesOut: 0, - }, - { - Input: []byte("BYTECOUNT:5,"), - WantClientId: "", - WantBytesIn: 5, - WantBytesOut: 0, - }, - { - Input: []byte("BYTECOUNT:,6"), - WantClientId: "", - WantBytesIn: 0, - WantBytesOut: 6, - }, - { - Input: []byte("BYTECOUNT:6"), - WantClientId: "", - WantBytesIn: 6, - WantBytesOut: 0, - }, - { - Input: []byte("BYTECOUNT:wrong,bad"), - WantClientId: "", - WantBytesIn: 0, - WantBytesOut: 0, - }, - { - Input: []byte("BYTECOUNT:1,2,3"), - WantClientId: "", - WantBytesIn: 1, - WantBytesOut: 2, - }, - { - // Intentionally malformed BYTECOUNT event sent as BYTECOUNT_CLI - Input: []byte("BYTECOUNT_CLI:123,456"), - WantClientId: "123", - WantBytesIn: 456, - WantBytesOut: 0, - }, - { - Input: []byte("BYTECOUNT_CLI:"), - WantClientId: "", - WantBytesIn: 0, - WantBytesOut: 0, - }, - { - Input: []byte("BYTECOUNT_CLI:abc123,123,456"), - WantClientId: "abc123", - WantBytesIn: 123, - WantBytesOut: 456, - }, - { - Input: []byte("BYTECOUNT_CLI:abc123,123"), - WantClientId: "abc123", - WantBytesIn: 123, - WantBytesOut: 0, - }, - } - - for i, testCase := range testCases { - event := upgradeEvent(testCase.Input) - - var bc *ByteCountEvent - var ok bool - if bc, ok = event.(*ByteCountEvent); !ok { - t.Errorf("test %d got %T; want %T", i, event, bc) - continue - } - - if got, want := bc.ClientId(), testCase.WantClientId; got != want { - t.Errorf("test %d ClientId returned %q; want %q", i, got, want) - } - if got, want := bc.BytesIn(), testCase.WantBytesIn; got != want { - t.Errorf("test %d BytesIn returned %d; want %d", i, got, want) - } - if got, want := bc.BytesOut(), testCase.WantBytesOut; got != want { - t.Errorf("test %d BytesOut returned %d; want %d", i, got, want) - } - } -} diff --git a/vendor/github.com/apparentlymart/go-openvpn-mgmt/openvpn/server.go b/vendor/github.com/apparentlymart/go-openvpn-mgmt/openvpn/server.go deleted file mode 100644 index d7defd4..0000000 --- a/vendor/github.com/apparentlymart/go-openvpn-mgmt/openvpn/server.go +++ /dev/null @@ -1,172 +0,0 @@ -package openvpn - -import ( - "net" - "time" -) - -// MgmtListener accepts incoming connections from OpenVPN. -// -// The primary way to instantiate this type is via the function Listen. -// See its documentation for more information. -type MgmtListener struct { - l net.Listener -} - -// NewMgmtListener constructs a MgmtListener from an already-established -// net.Listener. In most cases it will be more convenient to use -// the function Listen. -func NewMgmtListener(l net.Listener) *MgmtListener { - return &MgmtListener{l} -} - -// Listen opens a listen port and awaits incoming connections from OpenVPN -// processes. -// -// OpenVPN will behave in this manner when launched with the following options: -// -// --management ipaddr port --management-client -// -// Note that in this case the terminology is slightly confusing, since from -// the standpoint of TCP/IP it is OpenVPN that is the client and our program -// that is the server, but once the connection is established the channel -// is indistinguishable from the situation where OpenVPN exposed a management -// *server* and we connected to it. Thus we still refer to our program as -// the "client" and OpenVPN as the "server" once the connection is established. -// -// When running on Unix systems it's possible to instead listen on a Unix -// domain socket. To do this, pass an absolute path to the socket as -// the listen address, and then run OpenVPN with the following options: -// -// --management /path/to/socket unix --management-client -// -func Listen(laddr string) (*MgmtListener, error) { - proto := "tcp" - if len(laddr) > 0 && laddr[0] == '/' { - proto = "unix" - } - listener, err := net.Listen(proto, laddr) - if err != nil { - return nil, err - } - - return NewMgmtListener(listener), nil -} - -// Accept waits for and returns the next connection. -func (l *MgmtListener) Accept() (*IncomingConn, error) { - conn, err := l.l.Accept() - if err != nil { - return nil, err - } - - return &IncomingConn{conn}, nil -} - -// Close closes the listener. Any blocked Accept operations -// will be blocked and each will return an error. -func (l *MgmtListener) Close() error { - return l.l.Close() -} - -// Addr returns the listener's network address. -func (l *MgmtListener) Addr() net.Addr { - return l.l.Addr() -} - -// Serve will await new connections and call the given handler -// for each. -// -// Serve does not return unless the listen port is closed; a non-nil -// error is always returned. -func (l *MgmtListener) Serve(handler IncomingConnHandler) error { - defer l.Close() - - var tempDelay time.Duration - - for { - incoming, err := l.Accept() - if err != nil { - if ne, ok := err.(net.Error); ok && ne.Temporary() { - if tempDelay == 0 { - tempDelay = 5 * time.Millisecond - } else { - tempDelay *= 2 - } - if max := 1 * time.Second; tempDelay > max { - tempDelay = max - } - - // Wait a while before we try again. - time.Sleep(tempDelay) - continue - } else { - // Listen socket is permanently closed or errored, - // so it's time for us to exit. - return err - } - } - - // always reset our retry delay once we successfully read - tempDelay = 0 - - go handler.ServeOpenVPNMgmt(*incoming) - } -} - -type IncomingConn struct { - conn net.Conn -} - -// Open initiates communication with the connected OpenVPN process, -// and establishes the channel on which events will be delivered. -// -// See the documentation for NewClient for discussion about the requirements -// for eventCh. -func (ic IncomingConn) Open(eventCh chan<- Event) *MgmtClient { - return NewClient(ic.conn, eventCh) -} - -// Close abruptly closes the socket connected to the OpenVPN process. -// -// This is a rather abrasive way to close the channel, intended for rejecting -// unwanted incoming clients that may or may not speak the OpenVPN protocol. -// -// Once communication is accepted and established, it is generally better -// to close the connection gracefully using commands on the client returned -// from Open. -func (ic IncomingConn) Close() error { - return ic.conn.Close() -} - -type IncomingConnHandler interface { - ServeOpenVPNMgmt(IncomingConn) -} - -// IncomingConnHandlerFunc is an adapter to allow the use of ordinary -// functions as connection handlers. -// -// Given a function with the appropriate signature, IncomingConnHandlerFunc(f) -// is an IncomingConnHandler that calls f. -type IncomingConnHandlerFunc func(IncomingConn) - -func (f IncomingConnHandlerFunc) ServeOpenVPNMgmt(i IncomingConn) { - f(i) -} - -// ListenAndServe creates a MgmtListener for the given listen address -// and then calls AcceptAndServe on it. -// -// This is just a convenience wrapper. See the AcceptAndServe method for -// more details. Just as with AcceptAndServe, this function does not return -// except on error; in addition to the error cases handled by AcceptAndServe, -// this function may also fail if the listen socket cannot be established -// in the first place. -func ListenAndServe(laddr string, handler IncomingConnHandler) error { - listener, err := Listen(laddr) - if err != nil { - return err - } - - return listener.Serve(handler) -} |