├── Godeps ├── Godeps.json └── Readme ├── LICENSE ├── README.md ├── client.go ├── cmd ├── crowbar-forward │ └── main.go └── crowbard │ ├── auth.go │ ├── main.go │ └── worker.go ├── proto.go └── vendor └── github.com └── pborman └── uuid ├── .travis.yml ├── CONTRIBUTING.md ├── CONTRIBUTORS ├── LICENSE ├── README.md ├── dce.go ├── doc.go ├── hash.go ├── json.go ├── node.go ├── sql.go ├── time.go ├── util.go ├── uuid.go ├── version1.go └── version4.go /Godeps/Godeps.json: -------------------------------------------------------------------------------- 1 | { 2 | "ImportPath": "github.com/q3k/crowbar", 3 | "GoVersion": "go1.6", 4 | "GodepVersion": "v74", 5 | "Packages": [ 6 | "./..." 7 | ], 8 | "Deps": [ 9 | { 10 | "ImportPath": "github.com/pborman/uuid", 11 | "Comment": "v1.0-11-gc55201b", 12 | "Rev": "c55201b036063326c5b1b89ccfe45a184973d073" 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /Godeps/Readme: -------------------------------------------------------------------------------- 1 | This directory tree is generated automatically by godep. 2 | 3 | Please do not edit. 4 | 5 | See https://github.com/tools/godep for more information. 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, Segiusz 'q3k' Bazanski 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, 9 | this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 18 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 20 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 23 | OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Crowbar 2 | ======= 3 | 4 | When a [corkscrew](http://www.agroman.net/corkscrew/) just isn't enough... 5 | 6 | Intro 7 | ----- 8 | 9 | ![Crowbar overview](http://q3k.org/crowbar-overview.png) 10 | 11 | Crowbar is an **EXPERIMENTAL** tool that allows you to establish a secure circuit with your existing encrypting TCP endpoints (an OpenVPN setup, an SSH server for forwarding...) when your network connection is limited by a Web proxy that only allows basic port 80 HTTP connectivity. 12 | 13 | Crowbar will tunnel TCP connections over an HTTP session using only GET and POST requests. This is in contrast to most tunneling systems that reuse the CONNECT verb. It also provides basic authentication to make sure nobody who stumbles upon the server steals your proxy to order drugs from Silkroad. 14 | 15 | Features 16 | -------- 17 | 18 | - Establishes TCP connections via a proxy server using only HTTP GET and POST requests 19 | - Authenticates users from an authentication file 20 | - Will probably get you fired if you use this in an office setting 21 | 22 | Security & Confidentiality 23 | -------------------------- 24 | 25 | Crowbar **DOES NOT PROVIDE ANY DATA CONFIDENTIALITY**. While the user authentication mechanism protects from replay attacks to establish connectivity, it will not prevent someone from MITMing the later connection transfer itself, or from MITMing whole sessions. So, yeah, make sure to **use it only tunnel an SSH or OpenVPN server**, and **firewall off most outgoing connections on your proxy server** (ie. only allow access to an already publicly-available SSH server) 26 | 27 | The authentication code and crypto have not been reviewed by cryptographers. I am not a cryptographer. You should consider this when deploying Crowbar. 28 | 29 | Known bugs 30 | ---------- 31 | 32 | The crypto can be improved vastly to enable server authentication and make MITMing more difficult. It could also use a better authentication setup to allow the server to keep password hashes instead of plaintext. 33 | 34 | The server should include some filtering functionality for allowed remote connections. 35 | 36 | The server lacks any cleanup functions and rate limiting, so it will leak both descriptors and memory - this should be fixed soon. 37 | 38 | Is it any good? 39 | --------------- 40 | 41 | Eh, it works. I'm not an experienced Golang programmer though, so the codebase is probably butt-ugly. 42 | 43 | License 44 | ------- 45 | 46 | BSD 2-clause, 'nuff said. 47 | 48 | Usage 49 | ===== 50 | 51 | Binary releases 52 | --------------- 53 | 54 | Release and snapshot binaries can be downloaded from [this project's Github Releases page](https://github.com/q3k/crowbar/releases). 55 | 56 | Server setup 57 | ------------ 58 | 59 | This assumes you're using Linux. If not, you're on your own. 60 | 61 | Set up an user for the service 62 | 63 | useradd -rm crowbar 64 | mkdir /etc/crowbar/ 65 | chown crowbar:crowbar /etc/crowbar 66 | 67 | Create an authentication file - a new-line delimited file containing username:password pairs. 68 | 69 | touch /etc/crowbar/userfile 70 | chown crowbar:crowbar /etc/crowbar/userfile 71 | chmod 600 /etc/crowbar/userfile 72 | echo -ne "q3k:supersecurepassword\n1337h4xx0r:canttouchthis" >> /etc/crowbar/userfile 73 | 74 | Set up an iptables rule to forward traffic from the :80 port to :8080, where the server will be running. Replace eth0 with your public network interface. 75 | 76 | iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to-port 8080 77 | 78 | Run the daemon in screen/tmux or write some unit files for your distribution: 79 | 80 | crowbard -userfile=/etc/crowbar/userfile 81 | 82 | Client setup 83 | ------------ 84 | 85 | This assumes you're running Linux on your personal computer. If not, you're on your own. 86 | 87 | Crowbar will honor the _de-facto_ standard HTTP\_PROXY env var on Linux: 88 | 89 | export HTTP_PROXY=evil.company.proxy.com:80 90 | 91 | For netcat-like functionality: 92 | 93 | crowbar-forward -local=- -username q3k -password secret -server http://your.proxy.server.com:80 -remote towel.blinkenlights.nl:23 94 | 95 | For port-forwarding: 96 | 97 | 98 | crowbar-forward -local=127.0.0.1:1337 -username q3k -password secret -server http://your.proxy.server.com:80 -remote towel.blinkenlights.nl:23 & 99 | nc 127.0.0.1 1337 100 | 101 | 102 | For SSH ProxyCommand integration, place this in your .ssh/config, and then SSH into your.ssh.host.com as usual: 103 | 104 | Host your.ssh.host.com 105 | ProxyCommand crowbar-forward -local=- -username q3k -password secret -server http://your.proxy.server.com:80 -remote %h:%p 106 | 107 | Building from source 108 | -------------------- 109 | 110 | I assume you have a working $GOPATH. 111 | 112 | go get github.com/q3k/crowbar/... 113 | 114 | crowbar-forward and crowbard will be in $GOPATH/bin. 115 | 116 | -------------------------------------------------------------------------------- /client.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, Segiusz 'q3k' Bazanski 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // 1. Redistributions of source code must retain the above copyright notice, 9 | // this list of conditions and the following disclaimer. 10 | // 2. Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer in the 12 | // documentation and/or other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 18 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | // POSSIBILITY OF SUCH DAMAGE. 25 | 26 | package crowbar 27 | 28 | import ( 29 | "errors" 30 | "fmt" 31 | "io/ioutil" 32 | "net/http" 33 | "net/url" 34 | "strings" 35 | "sync" 36 | "encoding/base64" 37 | "crypto/hmac" 38 | "crypto/sha256" 39 | ) 40 | 41 | type ProxyConnection struct { 42 | uuid string 43 | server string 44 | read_buffer []byte 45 | read_mutex sync.Mutex 46 | } 47 | 48 | func (c *ProxyConnection) Write(b []byte) (int, error) { 49 | url_args := fmt.Sprintf("?uuid=" + c.uuid) 50 | post_args := url.Values{} 51 | post_args.Set("data", base64.StdEncoding.EncodeToString(b)) 52 | 53 | resp, err := http.PostForm(c.server + EndpointSync + url_args, post_args) 54 | if err != nil { 55 | return 0, err 56 | } 57 | data_bytes, err := ioutil.ReadAll(resp.Body) 58 | if err != nil { 59 | return 0, err 60 | } 61 | defer resp.Body.Close() 62 | data := string(data_bytes) 63 | 64 | if !strings.HasPrefix(data, PrefixOK) { 65 | msg := fmt.Sprintf("Could not send to server: %s", data) 66 | return 0, errors.New(msg) 67 | } 68 | 69 | return len(b), nil 70 | } 71 | 72 | func (c *ProxyConnection) FillReadBuffer() error { 73 | args := fmt.Sprintf("?uuid=" + c.uuid) 74 | resp, err := http.Get(c.server + EndpointSync + args) 75 | if err != nil { 76 | return err 77 | } 78 | data_bytes, err := ioutil.ReadAll(resp.Body) 79 | if err != nil { 80 | return err 81 | } 82 | defer resp.Body.Close() 83 | data := string(data_bytes) 84 | 85 | if strings.HasPrefix(data, PrefixData) { 86 | data := data[len(PrefixData):] 87 | 88 | decodeLen := base64.StdEncoding.DecodedLen(len(data)) 89 | bData := make([]byte, len(c.read_buffer) + decodeLen) 90 | n, err := base64.StdEncoding.Decode(bData[len(c.read_buffer):], []byte(data)) 91 | if err != nil { 92 | return err 93 | } 94 | bData = bData[:len(c.read_buffer)+n] 95 | c.read_buffer = bData 96 | } else { 97 | return errors.New("Could not read from server") 98 | } 99 | return nil 100 | } 101 | 102 | func (c *ProxyConnection) Read(b []byte) (n int, err error) { 103 | c.read_mutex.Lock() 104 | // If local buffer is empty, get new data 105 | if len(c.read_buffer) == 0 { 106 | err := c.FillReadBuffer() 107 | if err != nil { 108 | c.read_mutex.Unlock() 109 | return 0, err 110 | } 111 | } 112 | // Return local buffer 113 | count := len(b) 114 | if count > len(c.read_buffer){ 115 | count = len(c.read_buffer) 116 | } 117 | copy(b, c.read_buffer[:count]) 118 | c.read_buffer = c.read_buffer[count:] 119 | 120 | c.read_mutex.Unlock() 121 | return count, nil 122 | } 123 | 124 | func Connect(server, username, password, remote string) (*ProxyConnection, error) { 125 | if strings.HasSuffix(server, "/") { 126 | server = server[:len(server)-1] 127 | } 128 | conn := ProxyConnection{server: server} 129 | 130 | args := fmt.Sprintf("?username=%s", username) 131 | resp, err := http.Get(conn.server + EndpointAuth + args) 132 | if err != nil { 133 | return &ProxyConnection{}, err 134 | } 135 | data_bytes, err := ioutil.ReadAll(resp.Body) 136 | if err != nil { 137 | return &ProxyConnection{}, err 138 | } 139 | defer resp.Body.Close() 140 | data := string(data_bytes) 141 | if !strings.HasPrefix(data, PrefixData) { 142 | msg := fmt.Sprintf("crowbar: Invalid data returned by server: %s", data) 143 | return &ProxyConnection{}, errors.New(msg) 144 | } 145 | nonce_b64 := data[len(PrefixData):] 146 | decodeLen := base64.StdEncoding.DecodedLen(len(nonce_b64)) 147 | nonce := make([]byte, decodeLen) 148 | n, err := base64.StdEncoding.Decode(nonce, []byte(nonce_b64)) 149 | if err != nil { 150 | return &ProxyConnection{}, errors.New("crowbar: Invalid nonce") 151 | } 152 | nonce = nonce[:n] 153 | 154 | mac := hmac.New(sha256.New, []byte(password)) 155 | mac.Write(nonce) 156 | hmac := mac.Sum(nil) 157 | 158 | v := url.Values{} 159 | v.Set("remote_host", strings.Split(remote, ":")[0]) 160 | v.Set("remote_port", strings.Split(remote, ":")[1]) 161 | v.Set("username", username) 162 | v.Set("proof", base64.StdEncoding.EncodeToString(hmac)) 163 | resp, err = http.Get(conn.server + EndpointConnect + "?" + v.Encode()) 164 | if err != nil { 165 | return &ProxyConnection{}, err 166 | } 167 | data_bytes, err = ioutil.ReadAll(resp.Body) 168 | if err != nil { 169 | return &ProxyConnection{}, err 170 | } 171 | defer resp.Body.Close() 172 | data = string(data_bytes) 173 | if !strings.HasPrefix(data, PrefixOK) { 174 | return &ProxyConnection{}, errors.New("crowbar: Authentication error") 175 | } 176 | conn.uuid = data[len(PrefixOK):] 177 | 178 | return &conn, nil 179 | } 180 | -------------------------------------------------------------------------------- /cmd/crowbar-forward/main.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, Segiusz 'q3k' Bazanski 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // 1. Redistributions of source code must retain the above copyright notice, 9 | // this list of conditions and the following disclaimer. 10 | // 2. Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer in the 12 | // documentation and/or other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 18 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | // POSSIBILITY OF SUCH DAMAGE. 25 | 26 | package main 27 | 28 | import ( 29 | "flag" 30 | "fmt" 31 | "io" 32 | "net" 33 | "os" 34 | 35 | "github.com/q3k/crowbar" 36 | ) 37 | 38 | func main() { 39 | local := flag.String("local", "127.0.0.1:1122", "Local address to bind to, or - for stdin/out") 40 | remote := flag.String("remote", "HOST:PORT", "Remote address to establish tunnel to.") 41 | server := flag.String("server", "http://127.0.0.1:8080/", "Crowbar server to use.") 42 | username := flag.String("username", "", "Username to use.") 43 | password := flag.String("password", "", "Password to use.") 44 | flag.Parse() 45 | 46 | if *username == "" { 47 | fmt.Fprintf(os.Stderr, "Username must be given.\n") 48 | return 49 | } 50 | if *password == "" { 51 | fmt.Fprintf(os.Stderr, "Password must be given.\n") 52 | return 53 | } 54 | 55 | if *local == "-" { 56 | remoteConn, err := crowbar.Connect(*server, *username, *password, *remote) 57 | if err != nil { 58 | fmt.Fprintf(os.Stderr, "Error: %v\n", err) 59 | return 60 | } 61 | go io.Copy(remoteConn, os.Stdin) 62 | io.Copy(os.Stdout, remoteConn) 63 | } else { 64 | localListen, err := net.Listen("tcp", *local) 65 | if err != nil { 66 | fmt.Fprintf(os.Stderr, "Error: %v\n", err) 67 | return 68 | } 69 | for { 70 | localConn, err := localListen.Accept() 71 | if err != nil { 72 | fmt.Fprintf(os.Stderr, "Error: %v\n", err) 73 | return 74 | } 75 | remoteConn, err := crowbar.Connect(*server, *username, *password, *remote) 76 | if err != nil { 77 | fmt.Fprintf(os.Stderr, "Error: %v\n", err) 78 | return 79 | } 80 | go io.Copy(localConn, remoteConn) 81 | io.Copy(remoteConn, localConn) 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /cmd/crowbard/auth.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, Segiusz 'q3k' Bazanski 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // 1. Redistributions of source code must retain the above copyright notice, 9 | // this list of conditions and the following disclaimer. 10 | // 2. Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer in the 12 | // documentation and/or other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 18 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | // POSSIBILITY OF SUCH DAMAGE. 25 | 26 | package main 27 | 28 | import ( 29 | "os" 30 | "fmt" 31 | "bufio" 32 | "strings" 33 | "crypto/sha256" 34 | "crypto/hmac" 35 | ) 36 | 37 | type localUser struct { 38 | username string 39 | password string 40 | } 41 | 42 | type User interface { 43 | Authenticate(nonce []byte, hmac []byte) bool 44 | } 45 | 46 | func (u localUser) Authenticate(nonce []byte, givenMac []byte) bool { 47 | mac := hmac.New(sha256.New, []byte(u.password)) 48 | mac.Write(nonce) 49 | expectedMac := mac.Sum(nil) 50 | return hmac.Equal(expectedMac, givenMac) 51 | } 52 | 53 | var userMap = map[string]User{} 54 | 55 | func UserGet(username string) (User, bool) { 56 | val, ok := userMap[username] 57 | return val, ok 58 | } 59 | 60 | func loadUsersFromFile(filename string) { 61 | file, err := os.Open(filename) 62 | if err != nil { 63 | fmt.Fprintf(os.Stderr, "Could not open user file: %s\n", err) 64 | return 65 | } 66 | scanner := bufio.NewScanner(file) 67 | for scanner.Scan() { 68 | line := scanner.Text() 69 | if strings.Count(line, ":") != 1 { 70 | fmt.Fprintf(os.Stderr, "Invalid userfile line: %s\n", line) 71 | continue 72 | } 73 | parts := strings.Split(line, ":") 74 | 75 | user := localUser{username: parts[0], password: parts[1]} 76 | fmt.Fprintf(os.Stderr, "Loaded user %s\n", user.username) 77 | userMap[user.username] = user 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /cmd/crowbard/main.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, Segiusz 'q3k' Bazanski 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // 1. Redistributions of source code must retain the above copyright notice, 9 | // this list of conditions and the following disclaimer. 10 | // 2. Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer in the 12 | // documentation and/or other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 18 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | // POSSIBILITY OF SUCH DAMAGE. 25 | 26 | package main 27 | 28 | import ( 29 | "crypto/rand" 30 | "encoding/base64" 31 | "flag" 32 | "fmt" 33 | "net" 34 | "net/http" 35 | "os" 36 | "strconv" 37 | 38 | "github.com/pborman/uuid" 39 | 40 | "github.com/q3k/crowbar" 41 | ) 42 | 43 | var nonceMap = map[string][]byte{} 44 | 45 | func authHandler(w http.ResponseWriter, r *http.Request) { 46 | nonce := make([]byte, 16) 47 | _, err := rand.Read(nonce) 48 | if err != nil { 49 | crowbar.WriteHTTPError(w, "Internal error.") 50 | return 51 | } 52 | 53 | username := r.URL.Query().Get("username") 54 | _, ok := UserGet(username) 55 | 56 | if !ok { 57 | crowbar.WriteHTTPError(w, "No such user.") 58 | return 59 | } 60 | 61 | nonceMap[username] = nonce 62 | crowbar.WriteHTTPData(w, nonce) 63 | } 64 | 65 | func connectHandler(w http.ResponseWriter, r *http.Request) { 66 | remote_host := r.URL.Query().Get("remote_host") 67 | if remote_host == "" { 68 | crowbar.WriteHTTPError(w, "Invalid host") 69 | return 70 | } 71 | remote_port, err := strconv.Atoi(r.URL.Query().Get("remote_port")) 72 | if err != nil || remote_port > 0xFFFF { 73 | crowbar.WriteHTTPError(w, "Invalid port number.") 74 | return 75 | } 76 | username := r.URL.Query().Get("username") 77 | if username == "" { 78 | crowbar.WriteHTTPError(w, "Invalid username") 79 | return 80 | } 81 | user, ok := UserGet(username) 82 | if !ok { 83 | crowbar.WriteHTTPError(w, "Invalid username") 84 | return 85 | } 86 | nonce, ok := nonceMap[username] 87 | if !ok { 88 | crowbar.WriteHTTPError(w, "Invalid username") 89 | return 90 | } 91 | 92 | proof_b64 := r.URL.Query().Get("proof") 93 | decodeLen := base64.StdEncoding.DecodedLen(len(proof_b64)) 94 | proof := make([]byte, decodeLen) 95 | n, err := base64.StdEncoding.Decode(proof, []byte(proof_b64)) 96 | if err != nil { 97 | crowbar.WriteHTTPError(w, "Invalid nonce") 98 | return 99 | } 100 | proof = proof[:n] 101 | 102 | authenticated := user.Authenticate(nonce, proof) 103 | if !authenticated { 104 | crowbar.WriteHTTPError(w, "Invalid nonce") 105 | return 106 | } 107 | 108 | workerUuid := uuid.New() 109 | commandChannel := make(chan workerCommand, 10) 110 | responseChannel := make(chan workerResponse, 10) 111 | fmt.Printf("Connecting to %s:%d...\n", remote_host, remote_port) 112 | remote, err := net.Dial("tcp", fmt.Sprintf("%s:%d", remote_host, remote_port)) 113 | if err != nil { 114 | crowbar.WriteHTTPError(w, fmt.Sprintf("Could not connect to %s:%d", remote_host, remote_port)) 115 | return 116 | } 117 | 118 | newWorker := worker{remote: remote, commandChannel: commandChannel, responseChannel: responseChannel, uuid: workerUuid} 119 | workerMap[workerUuid] = newWorker 120 | 121 | crowbar.WriteHTTPOK(w, workerUuid) 122 | 123 | go socketWorker(newWorker) 124 | } 125 | 126 | func syncHandler(w http.ResponseWriter, r *http.Request) { 127 | workerUuid := r.URL.Query().Get("uuid") 128 | if worker, ok := workerMap[workerUuid]; ok { 129 | if r.Method == "POST" { 130 | r.ParseForm() 131 | if b64_parts, ok := r.Form["data"]; ok { 132 | b64 := b64_parts[0] 133 | decodeLen := base64.StdEncoding.DecodedLen(len(b64)) 134 | data := make([]byte, decodeLen) 135 | n, err := base64.StdEncoding.Decode(data, []byte(b64)) 136 | if err != nil { 137 | crowbar.WriteHTTPError(w, "Could not decode B64.") 138 | } else { 139 | worker.commandChannel <- workerCommand{command: command_data, extra: data[:n]} 140 | crowbar.WriteHTTPOK(w, "Sent.") 141 | } 142 | } else { 143 | crowbar.WriteHTTPError(w, "Data is required.") 144 | } 145 | } else { 146 | response := <-worker.responseChannel 147 | switch response.response { 148 | case response_data: 149 | crowbar.WriteHTTPData(w, response.extra_byte) 150 | case response_quit: 151 | crowbar.WriteHTTPQuit(w, response.extra_string) 152 | } 153 | } 154 | } else { 155 | crowbar.WriteHTTPError(w, "No such UUID") 156 | } 157 | } 158 | 159 | func main() { 160 | var listen = flag.String("listen", "0.0.0.0:8080", "Address to bind HTTP server to") 161 | var userfile = flag.String("userfile", "/etc/crowbard.conf", "Path of user config file") 162 | flag.Parse() 163 | loadUsersFromFile(*userfile) 164 | fmt.Fprintf(os.Stderr, "Server starting on %s...\n", *listen) 165 | http.HandleFunc(crowbar.EndpointConnect, connectHandler) 166 | http.HandleFunc(crowbar.EndpointSync, syncHandler) 167 | http.HandleFunc(crowbar.EndpointAuth, authHandler) 168 | http.ListenAndServe(*listen, nil) 169 | } 170 | -------------------------------------------------------------------------------- /cmd/crowbard/worker.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, Segiusz 'q3k' Bazanski 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // 1. Redistributions of source code must retain the above copyright notice, 9 | // this list of conditions and the following disclaimer. 10 | // 2. Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer in the 12 | // documentation and/or other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 18 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | // POSSIBILITY OF SUCH DAMAGE. 25 | 26 | package main 27 | 28 | import ( 29 | "fmt" 30 | "net" 31 | ) 32 | 33 | const command_data string = "DATA" 34 | const command_stop string = "STOP" 35 | 36 | const response_data string = "DATA" 37 | const response_quit string = "QUIT" 38 | 39 | type workerCommand struct { 40 | command string 41 | extra []byte 42 | } 43 | 44 | type workerResponse struct { 45 | response string 46 | extra_byte []byte 47 | extra_string string 48 | } 49 | 50 | func workerQuit(responseChannel chan workerResponse, extra string) { 51 | response := workerResponse{response: response_quit, extra_string: extra} 52 | responseChannel <- response 53 | } 54 | 55 | type worker struct { 56 | remote net.Conn 57 | uuid string 58 | commandChannel chan workerCommand 59 | responseChannel chan workerResponse 60 | } 61 | 62 | func socketWorker(wWorker worker) { 63 | fmt.Println("Worker starting...") 64 | 65 | continue_loop := true 66 | go func() { 67 | for continue_loop { 68 | data := make([]byte, 512) 69 | n, err := wWorker.remote.Read(data) 70 | if err != nil { 71 | workerQuit(wWorker.responseChannel, "Read error.") 72 | continue_loop = false 73 | wWorker.commandChannel <- workerCommand{command: "bogus"} 74 | } else { 75 | wWorker.responseChannel <- workerResponse{response: response_data, extra_byte: data[:n]} 76 | } 77 | } 78 | }() 79 | 80 | for continue_loop { 81 | command := <-wWorker.commandChannel 82 | switch command.command { 83 | case command_stop: 84 | workerQuit(wWorker.responseChannel, "Worker stopped.") 85 | continue_loop = false 86 | case command_data: 87 | wWorker.remote.Write(command.extra) 88 | } 89 | } 90 | fmt.Println("Worker exiting...") 91 | } 92 | 93 | var workerMap = map[string]worker{} 94 | -------------------------------------------------------------------------------- /proto.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, Segiusz 'q3k' Bazanski 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // 1. Redistributions of source code must retain the above copyright notice, 9 | // this list of conditions and the following disclaimer. 10 | // 2. Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer in the 12 | // documentation and/or other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 18 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | // POSSIBILITY OF SUCH DAMAGE. 25 | 26 | package crowbar 27 | 28 | import ( 29 | "fmt" 30 | "net/http" 31 | "encoding/base64" 32 | ) 33 | 34 | const PrefixError string = "ERROR:" 35 | const PrefixOK string = "OK:" 36 | const PrefixData string = "DATA:" 37 | const PrefixQuit string = "QUIT:" 38 | 39 | func WriteHTTPError(w http.ResponseWriter, message string) { 40 | body := fmt.Sprintf("%s%s", PrefixError, message) 41 | http.Error(w, body, http.StatusInternalServerError) 42 | } 43 | 44 | func WriteHTTPOK(w http.ResponseWriter, data string) { 45 | fmt.Fprintf(w, "%s%s", PrefixOK, data) 46 | } 47 | 48 | func WriteHTTPData(w http.ResponseWriter, data []byte) { 49 | data_encoded := base64.StdEncoding.EncodeToString(data) 50 | fmt.Fprintf(w, "%s%s", PrefixData, data_encoded) 51 | } 52 | 53 | func WriteHTTPQuit(w http.ResponseWriter, data string) { 54 | fmt.Fprintf(w, "%s%s", PrefixQuit, data) 55 | } 56 | 57 | const EndpointConnect string = "/connect/" 58 | const EndpointSync string = "/sync/" 59 | const EndpointAuth string = "/auth/" 60 | -------------------------------------------------------------------------------- /vendor/github.com/pborman/uuid/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.4.3 5 | - 1.5.3 6 | - release 7 | - tip 8 | 9 | script: 10 | - go test -v ./... 11 | -------------------------------------------------------------------------------- /vendor/github.com/pborman/uuid/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute 2 | 3 | We definitely welcome patches and contribution to this project! 4 | 5 | ### Legal requirements 6 | 7 | In order to protect both you and ourselves, you will need to sign the 8 | [Contributor License Agreement](https://cla.developers.google.com/clas). 9 | 10 | You may have already signed it for other Google projects. 11 | -------------------------------------------------------------------------------- /vendor/github.com/pborman/uuid/CONTRIBUTORS: -------------------------------------------------------------------------------- 1 | Paul Borman 2 | -------------------------------------------------------------------------------- /vendor/github.com/pborman/uuid/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009,2014 Google Inc. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /vendor/github.com/pborman/uuid/README.md: -------------------------------------------------------------------------------- 1 | This project was automatically exported from code.google.com/p/go-uuid 2 | 3 | # uuid ![build status](https://travis-ci.org/pborman/uuid.svg?branch=master) 4 | The uuid package generates and inspects UUIDs based on [RFC 412](http://tools.ietf.org/html/rfc4122) and DCE 1.1: Authentication and Security Services. 5 | 6 | ###### Install 7 | `go get github.com/pborman/uuid` 8 | 9 | ###### Documentation 10 | [![GoDoc](https://godoc.org/github.com/pborman/uuid?status.svg)](http://godoc.org/github.com/pborman/uuid) 11 | 12 | Full `go doc` style documentation for the package can be viewed online without installing this package by using the GoDoc site here: 13 | http://godoc.org/github.com/pborman/uuid 14 | -------------------------------------------------------------------------------- /vendor/github.com/pborman/uuid/dce.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package uuid 6 | 7 | import ( 8 | "encoding/binary" 9 | "fmt" 10 | "os" 11 | ) 12 | 13 | // A Domain represents a Version 2 domain 14 | type Domain byte 15 | 16 | // Domain constants for DCE Security (Version 2) UUIDs. 17 | const ( 18 | Person = Domain(0) 19 | Group = Domain(1) 20 | Org = Domain(2) 21 | ) 22 | 23 | // NewDCESecurity returns a DCE Security (Version 2) UUID. 24 | // 25 | // The domain should be one of Person, Group or Org. 26 | // On a POSIX system the id should be the users UID for the Person 27 | // domain and the users GID for the Group. The meaning of id for 28 | // the domain Org or on non-POSIX systems is site defined. 29 | // 30 | // For a given domain/id pair the same token may be returned for up to 31 | // 7 minutes and 10 seconds. 32 | func NewDCESecurity(domain Domain, id uint32) UUID { 33 | uuid := NewUUID() 34 | if uuid != nil { 35 | uuid[6] = (uuid[6] & 0x0f) | 0x20 // Version 2 36 | uuid[9] = byte(domain) 37 | binary.BigEndian.PutUint32(uuid[0:], id) 38 | } 39 | return uuid 40 | } 41 | 42 | // NewDCEPerson returns a DCE Security (Version 2) UUID in the person 43 | // domain with the id returned by os.Getuid. 44 | // 45 | // NewDCEPerson(Person, uint32(os.Getuid())) 46 | func NewDCEPerson() UUID { 47 | return NewDCESecurity(Person, uint32(os.Getuid())) 48 | } 49 | 50 | // NewDCEGroup returns a DCE Security (Version 2) UUID in the group 51 | // domain with the id returned by os.Getgid. 52 | // 53 | // NewDCEGroup(Group, uint32(os.Getgid())) 54 | func NewDCEGroup() UUID { 55 | return NewDCESecurity(Group, uint32(os.Getgid())) 56 | } 57 | 58 | // Domain returns the domain for a Version 2 UUID or false. 59 | func (uuid UUID) Domain() (Domain, bool) { 60 | if v, _ := uuid.Version(); v != 2 { 61 | return 0, false 62 | } 63 | return Domain(uuid[9]), true 64 | } 65 | 66 | // Id returns the id for a Version 2 UUID or false. 67 | func (uuid UUID) Id() (uint32, bool) { 68 | if v, _ := uuid.Version(); v != 2 { 69 | return 0, false 70 | } 71 | return binary.BigEndian.Uint32(uuid[0:4]), true 72 | } 73 | 74 | func (d Domain) String() string { 75 | switch d { 76 | case Person: 77 | return "Person" 78 | case Group: 79 | return "Group" 80 | case Org: 81 | return "Org" 82 | } 83 | return fmt.Sprintf("Domain%d", int(d)) 84 | } 85 | -------------------------------------------------------------------------------- /vendor/github.com/pborman/uuid/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // The uuid package generates and inspects UUIDs. 6 | // 7 | // UUIDs are based on RFC 4122 and DCE 1.1: Authentication and Security Services. 8 | package uuid 9 | -------------------------------------------------------------------------------- /vendor/github.com/pborman/uuid/hash.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package uuid 6 | 7 | import ( 8 | "crypto/md5" 9 | "crypto/sha1" 10 | "hash" 11 | ) 12 | 13 | // Well known Name Space IDs and UUIDs 14 | var ( 15 | NameSpace_DNS = Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8") 16 | NameSpace_URL = Parse("6ba7b811-9dad-11d1-80b4-00c04fd430c8") 17 | NameSpace_OID = Parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8") 18 | NameSpace_X500 = Parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8") 19 | NIL = Parse("00000000-0000-0000-0000-000000000000") 20 | ) 21 | 22 | // NewHash returns a new UUID derived from the hash of space concatenated with 23 | // data generated by h. The hash should be at least 16 byte in length. The 24 | // first 16 bytes of the hash are used to form the UUID. The version of the 25 | // UUID will be the lower 4 bits of version. NewHash is used to implement 26 | // NewMD5 and NewSHA1. 27 | func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID { 28 | h.Reset() 29 | h.Write(space) 30 | h.Write([]byte(data)) 31 | s := h.Sum(nil) 32 | uuid := make([]byte, 16) 33 | copy(uuid, s) 34 | uuid[6] = (uuid[6] & 0x0f) | uint8((version&0xf)<<4) 35 | uuid[8] = (uuid[8] & 0x3f) | 0x80 // RFC 4122 variant 36 | return uuid 37 | } 38 | 39 | // NewMD5 returns a new MD5 (Version 3) UUID based on the 40 | // supplied name space and data. 41 | // 42 | // NewHash(md5.New(), space, data, 3) 43 | func NewMD5(space UUID, data []byte) UUID { 44 | return NewHash(md5.New(), space, data, 3) 45 | } 46 | 47 | // NewSHA1 returns a new SHA1 (Version 5) UUID based on the 48 | // supplied name space and data. 49 | // 50 | // NewHash(sha1.New(), space, data, 5) 51 | func NewSHA1(space UUID, data []byte) UUID { 52 | return NewHash(sha1.New(), space, data, 5) 53 | } 54 | -------------------------------------------------------------------------------- /vendor/github.com/pborman/uuid/json.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package uuid 6 | 7 | import "errors" 8 | 9 | func (u UUID) MarshalJSON() ([]byte, error) { 10 | if len(u) != 16 { 11 | return []byte(`""`), nil 12 | } 13 | var js [38]byte 14 | js[0] = '"' 15 | encodeHex(js[1:], u) 16 | js[37] = '"' 17 | return js[:], nil 18 | } 19 | 20 | func (u *UUID) UnmarshalJSON(data []byte) error { 21 | if string(data) == `""` { 22 | return nil 23 | } 24 | if data[0] != '"' { 25 | return errors.New("invalid UUID format") 26 | } 27 | data = data[1 : len(data)-1] 28 | uu := Parse(string(data)) 29 | if uu == nil { 30 | return errors.New("invalid UUID format") 31 | } 32 | *u = uu 33 | return nil 34 | } 35 | -------------------------------------------------------------------------------- /vendor/github.com/pborman/uuid/node.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package uuid 6 | 7 | import ( 8 | "net" 9 | "sync" 10 | ) 11 | 12 | var ( 13 | nodeMu sync.Mutex 14 | interfaces []net.Interface // cached list of interfaces 15 | ifname string // name of interface being used 16 | nodeID []byte // hardware for version 1 UUIDs 17 | ) 18 | 19 | // NodeInterface returns the name of the interface from which the NodeID was 20 | // derived. The interface "user" is returned if the NodeID was set by 21 | // SetNodeID. 22 | func NodeInterface() string { 23 | defer nodeMu.Unlock() 24 | nodeMu.Lock() 25 | return ifname 26 | } 27 | 28 | // SetNodeInterface selects the hardware address to be used for Version 1 UUIDs. 29 | // If name is "" then the first usable interface found will be used or a random 30 | // Node ID will be generated. If a named interface cannot be found then false 31 | // is returned. 32 | // 33 | // SetNodeInterface never fails when name is "". 34 | func SetNodeInterface(name string) bool { 35 | defer nodeMu.Unlock() 36 | nodeMu.Lock() 37 | return setNodeInterface(name) 38 | } 39 | 40 | func setNodeInterface(name string) bool { 41 | if interfaces == nil { 42 | var err error 43 | interfaces, err = net.Interfaces() 44 | if err != nil && name != "" { 45 | return false 46 | } 47 | } 48 | 49 | for _, ifs := range interfaces { 50 | if len(ifs.HardwareAddr) >= 6 && (name == "" || name == ifs.Name) { 51 | if setNodeID(ifs.HardwareAddr) { 52 | ifname = ifs.Name 53 | return true 54 | } 55 | } 56 | } 57 | 58 | // We found no interfaces with a valid hardware address. If name 59 | // does not specify a specific interface generate a random Node ID 60 | // (section 4.1.6) 61 | if name == "" { 62 | if nodeID == nil { 63 | nodeID = make([]byte, 6) 64 | } 65 | randomBits(nodeID) 66 | return true 67 | } 68 | return false 69 | } 70 | 71 | // NodeID returns a slice of a copy of the current Node ID, setting the Node ID 72 | // if not already set. 73 | func NodeID() []byte { 74 | defer nodeMu.Unlock() 75 | nodeMu.Lock() 76 | if nodeID == nil { 77 | setNodeInterface("") 78 | } 79 | nid := make([]byte, 6) 80 | copy(nid, nodeID) 81 | return nid 82 | } 83 | 84 | // SetNodeID sets the Node ID to be used for Version 1 UUIDs. The first 6 bytes 85 | // of id are used. If id is less than 6 bytes then false is returned and the 86 | // Node ID is not set. 87 | func SetNodeID(id []byte) bool { 88 | defer nodeMu.Unlock() 89 | nodeMu.Lock() 90 | if setNodeID(id) { 91 | ifname = "user" 92 | return true 93 | } 94 | return false 95 | } 96 | 97 | func setNodeID(id []byte) bool { 98 | if len(id) < 6 { 99 | return false 100 | } 101 | if nodeID == nil { 102 | nodeID = make([]byte, 6) 103 | } 104 | copy(nodeID, id) 105 | return true 106 | } 107 | 108 | // NodeID returns the 6 byte node id encoded in uuid. It returns nil if uuid is 109 | // not valid. The NodeID is only well defined for version 1 and 2 UUIDs. 110 | func (uuid UUID) NodeID() []byte { 111 | if len(uuid) != 16 { 112 | return nil 113 | } 114 | node := make([]byte, 6) 115 | copy(node, uuid[10:]) 116 | return node 117 | } 118 | -------------------------------------------------------------------------------- /vendor/github.com/pborman/uuid/sql.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package uuid 6 | 7 | import ( 8 | "database/sql/driver" 9 | "errors" 10 | "fmt" 11 | ) 12 | 13 | // Scan implements sql.Scanner so UUIDs can be read from databases transparently 14 | // Currently, database types that map to string and []byte are supported. Please 15 | // consult database-specific driver documentation for matching types. 16 | func (uuid *UUID) Scan(src interface{}) error { 17 | switch src.(type) { 18 | case string: 19 | // if an empty UUID comes from a table, we return a null UUID 20 | if src.(string) == "" { 21 | return nil 22 | } 23 | 24 | // see uuid.Parse for required string format 25 | parsed := Parse(src.(string)) 26 | 27 | if parsed == nil { 28 | return errors.New("Scan: invalid UUID format") 29 | } 30 | 31 | *uuid = parsed 32 | case []byte: 33 | b := src.([]byte) 34 | 35 | // if an empty UUID comes from a table, we return a null UUID 36 | if len(b) == 0 { 37 | return nil 38 | } 39 | 40 | // assumes a simple slice of bytes if 16 bytes 41 | // otherwise attempts to parse 42 | if len(b) == 16 { 43 | *uuid = UUID(b) 44 | } else { 45 | u := Parse(string(b)) 46 | 47 | if u == nil { 48 | return errors.New("Scan: invalid UUID format") 49 | } 50 | 51 | *uuid = u 52 | } 53 | 54 | default: 55 | return fmt.Errorf("Scan: unable to scan type %T into UUID", src) 56 | } 57 | 58 | return nil 59 | } 60 | 61 | // Value implements sql.Valuer so that UUIDs can be written to databases 62 | // transparently. Currently, UUIDs map to strings. Please consult 63 | // database-specific driver documentation for matching types. 64 | func (uuid UUID) Value() (driver.Value, error) { 65 | return uuid.String(), nil 66 | } 67 | -------------------------------------------------------------------------------- /vendor/github.com/pborman/uuid/time.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package uuid 6 | 7 | import ( 8 | "encoding/binary" 9 | "sync" 10 | "time" 11 | ) 12 | 13 | // A Time represents a time as the number of 100's of nanoseconds since 15 Oct 14 | // 1582. 15 | type Time int64 16 | 17 | const ( 18 | lillian = 2299160 // Julian day of 15 Oct 1582 19 | unix = 2440587 // Julian day of 1 Jan 1970 20 | epoch = unix - lillian // Days between epochs 21 | g1582 = epoch * 86400 // seconds between epochs 22 | g1582ns100 = g1582 * 10000000 // 100s of a nanoseconds between epochs 23 | ) 24 | 25 | var ( 26 | timeMu sync.Mutex 27 | lasttime uint64 // last time we returned 28 | clock_seq uint16 // clock sequence for this run 29 | 30 | timeNow = time.Now // for testing 31 | ) 32 | 33 | // UnixTime converts t the number of seconds and nanoseconds using the Unix 34 | // epoch of 1 Jan 1970. 35 | func (t Time) UnixTime() (sec, nsec int64) { 36 | sec = int64(t - g1582ns100) 37 | nsec = (sec % 10000000) * 100 38 | sec /= 10000000 39 | return sec, nsec 40 | } 41 | 42 | // GetTime returns the current Time (100s of nanoseconds since 15 Oct 1582) and 43 | // clock sequence as well as adjusting the clock sequence as needed. An error 44 | // is returned if the current time cannot be determined. 45 | func GetTime() (Time, uint16, error) { 46 | defer timeMu.Unlock() 47 | timeMu.Lock() 48 | return getTime() 49 | } 50 | 51 | func getTime() (Time, uint16, error) { 52 | t := timeNow() 53 | 54 | // If we don't have a clock sequence already, set one. 55 | if clock_seq == 0 { 56 | setClockSequence(-1) 57 | } 58 | now := uint64(t.UnixNano()/100) + g1582ns100 59 | 60 | // If time has gone backwards with this clock sequence then we 61 | // increment the clock sequence 62 | if now <= lasttime { 63 | clock_seq = ((clock_seq + 1) & 0x3fff) | 0x8000 64 | } 65 | lasttime = now 66 | return Time(now), clock_seq, nil 67 | } 68 | 69 | // ClockSequence returns the current clock sequence, generating one if not 70 | // already set. The clock sequence is only used for Version 1 UUIDs. 71 | // 72 | // The uuid package does not use global static storage for the clock sequence or 73 | // the last time a UUID was generated. Unless SetClockSequence a new random 74 | // clock sequence is generated the first time a clock sequence is requested by 75 | // ClockSequence, GetTime, or NewUUID. (section 4.2.1.1) sequence is generated 76 | // for 77 | func ClockSequence() int { 78 | defer timeMu.Unlock() 79 | timeMu.Lock() 80 | return clockSequence() 81 | } 82 | 83 | func clockSequence() int { 84 | if clock_seq == 0 { 85 | setClockSequence(-1) 86 | } 87 | return int(clock_seq & 0x3fff) 88 | } 89 | 90 | // SetClockSeq sets the clock sequence to the lower 14 bits of seq. Setting to 91 | // -1 causes a new sequence to be generated. 92 | func SetClockSequence(seq int) { 93 | defer timeMu.Unlock() 94 | timeMu.Lock() 95 | setClockSequence(seq) 96 | } 97 | 98 | func setClockSequence(seq int) { 99 | if seq == -1 { 100 | var b [2]byte 101 | randomBits(b[:]) // clock sequence 102 | seq = int(b[0])<<8 | int(b[1]) 103 | } 104 | old_seq := clock_seq 105 | clock_seq = uint16(seq&0x3fff) | 0x8000 // Set our variant 106 | if old_seq != clock_seq { 107 | lasttime = 0 108 | } 109 | } 110 | 111 | // Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in 112 | // uuid. It returns false if uuid is not valid. The time is only well defined 113 | // for version 1 and 2 UUIDs. 114 | func (uuid UUID) Time() (Time, bool) { 115 | if len(uuid) != 16 { 116 | return 0, false 117 | } 118 | time := int64(binary.BigEndian.Uint32(uuid[0:4])) 119 | time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32 120 | time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48 121 | return Time(time), true 122 | } 123 | 124 | // ClockSequence returns the clock sequence encoded in uuid. It returns false 125 | // if uuid is not valid. The clock sequence is only well defined for version 1 126 | // and 2 UUIDs. 127 | func (uuid UUID) ClockSequence() (int, bool) { 128 | if len(uuid) != 16 { 129 | return 0, false 130 | } 131 | return int(binary.BigEndian.Uint16(uuid[8:10])) & 0x3fff, true 132 | } 133 | -------------------------------------------------------------------------------- /vendor/github.com/pborman/uuid/util.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package uuid 6 | 7 | import ( 8 | "io" 9 | ) 10 | 11 | // randomBits completely fills slice b with random data. 12 | func randomBits(b []byte) { 13 | if _, err := io.ReadFull(rander, b); err != nil { 14 | panic(err.Error()) // rand should never fail 15 | } 16 | } 17 | 18 | // xvalues returns the value of a byte as a hexadecimal digit or 255. 19 | var xvalues = [256]byte{ 20 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 21 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 22 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 23 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255, 24 | 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255, 25 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 26 | 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255, 27 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 28 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 29 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 30 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 31 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 32 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 33 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 34 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 35 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 36 | } 37 | 38 | // xtob converts the the first two hex bytes of x into a byte. 39 | func xtob(x string) (byte, bool) { 40 | b1 := xvalues[x[0]] 41 | b2 := xvalues[x[1]] 42 | return (b1 << 4) | b2, b1 != 255 && b2 != 255 43 | } 44 | -------------------------------------------------------------------------------- /vendor/github.com/pborman/uuid/uuid.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package uuid 6 | 7 | import ( 8 | "bytes" 9 | "crypto/rand" 10 | "encoding/hex" 11 | "fmt" 12 | "io" 13 | "strings" 14 | ) 15 | 16 | // Array is a pass-by-value UUID that can be used as an effecient key in a map. 17 | type Array [16]byte 18 | 19 | // UUID converts uuid into a slice. 20 | func (uuid Array) UUID() UUID { 21 | return uuid[:] 22 | } 23 | 24 | // String returns the string representation of uuid, 25 | // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. 26 | func (uuid Array) String() string { 27 | return uuid.UUID().String() 28 | } 29 | 30 | // A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC 31 | // 4122. 32 | type UUID []byte 33 | 34 | // A Version represents a UUIDs version. 35 | type Version byte 36 | 37 | // A Variant represents a UUIDs variant. 38 | type Variant byte 39 | 40 | // Constants returned by Variant. 41 | const ( 42 | Invalid = Variant(iota) // Invalid UUID 43 | RFC4122 // The variant specified in RFC4122 44 | Reserved // Reserved, NCS backward compatibility. 45 | Microsoft // Reserved, Microsoft Corporation backward compatibility. 46 | Future // Reserved for future definition. 47 | ) 48 | 49 | var rander = rand.Reader // random function 50 | 51 | // New returns a new random (version 4) UUID as a string. It is a convenience 52 | // function for NewRandom().String(). 53 | func New() string { 54 | return NewRandom().String() 55 | } 56 | 57 | // Parse decodes s into a UUID or returns nil. Both the UUID form of 58 | // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and 59 | // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded. 60 | func Parse(s string) UUID { 61 | if len(s) == 36+9 { 62 | if strings.ToLower(s[:9]) != "urn:uuid:" { 63 | return nil 64 | } 65 | s = s[9:] 66 | } else if len(s) != 36 { 67 | return nil 68 | } 69 | if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' { 70 | return nil 71 | } 72 | var uuid [16]byte 73 | for i, x := range [16]int{ 74 | 0, 2, 4, 6, 75 | 9, 11, 76 | 14, 16, 77 | 19, 21, 78 | 24, 26, 28, 30, 32, 34} { 79 | if v, ok := xtob(s[x:]); !ok { 80 | return nil 81 | } else { 82 | uuid[i] = v 83 | } 84 | } 85 | return uuid[:] 86 | } 87 | 88 | // Equal returns true if uuid1 and uuid2 are equal. 89 | func Equal(uuid1, uuid2 UUID) bool { 90 | return bytes.Equal(uuid1, uuid2) 91 | } 92 | 93 | // Array returns an array representation of uuid that can be used as a map key. 94 | // Array panics if uuid is not valid. 95 | func (uuid UUID) Array() Array { 96 | if len(uuid) != 16 { 97 | panic("invalid uuid") 98 | } 99 | var a Array 100 | copy(a[:], uuid) 101 | return a 102 | } 103 | 104 | // String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 105 | // , or "" if uuid is invalid. 106 | func (uuid UUID) String() string { 107 | if len(uuid) != 16 { 108 | return "" 109 | } 110 | var buf [36]byte 111 | encodeHex(buf[:], uuid) 112 | return string(buf[:]) 113 | } 114 | 115 | // URN returns the RFC 2141 URN form of uuid, 116 | // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, or "" if uuid is invalid. 117 | func (uuid UUID) URN() string { 118 | if len(uuid) != 16 { 119 | return "" 120 | } 121 | var buf [36 + 9]byte 122 | copy(buf[:], "urn:uuid:") 123 | encodeHex(buf[9:], uuid) 124 | return string(buf[:]) 125 | } 126 | 127 | func encodeHex(dst []byte, uuid UUID) { 128 | hex.Encode(dst[:], uuid[:4]) 129 | dst[8] = '-' 130 | hex.Encode(dst[9:13], uuid[4:6]) 131 | dst[13] = '-' 132 | hex.Encode(dst[14:18], uuid[6:8]) 133 | dst[18] = '-' 134 | hex.Encode(dst[19:23], uuid[8:10]) 135 | dst[23] = '-' 136 | hex.Encode(dst[24:], uuid[10:]) 137 | } 138 | 139 | // Variant returns the variant encoded in uuid. It returns Invalid if 140 | // uuid is invalid. 141 | func (uuid UUID) Variant() Variant { 142 | if len(uuid) != 16 { 143 | return Invalid 144 | } 145 | switch { 146 | case (uuid[8] & 0xc0) == 0x80: 147 | return RFC4122 148 | case (uuid[8] & 0xe0) == 0xc0: 149 | return Microsoft 150 | case (uuid[8] & 0xe0) == 0xe0: 151 | return Future 152 | default: 153 | return Reserved 154 | } 155 | } 156 | 157 | // Version returns the version of uuid. It returns false if uuid is not 158 | // valid. 159 | func (uuid UUID) Version() (Version, bool) { 160 | if len(uuid) != 16 { 161 | return 0, false 162 | } 163 | return Version(uuid[6] >> 4), true 164 | } 165 | 166 | func (v Version) String() string { 167 | if v > 15 { 168 | return fmt.Sprintf("BAD_VERSION_%d", v) 169 | } 170 | return fmt.Sprintf("VERSION_%d", v) 171 | } 172 | 173 | func (v Variant) String() string { 174 | switch v { 175 | case RFC4122: 176 | return "RFC4122" 177 | case Reserved: 178 | return "Reserved" 179 | case Microsoft: 180 | return "Microsoft" 181 | case Future: 182 | return "Future" 183 | case Invalid: 184 | return "Invalid" 185 | } 186 | return fmt.Sprintf("BadVariant%d", int(v)) 187 | } 188 | 189 | // SetRand sets the random number generator to r, which implents io.Reader. 190 | // If r.Read returns an error when the package requests random data then 191 | // a panic will be issued. 192 | // 193 | // Calling SetRand with nil sets the random number generator to the default 194 | // generator. 195 | func SetRand(r io.Reader) { 196 | if r == nil { 197 | rander = rand.Reader 198 | return 199 | } 200 | rander = r 201 | } 202 | -------------------------------------------------------------------------------- /vendor/github.com/pborman/uuid/version1.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package uuid 6 | 7 | import ( 8 | "encoding/binary" 9 | ) 10 | 11 | // NewUUID returns a Version 1 UUID based on the current NodeID and clock 12 | // sequence, and the current time. If the NodeID has not been set by SetNodeID 13 | // or SetNodeInterface then it will be set automatically. If the NodeID cannot 14 | // be set NewUUID returns nil. If clock sequence has not been set by 15 | // SetClockSequence then it will be set automatically. If GetTime fails to 16 | // return the current NewUUID returns nil. 17 | func NewUUID() UUID { 18 | if nodeID == nil { 19 | SetNodeInterface("") 20 | } 21 | 22 | now, seq, err := GetTime() 23 | if err != nil { 24 | return nil 25 | } 26 | 27 | uuid := make([]byte, 16) 28 | 29 | time_low := uint32(now & 0xffffffff) 30 | time_mid := uint16((now >> 32) & 0xffff) 31 | time_hi := uint16((now >> 48) & 0x0fff) 32 | time_hi |= 0x1000 // Version 1 33 | 34 | binary.BigEndian.PutUint32(uuid[0:], time_low) 35 | binary.BigEndian.PutUint16(uuid[4:], time_mid) 36 | binary.BigEndian.PutUint16(uuid[6:], time_hi) 37 | binary.BigEndian.PutUint16(uuid[8:], seq) 38 | copy(uuid[10:], nodeID) 39 | 40 | return uuid 41 | } 42 | -------------------------------------------------------------------------------- /vendor/github.com/pborman/uuid/version4.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package uuid 6 | 7 | // Random returns a Random (Version 4) UUID or panics. 8 | // 9 | // The strength of the UUIDs is based on the strength of the crypto/rand 10 | // package. 11 | // 12 | // A note about uniqueness derived from from the UUID Wikipedia entry: 13 | // 14 | // Randomly generated UUIDs have 122 random bits. One's annual risk of being 15 | // hit by a meteorite is estimated to be one chance in 17 billion, that 16 | // means the probability is about 0.00000000006 (6 × 10−11), 17 | // equivalent to the odds of creating a few tens of trillions of UUIDs in a 18 | // year and having one duplicate. 19 | func NewRandom() UUID { 20 | uuid := make([]byte, 16) 21 | randomBits([]byte(uuid)) 22 | uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4 23 | uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10 24 | return uuid 25 | } 26 | --------------------------------------------------------------------------------