summaryrefslogtreecommitdiff
path: root/webircgateway/pkg/proxy/proxy.go
diff options
context:
space:
mode:
Diffstat (limited to 'webircgateway/pkg/proxy/proxy.go')
-rw-r--r--webircgateway/pkg/proxy/proxy.go129
1 files changed, 129 insertions, 0 deletions
diff --git a/webircgateway/pkg/proxy/proxy.go b/webircgateway/pkg/proxy/proxy.go
new file mode 100644
index 0000000..c332f40
--- /dev/null
+++ b/webircgateway/pkg/proxy/proxy.go
@@ -0,0 +1,129 @@
+package proxy
+
+import (
+ "encoding/json"
+ "errors"
+ "io"
+ "net"
+)
+
+type KiwiProxyState int
+
+const KiwiProxyStateClosed KiwiProxyState = 0
+const KiwiProxyStateConnecting KiwiProxyState = 1
+const KiwiProxyStateHandshaking KiwiProxyState = 2
+const KiwiProxyStateConnected KiwiProxyState = 3
+
+type ConnError struct {
+ Msg string
+ Type string
+}
+
+func (err *ConnError) Error() string {
+ return err.Msg
+}
+
+type KiwiProxyConnection struct {
+ Username string
+ ProxyInterface string
+ DestHost string
+ DestPort int
+ DestTLS bool
+ State KiwiProxyState
+ Conn *net.Conn
+}
+
+func MakeKiwiProxyConnection() *KiwiProxyConnection {
+ return &KiwiProxyConnection{
+ State: KiwiProxyStateClosed,
+ }
+}
+
+func (c *KiwiProxyConnection) Close() error {
+ if c.State == KiwiProxyStateClosed {
+ return errors.New("Connection already closed")
+ }
+
+ return (*c.Conn).Close()
+}
+
+func (c *KiwiProxyConnection) Dial(proxyServerAddr string) error {
+ if c.State != KiwiProxyStateClosed {
+ return errors.New("Connection in closed state")
+ }
+
+ c.State = KiwiProxyStateConnecting
+
+ conn, err := net.Dial("tcp", proxyServerAddr)
+ if err != nil {
+ return err
+ }
+
+ c.Conn = &conn
+ c.State = KiwiProxyStateHandshaking
+
+ meta, _ := json.Marshal(map[string]interface{}{
+ "username": c.Username,
+ "interface": c.ProxyInterface,
+ "host": c.DestHost,
+ "port": c.DestPort,
+ "ssl": c.DestTLS,
+ })
+
+ (*c.Conn).Write(append(meta, byte('\n')))
+
+ buf := make([]byte, 1024)
+ bufLen, readErr := (*c.Conn).Read(buf)
+ if readErr != nil {
+ (*c.Conn).Close()
+ c.State = KiwiProxyStateClosed
+ return readErr
+ }
+
+ response := string(buf)
+ if bufLen > 0 && response[0] == '1' {
+ c.State = KiwiProxyStateConnected
+ } else {
+ (*c.Conn).Close()
+ c.State = KiwiProxyStateClosed
+
+ if bufLen == 0 {
+ return errors.New("The proxy could not connect to the destination")
+ }
+
+ switch response[0] {
+ case '0':
+ return errors.New("The proxy could not connect to the destination")
+ case '2':
+ return &ConnError{Msg: "Connection reset", Type: "conn_reset"}
+ case '3':
+ return &ConnError{Msg: "Connection refused", Type: "conn_refused"}
+ case '4':
+ return &ConnError{Msg: "Host not found", Type: "not_found"}
+ case '5':
+ return &ConnError{Msg: "Connection timed out", Type: "conn_timeout"}
+ }
+ }
+
+ return nil
+}
+
+func (c *KiwiProxyConnection) Read(b []byte) (n int, err error) {
+ if c.State == KiwiProxyStateConnecting || c.State == KiwiProxyStateHandshaking {
+ return 0, nil
+ } else if c.State == KiwiProxyStateClosed {
+ return 0, io.EOF
+ } else {
+ return (*c.Conn).Read(b)
+ }
+}
+
+func (c *KiwiProxyConnection) Write(b []byte) (n int, err error) {
+ if c.State == KiwiProxyStateConnecting || c.State == KiwiProxyStateHandshaking {
+ return 0, nil
+ } else if c.State == KiwiProxyStateClosed {
+ return 0, io.EOF
+ } else {
+ return (*c.Conn).Write(b)
+ }
+}