├── .gitignore ├── README ├── test ├── client.ovpn ├── dh1024.pem ├── server.ovpn ├── ca.cer ├── client.pem └── server.pem ├── utils.go ├── openvpn.secret ├── utils └── utils.go ├── tun ├── tun.go ├── tun_darwin.go └── tun_linux.go ├── link └── link.go ├── occ └── occ.go ├── protocol.go ├── opt └── options.go ├── reliable_udp.go ├── main.go └── ssl.go /.gitignore: -------------------------------------------------------------------------------- 1 | .*.swp 2 | 3 | *.[568] 4 | govpn* 5 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | It works. By now it's able to communicate with the simplest OpenVPN. 2 | -------------------------------------------------------------------------------- /test/client.ovpn: -------------------------------------------------------------------------------- 1 | client 2 | dev tun 3 | proto udp 4 | remote 192.168.56.8 1194 5 | nobind 6 | ca ca.cer 7 | cert client.pem 8 | key client.pem 9 | -------------------------------------------------------------------------------- /test/dh1024.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN DH PARAMETERS----- 2 | MIGHAoGBANRTuVhpJeTz7cij4PhEVdHxghrl2+skuNOmRzpEvm9z9V85Jxg9kbPw 3 | 453chqWADCz7OCsqPz+RLdiFMrNClsZ9VpnM5vIfWMAK2ePAX5OGQrJ5QlzQDC/d 4 | 3bqxO6I3B9svonzyCzRbktOjWVUcBgFdEU7BtT/VjqTJieqZuh4bAgEC 5 | -----END DH PARAMETERS----- 6 | -------------------------------------------------------------------------------- /test/server.ovpn: -------------------------------------------------------------------------------- 1 | port 1194 2 | proto udp 3 | dev tun 4 | topology subnet 5 | ca ca.cer 6 | cert server.pem 7 | key server.pem 8 | dh dh1024.pem 9 | server 10.8.0.0 255.255.255.0 10 | user jay 11 | group jay 12 | persist-key 13 | persist-tun 14 | verb 3 15 | keepalive 10 120 16 | tls-version-min 1.0 17 | cipher AES-128-CBC 18 | -------------------------------------------------------------------------------- /utils.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "io" 7 | ) 8 | 9 | func bufReadUint32(buf *bytes.Buffer) (uint32, error) { 10 | var numBuf [4]byte 11 | _, err := io.ReadFull(buf, numBuf[:]) 12 | if err != nil { 13 | return 0, err 14 | } 15 | return binary.BigEndian.Uint32(numBuf[:]), nil 16 | } 17 | 18 | func bufWriteUint32(buf *bytes.Buffer, num uint32) { 19 | var numBuf [4]byte 20 | binary.BigEndian.PutUint32(numBuf[:], num) 21 | buf.Write(numBuf[:]) 22 | } 23 | -------------------------------------------------------------------------------- /test/ca.cer: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIBrTCCARagAwIBAgIBATANBgkqhkiG9w0BAQUFADANMQswCQYDVQQDEwJjYTAe 3 | Fw0xNDA4MTkxNDE2MDBaFw0yNDA4MTkxNDE2MDBaMA0xCzAJBgNVBAMTAmNhMIGf 4 | MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHJfnWjYPfBndDjVltFB+OyuEZI++H 5 | HA/XrwW5tmE9dAOaSb0RRlbUQq+dlGghBdFrZX9Fl9MU4h+kdWQZ0XTA5fdskZ7V 6 | ixlezY8irCeR1FMIYwszJloQxO5kpZTQCl9htXAiL0BcJXDtOEKA6lqFDC9x1eMV 7 | N1VlaVh7+aG5ywIDAQABox0wGzAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjAN 8 | BgkqhkiG9w0BAQUFAAOBgQAkpjiAFADnS531RRpSrmtFhGKkII+D3b+Q103Vor/O 9 | KH6LIJM6FuGTN3Agc95TzkquLsvKbyaFpBTAwMzYlvKQCITCyVS0zI6Cl9+MAU4s 10 | 0jXgoj++BGtV3QU7GaPLlLGbYumbb/OUoriBZpPVsgTvZtKeRd49LoFMsHZnUnHV 11 | Qw== 12 | -----END CERTIFICATE----- 13 | -------------------------------------------------------------------------------- /openvpn.secret: -------------------------------------------------------------------------------- 1 | # 2 | # 2048 bit OpenVPN static key 3 | # 4 | -----BEGIN OpenVPN Static key V1----- 5 | 2647373144c0265ac50c417e37619d88 6 | c1dc75cc4659c3185a7d774e2922d1db 7 | f4014d672aab00e54880127cb33f4583 8 | 353f2df1dd39cab793687adf30c9a55d 9 | 47f435a4bc645c1a2461b4ba403a7f70 10 | b488afe7e840ce3f98d01639370a6115 11 | 204caba3929658a058aac529d556f264 12 | e456c5190071734cdc2a7808a2e47c08 13 | 44ae89143d01f29d424e90cd319c6155 14 | 148028e205a10a7ae891fb5e0600ba45 15 | 38150a323fe45017fbf31a37c07b23df 16 | 7c1b48d597a71cce27711a0fb3cb3655 17 | 62216dc7337b26279bcdf53bb9b5b557 18 | 1fa6d90f5a12382060ea795681cfc8ac 19 | f34937d161d52e503de1af726cff60ee 20 | 7380e7884c4fcaf94125ffd50fb2af90 21 | -----END OpenVPN Static key V1----- 22 | -------------------------------------------------------------------------------- /utils/utils.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net" 7 | "strconv" 8 | ) 9 | 10 | // number class helpers 11 | 12 | func Atoi(str string) int { 13 | i, err := strconv.Atoi(str) 14 | if err != nil { 15 | i = 0 16 | } 17 | return i 18 | } 19 | 20 | func PosAtoi(str string) int { 21 | i, err := strconv.Atoi(str) 22 | if err != nil || i < 0 { 23 | i = 0 24 | } 25 | return i 26 | } 27 | 28 | // network address class helpers 29 | 30 | func IsValidHost(addr string) bool { 31 | return net.ParseIP(addr) != nil 32 | } 33 | 34 | func IsValidPort(port int) bool { 35 | return port > 0 && port < 65536 36 | } 37 | 38 | func GetAddress(host string, port int) *net.UDPAddr { 39 | str := fmt.Sprintf("%s:%d", host, port) 40 | addr, err := net.ResolveUDPAddr("udp", str) 41 | if err != nil { 42 | log.Fatalf("[CRIT] RESOLVE: Cannot resolve host address %s: %v.", str, err) 43 | } 44 | return addr 45 | } 46 | 47 | func GetNetwork(address, netmask string) string { 48 | addr := net.ParseIP(address) 49 | mask := net.ParseIP(netmask) 50 | for i := 0; i < len(addr); i++ { 51 | addr[i] &= mask[i] 52 | } 53 | return addr.String() 54 | } 55 | -------------------------------------------------------------------------------- /tun/tun.go: -------------------------------------------------------------------------------- 1 | package tun 2 | 3 | import ( 4 | "log" 5 | "os" 6 | ) 7 | 8 | type Tun struct { 9 | fd *os.File 10 | actualName string 11 | ReadCh chan []byte 12 | WriteCh chan []byte 13 | } 14 | 15 | func New() *Tun { 16 | tun := &Tun{ReadCh: make(chan []byte), WriteCh: make(chan []byte)} 17 | return tun 18 | } 19 | 20 | func (tun *Tun) Start() { 21 | go tun.readLoop() 22 | go tun.writeLoop() 23 | } 24 | 25 | func (tun *Tun) writeLoop() { 26 | for { 27 | buf := <-tun.WriteCh 28 | _, err := tun.fd.Write(buf) 29 | if err != nil { 30 | log.Printf("[EROR] TUN/TAP: write failed: %v: %v", err, buf) 31 | tun.fd.Close() 32 | return 33 | } 34 | } 35 | } 36 | 37 | func (tun *Tun) readLoop() { 38 | var buf [4096]byte 39 | for { 40 | nread, err := tun.fd.Read(buf[:]) 41 | if nread > 0 { 42 | b := make([]byte, nread) 43 | copy(b, buf[:nread]) 44 | tun.ReadCh <- b 45 | } 46 | if nread == 0 { 47 | tun.fd.Close() 48 | return 49 | } 50 | if err != nil { 51 | log.Printf("[EROR] TUN/TAP: read failed: %v", err) 52 | tun.fd.Close() 53 | return 54 | } 55 | } 56 | } 57 | 58 | func (tun *Tun) Stop() { 59 | tun.fd.Close() 60 | } 61 | -------------------------------------------------------------------------------- /tun/tun_darwin.go: -------------------------------------------------------------------------------- 1 | package tun 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | "os/exec" 8 | ) 9 | 10 | func (tun *Tun) Open() { 11 | dynamicOpened := false 12 | dynamicName := "" 13 | for i := 0; i < 16; i++ { 14 | tunName := fmt.Sprintf("/dev/tun%d", i) 15 | dynamicName = fmt.Sprintf("tun%d", i) 16 | fd, err := os.OpenFile(tunName, os.O_RDWR, 0) 17 | if err == nil { 18 | tun.fd = fd 19 | dynamicOpened = true 20 | break 21 | } 22 | log.Printf("[WARN] Failed to open TUN/TAP device '%s': %v", dynamicName, err) 23 | } 24 | if !dynamicOpened { 25 | log.Fatalf("[CRIT] Cannot allocate TUN/TAP device dynamically.") 26 | } 27 | 28 | tun.actualName = dynamicName 29 | log.Printf("[INFO] TUN/TAP device %s opened.", tun.actualName) 30 | } 31 | 32 | func (tun *Tun) SetupAddress(addr, mask string) { 33 | cmd := exec.Command("/sbin/ifconfig", tun.actualName, "delete") 34 | _ = cmd.Run() 35 | log.Printf("[INFO] NOTE: Tried to delete pre-existing TUN/TAP instance -- no problem if failed.") 36 | 37 | cmd = exec.Command("/sbin/ifconfig", tun.actualName, 38 | addr, addr, "netmask", mask, "mtu", "1500", "up") 39 | output, err := cmd.CombinedOutput() 40 | if err != nil { 41 | log.Fatalf("[CRIT] Mac OS X ifconfig failed: %v: %s", err, output) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tun/tun_linux.go: -------------------------------------------------------------------------------- 1 | package tun 2 | 3 | import ( 4 | "log" 5 | "os" 6 | "os/exec" 7 | "strings" 8 | "syscall" 9 | "unsafe" 10 | ) 11 | 12 | const ( 13 | IFF_NO_PI = 0x10 14 | IFF_TUN = 0x01 15 | IFF_TAP = 0x02 16 | TUNSETIFF = 0x400454CA 17 | ) 18 | 19 | func (tun *Tun) Open() { 20 | deviceFile := "/dev/net/tun" 21 | fd, err := os.OpenFile(deviceFile, os.O_RDWR, 0) 22 | if err != nil { 23 | log.Fatalf("[CRIT] Note: Cannot open TUN/TAP dev %s: %v", deviceFile, err) 24 | } 25 | tun.fd = fd 26 | 27 | ifr := make([]byte, 18) 28 | ifr[17] = IFF_NO_PI 29 | ifr[16] = IFF_TUN 30 | _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, 31 | uintptr(tun.fd.Fd()), uintptr(TUNSETIFF), 32 | uintptr(unsafe.Pointer(&ifr[0]))) 33 | if errno != 0 { 34 | log.Fatalf("[CRIT] Cannot ioctl TUNSETIFF: %v", errno) 35 | } 36 | 37 | tun.actualName = string(ifr) 38 | tun.actualName = tun.actualName[:strings.Index(tun.actualName, "\000")] 39 | log.Printf("[INFO] TUN/TAP device %s opened.", tun.actualName) 40 | } 41 | 42 | func (tun *Tun) SetupAddress(addr, mask string) { 43 | cmd := exec.Command("ifconfig", tun.actualName, addr, 44 | "netmask", mask, "mtu", "1500") 45 | log.Printf("[DEBG] ifconfig command: %v", strings.Join(cmd.Args, " ")) 46 | err := cmd.Run() 47 | if err != nil { 48 | log.Printf("[EROR] Linux ifconfig failed: %v.", err) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /test/client.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIICXQIBAAKBgQDdLOVWjU4fR9njIuy7fAK7cgKSjvAzhxEIvsUjSmZ0JnnNGdIk 3 | ykI7VGcJx2qYXqhD76qro922zzM7BngTFY8KN0Y9mcPsgOC5VmnHEsKS/d4mDuQa 4 | TP3ZhAud2/tjZV2UJ/gZjIxTki7TBSfWsRtJoZr+D+oQaVT4Mczbxh9prwIDAQAB 5 | AoGAFXlVbvjbO+hC/G2YpH9e2IoyO76LDcWwXrP++fUwS1is/L/kClRk59PDCU0G 6 | SXLvTWFIpc+MKEKny7ROFjRCpeIPvHhpqC33fZmnfO3E+y6/TGu/GH7mj3KmdJak 7 | 61mdab7fcRSVWFf5Z31RpW+CMkFeKWBWMulYqKsvN8GXlBkCQQDxuKJ5zYF7Y4xz 8 | 6ZhVamdEBzVsNSjWCGsAdRtCm7H1IINDEp9UcRxpWBrRUqUsvlEJM2rBI7eYJ7CK 9 | 2bTGYAgDAkEA6j2P2o5kmW//GCCRBHqxOoY6BJa2pRAh0nzpoXr4lqFFWI684jFO 10 | XGMIPHoyefUuM+ME8drGbdHUoiqs+zAV5QJBAMekJw1Snk66uZZCqH5jk0asbYMh 11 | pMihyz5lek5ZKXG7mK4dA1tK0JxxGDUqfSGnTma7AMDkLw6MOVN028m8JuECQQCN 12 | TDdzgkOi3xFFD5gK2KwB/qgOzo88gL+2Rg10kEZWLtAy/F9qHo4DYuW7/YZnVQPa 13 | 3s3DytG5u0KF1DJmj3oVAkAkrkIe4FWvC8EBzuBAqAE+K5sGgJKEYabG1vC4i8l3 14 | q7+DccKK4U10SRYanTFyOBO04QFf51DRxYOu8TE9JNP5 15 | -----END RSA PRIVATE KEY----- 16 | -----BEGIN CERTIFICATE----- 17 | MIIBwzCCASygAwIBAgIBAzANBgkqhkiG9w0BAQUFADANMQswCQYDVQQDEwJjYTAe 18 | Fw0xNDA4MTkxNDE4MDBaFw0yNDA4MTkxNDE2MDBaMBExDzANBgNVBAMTBmNsaWVu 19 | dDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA3SzlVo1OH0fZ4yLsu3wCu3IC 20 | ko7wM4cRCL7FI0pmdCZ5zRnSJMpCO1RnCcdqmF6oQ++qq6Pdts8zOwZ4ExWPCjdG 21 | PZnD7IDguVZpxxLCkv3eJg7kGkz92YQLndv7Y2VdlCf4GYyMU5Iu0wUn1rEbSaGa 22 | /g/qEGlU+DHM28Yfaa8CAwEAAaMvMC0wCQYDVR0TBAIwADALBgNVHQ8EBAMCA7gw 23 | EwYDVR0lBAwwCgYIKwYBBQUHAwIwDQYJKoZIhvcNAQEFBQADgYEAM84kR+FV5lYP 24 | 68U43oByFCGfQfJjpSq3r3xsZEHlTCA7JMg1BtfGrwuqF+Juzf3a3YXlySEpsXVZ 25 | 9tEmtw+kNN6OY3MfIixW0u2WfheSMIRw18lRWXUK0uwEAASeqeau7QGyOyLJDC7t 26 | V0j4pzZ0tnmF0Ybeqs33u8+v43/cf0U= 27 | -----END CERTIFICATE----- 28 | -------------------------------------------------------------------------------- /test/server.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIICXQIBAAKBgQDcES/VJfA1MtvjO15cRfOjxC1flCq07G4OEnx34SsJbdC7kI+x 3 | tjoIjLBH+pR/hNp1IoQn34ZaSjalc+6dEH3Vq2OKPBN4tJr6COYvm5LS7CtbAiIn 4 | +AadT5g1+Erxb2LovnQb4xDbodR+UTw5HI7h13+rgkFtBUO1nR25mGQ0wwIDAQAB 5 | AoGBAJtDTPoXQDhoX5ccZeC4QcNDP7f1c4QeYy9uf36c0J5gaipLPfZl2N/7UswV 6 | 0Pt/IhoOdisjm0jMn21wM+OApSXyP1bsBYdYK64vJd28OqtmnyMY/yo2e2dL3eXX 7 | RKHUHL27c3yoetRPLpEqUeZ/x/gu5Vd9gx2ee0LVxZSNsZfxAkEA8falPzfDu+oB 8 | WXo9dk6HyFOVUpVI7Y1r87kmD1pL1vDFRFsp3nlml9q/07lW4F3yPjACq8YF+Llt 9 | Ig171wgCfwJBAOjVXPUrxO30q7BoKkCuf4JCtQUZlQIBLBeTn1hPoyTqpgGPPToW 10 | vRStrkY3l8f0Kq4s9ENqkKoBp8gTKaldI70CQQDx60260FGGL2gcA0kyYUAHPfJ9 11 | OD9LK+u0KfjwvrI2/FHvj0pkYnL9/ztuP8+p0qRiIvR4tCvCS/reYibgjuSXAkA0 12 | fqaOwGeOHvP2ugWMv8sP22pk0/e8k/cU+bubdZka4ay7/UeYqTfIScBZJH+cHXjh 13 | /FC2QniLXAQwH+HsxYshAkBMaipdgXlDXz24iPGDMwh8N0jp6ji+yfJS4HM4zekI 14 | NtLUa7bHpiBOHjijzi2xl5LbnCpBvmtit/G5Vw7+QLkl 15 | -----END RSA PRIVATE KEY----- 16 | -----BEGIN CERTIFICATE----- 17 | MIIBwzCCASygAwIBAgIBAjANBgkqhkiG9w0BAQUFADANMQswCQYDVQQDEwJjYTAe 18 | Fw0xNDA4MTkxNDE3MDBaFw0yNDA4MTkxNDE2MDBaMBExDzANBgNVBAMTBnNlcnZl 19 | cjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA3BEv1SXwNTLb4zteXEXzo8Qt 20 | X5QqtOxuDhJ8d+ErCW3Qu5CPsbY6CIywR/qUf4TadSKEJ9+GWko2pXPunRB91atj 21 | ijwTeLSa+gjmL5uS0uwrWwIiJ/gGnU+YNfhK8W9i6L50G+MQ26HUflE8ORyO4dd/ 22 | q4JBbQVDtZ0duZhkNMMCAwEAAaMvMC0wCQYDVR0TBAIwADALBgNVHQ8EBAMCA7gw 23 | EwYDVR0lBAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcNAQEFBQADgYEAF2YIBrZ2UjlI 24 | +1uLdR11z3Yw2pZVkq71JN4cQLquq04tDRRpBaD+iY48gwCvZxsMfeGRz/mcfiEs 25 | skZ83ZEy7T24P2YJS0ZIAFSP+LQMwK1XmuR+24NE8FoGR947897QUQmInBGKHonP 26 | r39NtarHASuXCmfYehEtD2bXkAZ5JjY= 27 | -----END CERTIFICATE----- 28 | -------------------------------------------------------------------------------- /link/link.go: -------------------------------------------------------------------------------- 1 | package link 2 | 3 | import ( 4 | "github.com/glacjay/govpn/opt" 5 | "github.com/glacjay/govpn/utils" 6 | "log" 7 | "net" 8 | ) 9 | 10 | type Link struct { 11 | inputChan <-chan []byte 12 | outputChan chan<- []byte 13 | 14 | conn *net.UDPConn 15 | 16 | remote *net.UDPAddr 17 | connected bool 18 | } 19 | 20 | func New(o *opt.Options, inputChan <-chan []byte, outputChan chan<- []byte) *Link { 21 | link := new(Link) 22 | link.inputChan = inputChan 23 | link.outputChan = outputChan 24 | 25 | addr := utils.GetAddress(o.Conn.LocalHost, o.Conn.LocalPort) 26 | conn, err := net.ListenUDP("udp", addr) 27 | if err != nil { 28 | log.Fatalf("[CRIT] UDP: Cannot create UDP socket: %v.", err) 29 | } 30 | link.conn = conn 31 | 32 | if o.Conn.RemoteHost != "" { 33 | link.remote = utils.GetAddress(o.Conn.RemoteHost, o.Conn.RemotePort) 34 | } 35 | 36 | return link 37 | } 38 | 39 | func (link *Link) Start() { 40 | go link.inputLoop() 41 | go link.outputLoop() 42 | } 43 | 44 | func (link *Link) inputLoop() { 45 | for { 46 | buf := <-link.inputChan 47 | if link.remote == nil { 48 | continue 49 | } 50 | _, err := link.conn.WriteToUDP(buf, link.remote) 51 | if err != nil { 52 | log.Printf("[EROR] UDPv4: write failed: %v", err) 53 | } 54 | } 55 | } 56 | 57 | func (link *Link) outputLoop() { 58 | for { 59 | buf := make([]byte, 4096) 60 | nread, addr, err := link.conn.ReadFromUDP(buf) 61 | if err != nil { 62 | if err.(net.Error).Temporary() { 63 | continue 64 | } else { 65 | log.Printf("[EROR] UDPv4: read failed: %v", err) 66 | } 67 | } 68 | if link.remote == nil { 69 | link.remote = addr 70 | } 71 | if link.remote.String() != addr.String() { 72 | log.Printf("[WARN] TCP/UDP: Incoming packet rejected from %s[%s], expected peer address: %s (allow this incoming source address/port by removing --remote)", addr.String(), addr.Network(), link.remote.String()) 73 | continue 74 | } 75 | if !link.connected { 76 | link.connected = true 77 | log.Printf("[INFO] Peer Connection Initiated with %s", addr.String()) 78 | log.Printf("[INFO] Initialization Sequence Completed.") 79 | } 80 | 81 | link.outputChan <- buf[:nread] 82 | } 83 | } 84 | 85 | func (link *Link) Stop() { 86 | link.conn.Close() 87 | } 88 | -------------------------------------------------------------------------------- /occ/occ.go: -------------------------------------------------------------------------------- 1 | package occ 2 | 3 | import ( 4 | "log" 5 | "github.com/glacjay/govpn/opt" 6 | "time" 7 | ) 8 | 9 | // const, actually 10 | var messageHeader = [16]byte{ 11 | 0x28, 0x7f, 0x34, 0x6b, 0xd4, 0xef, 0x7a, 0x81, 12 | 0x2d, 0x56, 0xb8, 0xd3, 0xaf, 0xc5, 0x45, 0x9c} 13 | 14 | // OCC Message Types 15 | const ( 16 | requestOpcode = 0 17 | replyOpcode = 1 18 | ) 19 | 20 | type OCC struct { 21 | commandChan chan int 22 | outputChan chan<- []byte 23 | 24 | localString string 25 | remoteString string 26 | } 27 | 28 | func New(o *opt.Options, outputChan chan<- []byte) *OCC { 29 | occ := new(OCC) 30 | occ.commandChan = make(chan int, 1) 31 | occ.outputChan = outputChan 32 | 33 | occ.localString = o.OptionsString() 34 | log.Printf("[INFO] Local Options String: '%s'", occ.localString) 35 | occ.remoteString = o.OptionsString() 36 | log.Printf("[INFO] Expected Remote Options String: '%s'", occ.remoteString) 37 | 38 | return occ 39 | } 40 | 41 | func (occ *OCC) StartSendingRequest() { 42 | go occ.outputLoop() 43 | } 44 | 45 | func (occ *OCC) outputLoop() { 46 | for i := 0; i < 12; i++ { 47 | select { 48 | case _ = <-occ.commandChan: 49 | return 50 | case _ = <-time.After(1e9 * 10): 51 | occ.outputChan <- occ.requestMessage() 52 | } 53 | } 54 | } 55 | 56 | func (occ *OCC) Stop() { 57 | occ.commandChan <- 1 58 | } 59 | 60 | func (occ *OCC) requestMessage() []byte { 61 | msg := make([]byte, 17) 62 | copy(msg, messageHeader[:]) 63 | msg[16] = requestOpcode 64 | return msg 65 | } 66 | 67 | func (occ *OCC) replyMessage() []byte { 68 | msg := make([]byte, 18+len(occ.localString)) 69 | copy(msg, messageHeader[:]) 70 | msg[16] = replyOpcode 71 | copy(msg[17:], occ.localString) 72 | msg[len(msg)-1] = 0 73 | return msg 74 | } 75 | 76 | func (occ *OCC) CheckOccMessage(msg []byte) bool { 77 | if msg == nil || len(msg) <= 16 || string(msg[:16]) != string(messageHeader[:]) { 78 | return false 79 | } 80 | 81 | msg = msg[16:] 82 | switch msg[0] { 83 | case requestOpcode: 84 | occ.outputChan <- occ.replyMessage() 85 | case replyOpcode: 86 | occ.Stop() 87 | remoteString := string(msg[1 : len(msg)-1]) 88 | if remoteString != occ.remoteString { 89 | log.Printf("[INFO] NOTE: Options consistency check may be skewed by version differences.") 90 | // TODO More detailed check 91 | } 92 | default: 93 | } 94 | return true 95 | } 96 | -------------------------------------------------------------------------------- /protocol.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "io" 6 | "log" 7 | "net" 8 | ) 9 | 10 | const ( 11 | kProtoControlHardResetClientV1 = 1 12 | kProtoControlHardResetServerV1 = 2 13 | kProtoControlSoftResetV1 = 3 14 | kProtoControlV1 = 4 15 | kProtoAckV1 = 5 16 | kProtoDataV1 = 6 17 | kProtoControlHardResetClientV2 = 7 18 | kProtoControlHardResetServerV2 = 8 19 | ) 20 | 21 | type sessionId [8]byte 22 | type ackArray []uint32 23 | 24 | type packet struct { 25 | opCode byte 26 | keyId byte 27 | localSid sessionId 28 | acks ackArray 29 | remoteSid sessionId 30 | id uint32 31 | content []byte 32 | } 33 | 34 | func decodeCommonHeader(buf []byte) *packet { 35 | if len(buf) < 2 { 36 | return nil 37 | } 38 | packet := &packet{ 39 | opCode: buf[0] >> 3, 40 | keyId: buf[0] & 0x07, 41 | } 42 | packet.content = make([]byte, len(buf)-1) 43 | copy(packet.content, buf[1:]) 44 | return packet 45 | } 46 | 47 | func sendDataPacket(conn *net.UDPConn, packet *packet) { 48 | buf := &bytes.Buffer{} 49 | 50 | // op code and key id 51 | buf.WriteByte((packet.opCode << 3) | (packet.keyId & 0x07)) 52 | 53 | // content 54 | buf.Write(packet.content) 55 | 56 | // sending 57 | _, err := conn.Write(buf.Bytes()) 58 | if err != nil { 59 | log.Fatalf("can't send packet to peer: %v", err) 60 | } 61 | } 62 | 63 | func encodeCtrlPacket(packet *packet) []byte { 64 | buf := &bytes.Buffer{} 65 | 66 | // op code and key id 67 | buf.WriteByte((packet.opCode << 3) | (packet.keyId & 0x07)) 68 | 69 | // local session id 70 | buf.Write(packet.localSid[:]) 71 | 72 | // acks 73 | buf.WriteByte(byte(len(packet.acks))) 74 | for i := 0; i < len(packet.acks); i++ { 75 | bufWriteUint32(buf, packet.acks[i]) 76 | } 77 | 78 | // remote session id 79 | if len(packet.acks) > 0 { 80 | buf.Write(packet.remoteSid[:]) 81 | } 82 | 83 | // packet id 84 | if packet.opCode != kProtoAckV1 { 85 | bufWriteUint32(buf, packet.id) 86 | } 87 | 88 | // content 89 | buf.Write(packet.content) 90 | 91 | return buf.Bytes() 92 | } 93 | 94 | func decodeCtrlPacket(packet *packet) *packet { 95 | buf := bytes.NewBuffer(packet.content) 96 | 97 | // remote session id 98 | _, err := io.ReadFull(buf, packet.localSid[:]) 99 | if err != nil { 100 | return nil 101 | } 102 | 103 | // ack array 104 | code, err := buf.ReadByte() 105 | if err != nil { 106 | return nil 107 | } 108 | nAcks := int(code) 109 | packet.acks = make([]uint32, nAcks) 110 | for i := 0; i < nAcks; i++ { 111 | packet.acks[i], err = bufReadUint32(buf) 112 | if err != nil { 113 | return nil 114 | } 115 | } 116 | 117 | // local session id 118 | if nAcks > 0 { 119 | _, err = io.ReadFull(buf, packet.remoteSid[:]) 120 | if err != nil { 121 | return nil 122 | } 123 | } 124 | 125 | // packet id 126 | if packet.opCode != kProtoAckV1 { 127 | packet.id, err = bufReadUint32(buf) 128 | if err != nil { 129 | return nil 130 | } 131 | } 132 | 133 | // content 134 | packet.content = buf.Bytes() 135 | 136 | return packet 137 | } 138 | -------------------------------------------------------------------------------- /opt/options.go: -------------------------------------------------------------------------------- 1 | package opt 2 | 3 | import ( 4 | "github.com/glacjay/govpn/utils" 5 | "log" 6 | "os" 7 | "strconv" 8 | ) 9 | 10 | const MAX_PARAMS = 16 11 | 12 | const GOVPN_PORT = 1194 13 | 14 | func usage() { 15 | log.Printf("[EROR] Usage: ...\n") 16 | os.Exit(1) 17 | } 18 | 19 | func usageVersion() { 20 | log.Printf("[INFO] Version: ...\n") 21 | os.Exit(0) 22 | } 23 | 24 | func stringDefinedEqual(s1, s2 string) bool { 25 | return s1 != "" && s2 != "" && s1 == s2 26 | } 27 | 28 | type Connection struct { 29 | LocalHost string 30 | LocalPort int 31 | RemoteHost string 32 | RemotePort int 33 | } 34 | 35 | type Options struct { 36 | Conn Connection 37 | 38 | IfconfigAddress string 39 | IfconfigNetmask string 40 | 41 | EnableOCC bool 42 | 43 | Verbosity uint 44 | Mute int 45 | } 46 | 47 | func NewOptions() *Options { 48 | o := new(Options) 49 | o.Conn.LocalPort = GOVPN_PORT 50 | o.Conn.RemotePort = GOVPN_PORT 51 | o.EnableOCC = true 52 | o.Verbosity = 1 53 | 54 | o.parseArgs() 55 | o.postProcess() 56 | return o 57 | } 58 | 59 | func (o *Options) parseArgs() { 60 | args := os.Args 61 | if len(args) < 1 { 62 | usage() 63 | } 64 | for i := 1; i < len(args); i++ { 65 | p := make([]string, 0, MAX_PARAMS) 66 | p = append(p, args[i]) 67 | if p[0][:2] != "--" { 68 | log.Printf("[WARN] I'm trying to parse '%s' as an option parameter but I don't see a leading '--'.", p[0]) 69 | } else { 70 | p[0] = p[0][2:] 71 | } 72 | var j int 73 | for j = 1; j < MAX_PARAMS; j++ { 74 | if i+j < len(args) { 75 | arg := args[i+j] 76 | if len(arg) < 2 || arg[:2] != "--" { 77 | p = append(p, arg) 78 | } else { 79 | break 80 | } 81 | } 82 | } 83 | o.AddOption(p) 84 | i += j - 1 85 | } 86 | } 87 | 88 | func (o *Options) postProcess() { 89 | o.postProcessVerify() 90 | } 91 | 92 | func (o *Options) postProcessVerify() { 93 | o.postProcessVerifyCe(&o.Conn) 94 | } 95 | 96 | func (o *Options) postProcessVerifyCe(Conn *Connection) { 97 | if stringDefinedEqual(Conn.LocalHost, Conn.RemoteHost) && 98 | Conn.LocalPort == Conn.RemotePort { 99 | log.Printf("[EROR] --remote and --local addresses are the same.") 100 | os.Exit(1) 101 | } 102 | if stringDefinedEqual(Conn.RemoteHost, o.IfconfigAddress) || 103 | stringDefinedEqual(Conn.RemoteHost, o.IfconfigNetmask) { 104 | log.Printf("[EROR] --remote address must be distinct from --ifconfig addresses.") 105 | os.Exit(1) 106 | } 107 | if stringDefinedEqual(Conn.LocalHost, o.IfconfigAddress) || 108 | stringDefinedEqual(Conn.LocalHost, o.IfconfigNetmask) { 109 | log.Printf("[EROR] --local address must be distinct from --ifconfig addresses.") 110 | os.Exit(1) 111 | } 112 | if stringDefinedEqual(o.IfconfigAddress, o.IfconfigNetmask) { 113 | log.Printf("[EROR] local and remote/netmask --ifconfig addresses must be different.") 114 | os.Exit(1) 115 | } 116 | } 117 | 118 | func (o *Options) OptionsString() string { 119 | out := "V4" 120 | if o.IfconfigAddress != "" { 121 | out += ",ifconfig " + o.ifconfigOptionsString() 122 | } 123 | return out 124 | } 125 | 126 | func (o *Options) ifconfigOptionsString() string { 127 | return utils.GetNetwork(o.IfconfigAddress, o.IfconfigNetmask) + " " + 128 | string(o.IfconfigNetmask) 129 | } 130 | 131 | func (o *Options) AddOption(p []string) { 132 | name := p[0] 133 | num := len(p) 134 | if name == "help" { 135 | usage() 136 | } else if name == "version" { 137 | usageVersion() 138 | } else if name == "ifconfig" && num > 2 { 139 | if utils.IsValidHost(p[1]) && utils.IsValidHost(p[2]) { 140 | o.IfconfigAddress = p[1] 141 | o.IfconfigNetmask = p[2] 142 | } else { 143 | log.Printf("[EROR] ifconfig params '%s' and '%s' must be valid addresses.", p[1], p[2]) 144 | return 145 | } 146 | } else if name == "remote" && num > 1 { 147 | o.Conn.RemoteHost = p[1] 148 | if num > 2 { 149 | port, err := strconv.Atoi(p[2]) 150 | if err != nil || !utils.IsValidPort(port) { 151 | log.Printf("[EROR] remote: port number associated with host %s is out of range.", p[1]) 152 | return 153 | } 154 | o.Conn.RemotePort = port 155 | } 156 | } else if name == "disable-occ" { 157 | o.EnableOCC = false 158 | } else if name == "verb" && num > 1 { 159 | o.Verbosity = uint(utils.PosAtoi(p[1])) 160 | } else if name == "mute" && num > 1 { 161 | o.Mute = utils.PosAtoi(p[1]) 162 | } else { 163 | log.Printf("[EROR] unrecognized option or missing parameter(s): --%s.", p[0]) 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /reliable_udp.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "crypto/rand" 6 | "io" 7 | "log" 8 | "net" 9 | "time" 10 | ) 11 | 12 | const ( 13 | kReliableRecvCacheSize = 8 14 | kReliableSendAcksCount = 4 15 | ) 16 | 17 | type reliableUdp struct { 18 | stopChan chan struct{} 19 | failChan <-chan time.Time 20 | doneHandshake chan struct{} 21 | 22 | ctrlSendChan chan *packet 23 | conn *net.UDPConn 24 | sendingPid uint32 25 | waitingAck map[uint32]chan<- struct{} 26 | 27 | ctrlRecvChan <-chan *packet 28 | recvedPackets [kReliableRecvCacheSize]*packet 29 | recvingPid uint32 30 | acks ackArray 31 | sslRecvChan chan *packet 32 | sslRecvBuf bytes.Buffer 33 | 34 | connected bool 35 | keyId byte 36 | localSid sessionId 37 | remoteSid sessionId 38 | } 39 | 40 | func dialReliableUdp(conn *net.UDPConn, ctrlRecvChan <-chan *packet) *reliableUdp { 41 | ru := &reliableUdp{ 42 | stopChan: make(chan struct{}), 43 | failChan: time.After(time.Minute), 44 | doneHandshake: make(chan struct{}), 45 | conn: conn, 46 | ctrlSendChan: make(chan *packet), 47 | waitingAck: make(map[uint32]chan<- struct{}), 48 | ctrlRecvChan: ctrlRecvChan, 49 | sslRecvChan: make(chan *packet), 50 | } 51 | io.ReadFull(rand.Reader, ru.localSid[:]) 52 | 53 | ru.start() 54 | ru.ctrlSendChan <- &packet{ 55 | opCode: kProtoControlHardResetClientV2, 56 | } 57 | 58 | return ru 59 | } 60 | 61 | func (ru *reliableUdp) start() { 62 | go func() { 63 | for { 64 | if !ru.iterate() { 65 | break 66 | } 67 | } 68 | }() 69 | } 70 | 71 | func (ru *reliableUdp) stop() { 72 | ru.stopChan <- struct{}{} 73 | } 74 | 75 | func (ru *reliableUdp) iterate() bool { 76 | var ackTimeout <-chan time.Time 77 | if len(ru.acks) > 0 { 78 | ackTimeout = time.After(time.Microsecond) 79 | } 80 | 81 | select { 82 | case <-ru.stopChan: 83 | return false 84 | 85 | case <-ru.failChan: 86 | log.Fatalf("can't negotiate with peer within 60 seconds") 87 | 88 | case <-ru.doneHandshake: 89 | ru.failChan = nil 90 | 91 | case packet := <-ru.ctrlRecvChan: 92 | ru.recvCtrlPacket(packet) 93 | 94 | case packet := <-ru.ctrlSendChan: 95 | packet.id = ru.sendingPid 96 | ru.sendingPid++ 97 | ru.waitingAck[packet.id] = ru.sendCtrlPacket(packet) 98 | 99 | case <-ackTimeout: 100 | ru.sendCtrlPacket(&packet{opCode: kProtoAckV1}) 101 | } 102 | 103 | return true 104 | } 105 | 106 | func (ru *reliableUdp) recvCtrlPacket(packet *packet) { 107 | packet = decodeCtrlPacket(packet) 108 | 109 | if packet.opCode != kProtoAckV1 { 110 | ru.acks = append(ru.acks, packet.id) 111 | } 112 | 113 | for _, ack := range packet.acks { 114 | if _, ok := ru.waitingAck[ack]; ok { 115 | ru.waitingAck[ack] <- struct{}{} 116 | delete(ru.waitingAck, ack) 117 | } 118 | } 119 | 120 | if packet.id-ru.recvingPid >= kReliableRecvCacheSize { 121 | return 122 | } 123 | if ru.recvedPackets[packet.id-ru.recvingPid] != nil { 124 | return 125 | } 126 | ru.recvedPackets[packet.id-ru.recvingPid] = packet 127 | 128 | switch packet.opCode { 129 | case kProtoControlHardResetServerV2: 130 | copy(ru.remoteSid[:], packet.localSid[:]) 131 | ru.connected = true 132 | 133 | case kProtoControlV1: 134 | i := 0 135 | for ru.recvedPackets[i] != nil { 136 | ru.sslRecvChan <- ru.recvedPackets[i] 137 | i++ 138 | ru.recvingPid++ 139 | } 140 | copy(ru.recvedPackets[:kReliableRecvCacheSize-i], ru.recvedPackets[i:]) 141 | } 142 | } 143 | 144 | func (ru *reliableUdp) sendCtrlPacket(packet *packet) chan<- struct{} { 145 | copy(packet.localSid[:], ru.localSid[:]) 146 | copy(packet.remoteSid[:], ru.remoteSid[:]) 147 | 148 | nAck := len(ru.acks) 149 | if nAck > kReliableSendAcksCount { 150 | nAck = kReliableSendAcksCount 151 | } 152 | packet.acks = make(ackArray, nAck) 153 | copy(packet.acks, ru.acks) 154 | 155 | _, err := ru.conn.Write(encodeCtrlPacket(packet)) 156 | if err != nil { 157 | log.Fatalf("can't send packet to peer: %v", err) 158 | } 159 | 160 | ru.acks = ru.acks[nAck:] 161 | 162 | if packet.opCode != kProtoAckV1 { 163 | packet.acks = nil 164 | return startRetrySendCtrlPacket(ru.conn, packet) 165 | } 166 | 167 | return nil 168 | } 169 | 170 | func startRetrySendCtrlPacket(conn *net.UDPConn, packet *packet) chan<- struct{} { 171 | stopChan := make(chan struct{}) 172 | buf := encodeCtrlPacket(packet) 173 | go func() { 174 | totalSeconds := 0 175 | for i := 1; totalSeconds < 60; i *= 2 { 176 | totalSeconds += i 177 | select { 178 | case <-stopChan: 179 | return 180 | case <-time.After(time.Duration(i) * time.Second): 181 | _, err := conn.Write(buf) 182 | if err != nil { 183 | log.Fatalf("can't send packet to peer: %v", err) 184 | } 185 | } 186 | } 187 | log.Fatalf("can't negotiate with peer within 60 seconds: %v", packet.id) 188 | }() 189 | return stopChan 190 | } 191 | 192 | func (ru *reliableUdp) Close() error { return nil } 193 | func (ru *reliableUdp) LocalAddr() net.Addr { return nil } 194 | func (ru *reliableUdp) RemoteAddr() net.Addr { return nil } 195 | func (ru *reliableUdp) SetDeadline(t time.Time) error { return nil } 196 | func (ru *reliableUdp) SetReadDeadline(t time.Time) error { return nil } 197 | func (ru *reliableUdp) SetWriteDeadline(t time.Time) error { return nil } 198 | 199 | func (ru *reliableUdp) Read(b []byte) (n int, err error) { 200 | for ru.sslRecvBuf.Len() == 0 { 201 | packet := <-ru.sslRecvChan 202 | ru.sslRecvBuf.Write(packet.content) 203 | } 204 | return ru.sslRecvBuf.Read(b) 205 | } 206 | 207 | func (ru *reliableUdp) Write(b []byte) (n int, err error) { 208 | buf := make([]byte, len(b)) 209 | copy(buf, b) 210 | packet := &packet{ 211 | opCode: kProtoControlV1, 212 | content: buf, 213 | } 214 | ru.ctrlSendChan <- packet 215 | return len(b), nil 216 | } 217 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "crypto/aes" 7 | "crypto/cipher" 8 | "crypto/hmac" 9 | "crypto/rand" 10 | "crypto/sha1" 11 | "flag" 12 | "fmt" 13 | "hash" 14 | "io" 15 | "log" 16 | "net" 17 | "os" 18 | "strconv" 19 | "strings" 20 | 21 | "github.com/glacjay/govpn/tun" 22 | ) 23 | 24 | var ( 25 | flagVirtAddr = flag.String("virt-addr", "10.8.0.1/24", "virtual IP address of my TUN/TAP device") 26 | flagRemoteHost = flag.String("remote-host", "localhost", "remote peer's hostname or IP address") 27 | flagSecretFile = flag.String("secret-file", "", "name of file which contains static secret keys") 28 | flagSecretDir = flag.Int("secret-direction", -1, "direction of static secret keys: 0 for normal, 1 for inverse, and default (unset) for bidirectional") 29 | ) 30 | 31 | const ( 32 | maxCipherKeyLen = 64 33 | maxHMacKeyLen = 64 34 | 35 | staticKeyHead = "-----BEGIN OpenVPN Static key V1-----" 36 | staticKeyFoot = "-----END OpenVPN Static key V1-----" 37 | ) 38 | 39 | type key2 struct { 40 | count int 41 | keys [2]key 42 | encI int 43 | decI int 44 | } 45 | 46 | type key struct { 47 | cipher [maxCipherKeyLen]byte 48 | hmac [maxHMacKeyLen]byte 49 | } 50 | 51 | func _main() { 52 | flag.Parse() 53 | 54 | var encCipher, decCipher cipher.Block 55 | var encHmac, decHmac hash.Hash 56 | if *flagSecretFile != "" { 57 | var err error 58 | keys := initKeysWithSecretFile(*flagSecretFile, *flagSecretDir) 59 | encCipher, err = aes.NewCipher(keys.keys[keys.encI].cipher[:32]) 60 | if err != nil { 61 | log.Fatalf("Failed to create AES256 cipher for encryption: %v", err) 62 | } 63 | encHmac = hmac.New(sha1.New, keys.keys[keys.encI].hmac[:20]) 64 | decCipher, err = aes.NewCipher(keys.keys[keys.decI].cipher[:32]) 65 | if err != nil { 66 | log.Fatalf("Failed to create AES256 cipher for decryption: %v", err) 67 | } 68 | decHmac = hmac.New(sha1.New, keys.keys[keys.decI].hmac[:20]) 69 | } 70 | 71 | remoteAddrs, err := net.LookupIP(*flagRemoteHost) 72 | if err != nil || len(remoteAddrs) == 0 { 73 | log.Fatalf("Failed to resolve remote's hostname or address: %v", err) 74 | } 75 | conn, err := net.DialUDP("udp", nil, &net.UDPAddr{IP: remoteAddrs[0], Port: 1194}) 76 | if err != nil { 77 | log.Fatalf("Failed to connect to remote's UDP port: %v", err) 78 | } 79 | defer conn.Close() 80 | 81 | tokens := strings.Split(*flagVirtAddr, "/") 82 | if len(tokens) < 2 { 83 | log.Fatalf("Malformed virt-addr: %s", *flagVirtAddr) 84 | } 85 | virtMaskOnes, err := strconv.ParseUint(tokens[1], 10, 8) 86 | if err != nil { 87 | log.Fatalf("Malformed virt-mask: %s", *flagVirtAddr) 88 | } 89 | virtAddr := tokens[0] 90 | virtMask := net.IP(net.CIDRMask(int(virtMaskOnes), 32)).String() 91 | 92 | tunDevice := tun.New() 93 | tunDevice.Open() 94 | tunDevice.SetupAddress(virtAddr, virtMask) 95 | tunDevice.Start() 96 | 97 | sendNetCh := startSendingNet(conn) 98 | recvNetCh := startRecvingNet(conn) 99 | for { 100 | select { 101 | case packet := <-tunDevice.ReadCh: 102 | if encCipher != nil { 103 | packet = encrypt(encCipher, packet) 104 | } 105 | if encHmac != nil { 106 | packet = sign(encHmac, packet) 107 | } 108 | sendNetCh <- packet 109 | case packet := <-recvNetCh: 110 | if decHmac != nil { 111 | var valid bool 112 | packet, valid = verify(decHmac, packet) 113 | if !valid { 114 | log.Printf("hmac authentication failed") 115 | continue 116 | } 117 | } 118 | if decCipher != nil { 119 | packet = decrypt(decCipher, packet) 120 | } 121 | tunDevice.WriteCh <- packet 122 | } 123 | } 124 | } 125 | 126 | func startSendingNet(conn *net.UDPConn) chan<- []byte { 127 | ch := make(chan []byte) 128 | go func() { 129 | for { 130 | packet := <-ch 131 | _, err := conn.Write(packet) 132 | if err != nil { 133 | log.Printf("[EROR] Failed to write to UDP socket: %v", err) 134 | return 135 | } 136 | } 137 | }() 138 | return ch 139 | } 140 | 141 | func startRecvingNet(conn *net.UDPConn) <-chan []byte { 142 | ch := make(chan []byte) 143 | var buf [4096]byte 144 | go func() { 145 | for { 146 | nread, err := conn.Read(buf[:]) 147 | if nread > 0 { 148 | packet := make([]byte, nread) 149 | copy(packet, buf[:nread]) 150 | ch <- packet 151 | } 152 | if nread == 0 { 153 | return 154 | } 155 | if err != nil { 156 | log.Printf("[EROR] Failed to read from UDP socket: %v", err) 157 | return 158 | } 159 | } 160 | }() 161 | return ch 162 | } 163 | 164 | func readSecretFile(filename string) []byte { 165 | file, err := os.Open(*flagSecretFile) 166 | if err != nil { 167 | log.Fatalf("Failed to open secret file '%s': %v", *flagSecretFile, err) 168 | } 169 | scanner := bufio.NewScanner(file) 170 | inData := false 171 | content := &bytes.Buffer{} 172 | lineno := 0 173 | for scanner.Scan() { 174 | lineno++ 175 | if scanner.Text() == staticKeyHead { 176 | inData = true 177 | continue 178 | } 179 | if scanner.Text() == staticKeyFoot { 180 | break 181 | } 182 | if inData { 183 | if len(scanner.Text())%2 == 1 { 184 | log.Fatalf("Malformed secret file: line %d has odd characters", lineno) 185 | } 186 | for i := 0; i < len(scanner.Text()); i += 2 { 187 | var c byte 188 | _, err := fmt.Sscanf(scanner.Text()[i:i+2], "%02x", &c) 189 | if err != nil { 190 | log.Fatalf("Malformed secret file: line %d has invalid hex numbers", lineno) 191 | } 192 | content.WriteByte(c) 193 | } 194 | } 195 | } 196 | return content.Bytes() 197 | } 198 | 199 | func initKeysWithSecretFile(filename string, direction int) *key2 { 200 | content := readSecretFile(filename) 201 | keys := &key2{count: len(content) / (maxCipherKeyLen + maxHMacKeyLen)} 202 | index := 0 203 | for i := 0; i < keys.count; i++ { 204 | copy(keys.keys[i].cipher[:maxCipherKeyLen], content[index:index+maxCipherKeyLen]) 205 | index += maxCipherKeyLen 206 | copy(keys.keys[i].hmac[:maxHMacKeyLen], content[index:index+maxHMacKeyLen]) 207 | index += maxHMacKeyLen 208 | } 209 | switch direction { 210 | case -1: 211 | if keys.count < 1 { 212 | log.Fatal("Malformed secret file: contains less than 1 complete key for bidirection") 213 | } 214 | keys.encI = 0 215 | keys.decI = 0 216 | case 0: 217 | if keys.count < 2 { 218 | log.Fatal("Malformed secret file: contains less than 2 complete key for normal direction") 219 | } 220 | keys.encI = 0 221 | keys.decI = 1 222 | case 1: 223 | if keys.count < 2 { 224 | log.Fatal("Malformed secret file: contains less than 2 complete key for inverse direction") 225 | } 226 | keys.encI = 1 227 | keys.decI = 0 228 | default: 229 | log.Fatal("Invalid direction setup: %v", *flagSecretDir) 230 | } 231 | return keys 232 | } 233 | 234 | func encrypt(encCipher cipher.Block, plain []byte) []byte { 235 | plainlen := len(plain) 236 | paddinglen := encCipher.BlockSize() - plainlen%encCipher.BlockSize() 237 | for i := 0; i < paddinglen; i++ { 238 | plain = append(plain, byte(paddinglen)) 239 | } 240 | iv := make([]byte, encCipher.BlockSize()) 241 | io.ReadFull(rand.Reader, iv) 242 | enc := cipher.NewCBCEncrypter(encCipher, iv) 243 | enc.CryptBlocks(plain, plain) 244 | return append(iv, plain...) 245 | } 246 | 247 | func decrypt(decCipher cipher.Block, encrypted []byte) []byte { 248 | iv := encrypted[:decCipher.BlockSize()] 249 | plain := encrypted[decCipher.BlockSize():] 250 | dec := cipher.NewCBCDecrypter(decCipher, iv) 251 | dec.CryptBlocks(plain, plain) 252 | return plain[:len(plain)-int(plain[len(plain)-1])] 253 | } 254 | 255 | func sign(encHmac hash.Hash, origin []byte) []byte { 256 | encHmac.Reset() 257 | encHmac.Write(origin) 258 | hmac := make([]byte, 0) 259 | hmac = encHmac.Sum(hmac) 260 | return append(hmac, origin...) 261 | } 262 | 263 | func verify(decHmac hash.Hash, signed []byte) ([]byte, bool) { 264 | remoteHmac := signed[:decHmac.Size()] 265 | origin := signed[decHmac.Size():] 266 | decHmac.Reset() 267 | decHmac.Write(origin) 268 | localHmac := make([]byte, 0) 269 | localHmac = decHmac.Sum(localHmac) 270 | return origin, bytes.Equal(remoteHmac, localHmac) 271 | } 272 | -------------------------------------------------------------------------------- /ssl.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "crypto/aes" 6 | "crypto/cipher" 7 | "crypto/hmac" 8 | "crypto/md5" 9 | "crypto/rand" 10 | "crypto/sha1" 11 | "crypto/tls" 12 | "crypto/x509" 13 | "encoding/binary" 14 | "flag" 15 | "hash" 16 | "io" 17 | "io/ioutil" 18 | "log" 19 | "net" 20 | "sync/atomic" 21 | "time" 22 | ) 23 | 24 | type udpReceiver struct { 25 | conn *net.UDPConn 26 | stopFlag uint32 27 | ctrlChan chan<- *packet 28 | dataChan chan<- *packet 29 | } 30 | 31 | func (ur *udpReceiver) start() { 32 | go func() { 33 | for { 34 | if !ur.iterate() { 35 | break 36 | } 37 | } 38 | }() 39 | } 40 | 41 | func (ur *udpReceiver) stop() { 42 | atomic.StoreUint32(&ur.stopFlag, 1) 43 | ur.conn.Close() 44 | } 45 | 46 | func (ur *udpReceiver) iterate() bool { 47 | var buf [2048]byte 48 | nr, err := ur.conn.Read(buf[:]) 49 | if err != nil { 50 | if stopFlag := atomic.LoadUint32(&ur.stopFlag); stopFlag == 1 { 51 | return false 52 | } 53 | if netErr, ok := err.(net.Error); ok { 54 | if netErr.Temporary() { 55 | log.Printf("ERROR udp recv: %v", netErr) 56 | return true 57 | } else { 58 | log.Fatalf("FATAL udp recv: %v", netErr) 59 | } 60 | } else { 61 | log.Fatalf("FATAL udp recv: %v", err) 62 | } 63 | } 64 | 65 | packet := decodeCommonHeader(buf[:nr]) 66 | if packet != nil { 67 | if packet.opCode == kProtoDataV1 { 68 | ur.dataChan <- packet 69 | } else { 70 | ur.ctrlChan <- packet 71 | } 72 | } 73 | 74 | return true 75 | } 76 | 77 | type keys struct { 78 | encryptCipher [16]byte 79 | encryptDigest [20]byte 80 | decryptCipher [16]byte 81 | decryptDigest [20]byte 82 | } 83 | 84 | type dataTransporter struct { 85 | conn *net.UDPConn 86 | stopChan chan struct{} 87 | 88 | cipherRecvChan <-chan *packet 89 | plainSendChan chan<- []byte 90 | plainRecvChan <-chan []byte 91 | 92 | keys *keys 93 | } 94 | 95 | func (dt *dataTransporter) start() { 96 | go func() { 97 | for { 98 | if !dt.iterate() { 99 | break 100 | } 101 | } 102 | }() 103 | } 104 | 105 | func (dt *dataTransporter) stop() { 106 | dt.stopChan <- struct{}{} 107 | } 108 | 109 | func (dt *dataTransporter) iterate() bool { 110 | select { 111 | case <-dt.stopChan: 112 | return false 113 | 114 | case packet := <-dt.cipherRecvChan: 115 | plain := dt.decrypt(packet.content) 116 | dt.plainSendChan <- plain 117 | 118 | case plain := <-dt.plainRecvChan: 119 | packet := &packet{ 120 | opCode: kProtoDataV1, 121 | content: dt.encrypt(plain), 122 | } 123 | sendDataPacket(dt.conn, packet) 124 | } 125 | 126 | return true 127 | } 128 | 129 | func (dt *dataTransporter) decrypt(content []byte) []byte { 130 | hasher := hmac.New(sha1.New, dt.keys.decryptDigest[:]) 131 | if len(content) < hasher.Size() { 132 | log.Printf("ERROR plain size too small") 133 | return nil 134 | } 135 | hasher.Write(content[hasher.Size():]) 136 | sig := hasher.Sum(nil) 137 | if !bytes.Equal(sig, content[:hasher.Size()]) { 138 | log.Printf("ERROR invalid signature") 139 | return nil 140 | } 141 | content = content[hasher.Size():] 142 | 143 | iv := content[:16] 144 | content = content[16:] 145 | blocker, _ := aes.NewCipher(dt.keys.decryptCipher[:]) 146 | decrypter := cipher.NewCBCDecrypter(blocker, iv) 147 | plain := make([]byte, len(content)) 148 | decrypter.CryptBlocks(plain, content) 149 | 150 | //packetId := binary.BigEndian.Uint32(plain[:4]) 151 | //plain = plain[4:] 152 | paddingLen := int(plain[len(plain)-1]) 153 | if paddingLen > len(plain) { 154 | log.Printf("ERROR invalid padding") 155 | return nil 156 | } 157 | plain = plain[:len(plain)-paddingLen] 158 | 159 | return plain 160 | } 161 | 162 | func (dt *dataTransporter) encrypt(plain []byte) []byte { 163 | paddingLen := 16 - len(plain)%16 164 | if paddingLen == 0 { 165 | paddingLen = 16 166 | } 167 | 168 | content := make([]byte, 20+16+len(plain)+paddingLen) 169 | iv := content[20:36] 170 | io.ReadFull(rand.Reader, iv) 171 | copy(content[20+16:], plain) 172 | for i := 0; i < paddingLen; i++ { 173 | content[i+20+16+len(plain)] = byte(paddingLen) 174 | } 175 | blocker, _ := aes.NewCipher(dt.keys.encryptCipher[:]) 176 | encrypter := cipher.NewCBCEncrypter(blocker, iv) 177 | encrypter.CryptBlocks(content[20+16:], content[20+16:]) 178 | 179 | hasher := hmac.New(sha1.New, dt.keys.encryptDigest[:]) 180 | hasher.Write(content[20:]) 181 | copy(content[:20], hasher.Sum(nil)) 182 | 183 | return content 184 | } 185 | 186 | type tlsTransporter struct { 187 | stopChan chan struct{} 188 | 189 | reliableUdp *reliableUdp 190 | conn *tls.Conn 191 | 192 | keysChan chan<- *keys 193 | sendChan <-chan string 194 | recvChan chan<- string 195 | } 196 | 197 | func newTlsTransporter(reliableUdp *reliableUdp, keysChan chan<- *keys, 198 | sendChan <-chan string, recvChan chan<- string) *tlsTransporter { 199 | 200 | return &tlsTransporter{ 201 | stopChan: make(chan struct{}), 202 | reliableUdp: reliableUdp, 203 | keysChan: keysChan, 204 | sendChan: sendChan, 205 | recvChan: recvChan, 206 | } 207 | } 208 | 209 | func (tt *tlsTransporter) start() { 210 | tt.handshake() 211 | go func() { 212 | for { 213 | if !tt.iterate() { 214 | break 215 | } 216 | } 217 | }() 218 | } 219 | 220 | func (tt *tlsTransporter) stop() { 221 | tt.stopChan <- struct{}{} 222 | } 223 | 224 | type keySource2 struct { 225 | preMaster [48]byte 226 | random1 [32]byte 227 | random2 [32]byte 228 | } 229 | 230 | func (tt *tlsTransporter) handshake() { 231 | caCertFileContent, err := ioutil.ReadFile("test/ca.cer") 232 | if err != nil { 233 | log.Fatalf("can't read ca cert file: %v", err) 234 | } 235 | caCerts := x509.NewCertPool() 236 | ok := caCerts.AppendCertsFromPEM(caCertFileContent) 237 | if !ok { 238 | log.Fatalf("can't parse ca cert file") 239 | } 240 | 241 | clientCert, err := tls.LoadX509KeyPair("test/client.pem", "test/client.pem") 242 | if err != nil { 243 | log.Fatalf("can't load client cert and key: %v", err) 244 | } 245 | 246 | tlsConfig := &tls.Config{ 247 | Certificates: []tls.Certificate{clientCert}, 248 | RootCAs: caCerts, 249 | InsecureSkipVerify: true, 250 | } 251 | tt.conn = tls.Client(tt.reliableUdp, tlsConfig) 252 | err = tt.conn.Handshake() 253 | if err != nil { 254 | log.Fatalf("can't handshake tls with remote: %v", err) 255 | } 256 | tt.reliableUdp.doneHandshake <- struct{}{} 257 | 258 | localKeySource := &keySource2{} 259 | remoteKeySource := &keySource2{} 260 | 261 | // openvpn client send key 262 | buf := &bytes.Buffer{} 263 | // uint32 0 264 | buf.Write([]byte{0, 0, 0, 0}) 265 | // key method 266 | buf.WriteByte(2) 267 | // key material 268 | io.ReadFull(rand.Reader, localKeySource.preMaster[:]) 269 | buf.Write(localKeySource.preMaster[:]) 270 | io.ReadFull(rand.Reader, localKeySource.random1[:]) 271 | buf.Write(localKeySource.random1[:]) 272 | io.ReadFull(rand.Reader, localKeySource.random2[:]) 273 | buf.Write(localKeySource.random2[:]) 274 | // options string 275 | optionsString := "V4,dev-type tun,link-mtu 1541,tun-mtu 1500,proto UDPv4,cipher AES-128-CBC,auth SHA1,keysize 128,key-method 2,tls-client" 276 | lenBuf := make([]byte, 2) 277 | binary.BigEndian.PutUint16(lenBuf, uint16(len(optionsString)+1)) 278 | buf.Write(lenBuf) 279 | buf.WriteString(optionsString) 280 | buf.WriteByte(0) 281 | // username and password 282 | buf.Write([]byte{0, 0, 0, 0}) 283 | _, err = tt.conn.Write(buf.Bytes()) 284 | if err != nil { 285 | log.Fatalf("can't send key to remote: %v", err) 286 | } 287 | 288 | recvBuf := make([]byte, 1024) 289 | _, err = tt.conn.Read(recvBuf) 290 | if err != nil { 291 | log.Fatalf("can't get key from remote: %v", err) 292 | } 293 | //copy(remoteKeySource.preMaster[:], recvBuf[5:53]) 294 | copy(remoteKeySource.random1[:], recvBuf[5:37]) 295 | copy(remoteKeySource.random2[:], recvBuf[37:69]) 296 | 297 | master := make([]byte, 48) 298 | prf(localKeySource.preMaster[:], "OpenVPN master secret", 299 | localKeySource.random1[:], remoteKeySource.random1[:], 300 | nil, nil, master) 301 | keyBuf := make([]byte, 256) 302 | prf(master, "OpenVPN key expansion", 303 | localKeySource.random2[:], remoteKeySource.random2[:], 304 | tt.reliableUdp.localSid[:], tt.reliableUdp.remoteSid[:], keyBuf) 305 | 306 | keys := &keys{} 307 | copy(keys.encryptCipher[:], keyBuf[:16]) 308 | copy(keys.encryptDigest[:], keyBuf[64:84]) 309 | copy(keys.decryptCipher[:], keyBuf[128:144]) 310 | copy(keys.decryptDigest[:], keyBuf[192:212]) 311 | tt.keysChan <- keys 312 | 313 | log.Printf("done negotiate initial keys") 314 | } 315 | 316 | func (tt *tlsTransporter) iterate() bool { 317 | time.Sleep(time.Second) 318 | return true 319 | } 320 | 321 | type client struct { 322 | peerAddr string 323 | conn *net.UDPConn 324 | 325 | plainSendChan chan []byte 326 | plainRecvChan chan []byte 327 | 328 | udpRecv *udpReceiver 329 | reliableUdp *reliableUdp 330 | tlsTrans *tlsTransporter 331 | dataTrans *dataTransporter 332 | } 333 | 334 | func newClient(peerAddr string) *client { 335 | c := &client{ 336 | peerAddr: peerAddr, 337 | plainSendChan: make(chan []byte), 338 | plainRecvChan: make(chan []byte), 339 | } 340 | return c 341 | } 342 | 343 | func (c *client) start() { 344 | addr, err := net.ResolveUDPAddr("udp", c.peerAddr) 345 | if err != nil { 346 | log.Fatalf("can't resolve peer addr '%s': %v", c.peerAddr, err) 347 | } 348 | c.conn, err = net.DialUDP("udp", nil, addr) 349 | if err != nil { 350 | log.Fatalf("can't connect to peer: %v", err) 351 | } 352 | 353 | ciphertextRecvChan := make(chan *packet) 354 | ctrlRecvChan := make(chan *packet) 355 | c.udpRecv = &udpReceiver{ 356 | conn: c.conn, 357 | dataChan: ciphertextRecvChan, 358 | ctrlChan: ctrlRecvChan, 359 | } 360 | c.udpRecv.start() 361 | 362 | c.reliableUdp = dialReliableUdp(c.conn, ctrlRecvChan) 363 | 364 | keysChan := make(chan *keys, 1) 365 | c.tlsTrans = newTlsTransporter(c.reliableUdp, keysChan, nil, nil) 366 | c.tlsTrans.start() 367 | keys := <-keysChan 368 | 369 | c.dataTrans = &dataTransporter{ 370 | conn: c.conn, 371 | stopChan: make(chan struct{}), 372 | cipherRecvChan: ciphertextRecvChan, 373 | plainSendChan: c.plainSendChan, 374 | plainRecvChan: c.plainRecvChan, 375 | keys: keys, 376 | } 377 | c.dataTrans.start() 378 | 379 | for { 380 | plain := <-c.plainSendChan 381 | log.Printf("recv from server: %#v", plain) 382 | c.plainRecvChan <- plain 383 | } 384 | } 385 | 386 | func prf(secret []byte, label string, clientSeed, serverSeed []byte, clientSid, serverSid []byte, result []byte) { 387 | seed := &bytes.Buffer{} 388 | seed.WriteString(label) 389 | seed.Write(clientSeed) 390 | seed.Write(serverSeed) 391 | if clientSid != nil { 392 | seed.Write(clientSid) 393 | } 394 | if serverSid != nil { 395 | seed.Write(serverSid) 396 | } 397 | tls1Prf(seed.Bytes(), secret, result) 398 | } 399 | 400 | func tls1Prf(label, secret []byte, result []byte) { 401 | out2 := make([]byte, len(result)) 402 | 403 | length := len(secret) / 2 404 | s1 := secret[:length] 405 | s2 := secret[length:] 406 | tls1Phash(md5.New, s1, label, result) 407 | tls1Phash(sha1.New, s2, label, out2) 408 | for i := 0; i < len(result); i++ { 409 | result[i] ^= out2[i] 410 | } 411 | } 412 | 413 | func tls1Phash(hasher func() hash.Hash, secret, seed []byte, result []byte) { 414 | hasher1 := hmac.New(hasher, secret) 415 | hasher1.Write(seed) 416 | a1 := hasher1.Sum(nil) 417 | 418 | for { 419 | hasher1 := hmac.New(hasher, secret) 420 | hasher2 := hmac.New(hasher, secret) 421 | hasher1.Write(a1) 422 | hasher2.Write(a1) 423 | hasher1.Write(seed) 424 | if len(result) > hasher1.Size() { 425 | out := hasher1.Sum(nil) 426 | copy(result, out) 427 | result = result[len(out):] 428 | a1 = hasher2.Sum(nil) 429 | } else { 430 | a1 = hasher1.Sum(nil) 431 | copy(result, a1) 432 | break 433 | } 434 | } 435 | } 436 | 437 | func main() { 438 | remoteEndpoint := flag.String("remote", "127.0.0.1:1194", "remote server address and port") 439 | flag.Parse() 440 | c := newClient(*remoteEndpoint) 441 | log.Printf("client start") 442 | c.start() 443 | } 444 | --------------------------------------------------------------------------------