├── .travis.yml ├── vendor ├── github.com │ ├── godbus │ │ └── dbus │ │ │ ├── transport_darwin.go │ │ │ ├── homedir_dynamic.go │ │ │ ├── transport_unixcred_openbsd.go │ │ │ ├── homedir.go │ │ │ ├── auth_external.go │ │ │ ├── transport_unixcred_linux.go │ │ │ ├── homedir_static.go │ │ │ ├── conn_darwin.go │ │ │ ├── conn_other.go │ │ │ ├── transport_tcp.go │ │ │ ├── call.go │ │ │ ├── transport_generic.go │ │ │ ├── LICENSE │ │ │ ├── doc.go │ │ │ ├── auth_sha1.go │ │ │ ├── transport_unixcred_freebsd.go │ │ │ ├── transport_unixcred_dragonfly.go │ │ │ ├── server_interfaces.go │ │ │ ├── variant.go │ │ │ ├── object.go │ │ │ ├── transport_unix.go │ │ │ ├── decoder.go │ │ │ ├── variant_lexer.go │ │ │ ├── encoder.go │ │ │ ├── sig.go │ │ │ ├── default_handler.go │ │ │ ├── auth.go │ │ │ ├── message.go │ │ │ ├── dbus.go │ │ │ └── export.go │ ├── armon │ │ └── go-socks5 │ │ │ ├── credentials.go │ │ │ ├── resolver.go │ │ │ ├── LICENSE │ │ │ ├── ruleset.go │ │ │ ├── auth.go │ │ │ ├── socks5.go │ │ │ └── request.go │ └── BurntSushi │ │ └── toml │ │ ├── COPYING │ │ ├── cmd │ │ ├── tomlv │ │ │ └── COPYING │ │ ├── toml-test-decoder │ │ │ └── COPYING │ │ └── toml-test-encoder │ │ │ └── COPYING │ │ ├── encoding_types_1.1.go │ │ ├── encoding_types.go │ │ ├── doc.go │ │ ├── type_check.go │ │ ├── decode_meta.go │ │ ├── type_fields.go │ │ └── decode.go └── golang.org │ └── x │ └── net │ ├── AUTHORS │ ├── CONTRIBUTORS │ ├── context │ ├── go19.go │ ├── context.go │ ├── go17.go │ ├── pre_go19.go │ └── pre_go17.go │ ├── PATENTS │ └── LICENSE ├── Gopkg.toml ├── bind_device_other.go ├── bind_device_linux.go ├── Gopkg.lock ├── LICENSE ├── captive-browser-dhcpcd-chromium.toml ├── captive-browser-ubuntu-chrome.toml ├── captive-browser-mac-chrome.toml ├── captive-browser-arch-chrome.toml ├── README.md ├── cmd └── systemd-networkd-dns │ └── main.go └── main.go /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | dist: xenial 3 | go: 4 | - 1.x 5 | - 1.11.x 6 | script: 7 | - GOOS=linux go test ./... 8 | - GOOS=darwin go test ./... 9 | -------------------------------------------------------------------------------- /vendor/github.com/godbus/dbus/transport_darwin.go: -------------------------------------------------------------------------------- 1 | package dbus 2 | 3 | func (t *unixTransport) SendNullByte() error { 4 | _, err := t.Write([]byte{0}) 5 | return err 6 | } 7 | -------------------------------------------------------------------------------- /vendor/golang.org/x/net/AUTHORS: -------------------------------------------------------------------------------- 1 | # This source code refers to The Go Authors for copyright purposes. 2 | # The master list of authors is in the main Go distribution, 3 | # visible at http://tip.golang.org/AUTHORS. 4 | -------------------------------------------------------------------------------- /vendor/golang.org/x/net/CONTRIBUTORS: -------------------------------------------------------------------------------- 1 | # This source code was written by the Go contributors. 2 | # The master list of contributors is in the main Go distribution, 3 | # visible at http://tip.golang.org/CONTRIBUTORS. 4 | -------------------------------------------------------------------------------- /vendor/github.com/godbus/dbus/homedir_dynamic.go: -------------------------------------------------------------------------------- 1 | // +build !static_build 2 | 3 | package dbus 4 | 5 | import ( 6 | "os/user" 7 | ) 8 | 9 | func lookupHomeDir() string { 10 | u, err := user.Current() 11 | if err != nil { 12 | return "/" 13 | } 14 | return u.HomeDir 15 | } 16 | -------------------------------------------------------------------------------- /vendor/github.com/godbus/dbus/transport_unixcred_openbsd.go: -------------------------------------------------------------------------------- 1 | package dbus 2 | 3 | import "io" 4 | 5 | func (t *unixTransport) SendNullByte() error { 6 | n, _, err := t.UnixConn.WriteMsgUnix([]byte{0}, nil, nil) 7 | if err != nil { 8 | return err 9 | } 10 | if n != 1 { 11 | return io.ErrShortWrite 12 | } 13 | return nil 14 | } 15 | -------------------------------------------------------------------------------- /Gopkg.toml: -------------------------------------------------------------------------------- 1 | [prune] 2 | unused-packages = true 3 | go-tests = true 4 | non-go = true 5 | 6 | [[constraint]] 7 | name = "github.com/BurntSushi/toml" 8 | version = "0.3.0" 9 | 10 | [[constraint]] 11 | name = "github.com/godbus/dbus" 12 | version = "4.1.0" 13 | 14 | [[constraint]] 15 | branch = "master" 16 | name = "github.com/armon/go-socks5" 17 | -------------------------------------------------------------------------------- /bind_device_other.go: -------------------------------------------------------------------------------- 1 | // +build !linux 2 | 3 | package main 4 | 5 | import ( 6 | "fmt" 7 | "runtime" 8 | "syscall" 9 | ) 10 | 11 | func bindToDevice(device string) func(network, address string, c syscall.RawConn) error { 12 | return func(network, address string, c syscall.RawConn) error { 13 | return fmt.Errorf("bind-device not supported on %s", runtime.GOOS) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /bind_device_linux.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "syscall" 6 | ) 7 | 8 | func bindToDevice(device string) func(network, address string, c syscall.RawConn) error { 9 | return func(network, address string, c syscall.RawConn) error { 10 | return c.Control(func(fd uintptr) { 11 | err := syscall.BindToDevice(int(fd), device) 12 | if err != nil { 13 | log.Fatalf("Failed to bind to %q: %s", device, err) 14 | } 15 | }) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /vendor/github.com/godbus/dbus/homedir.go: -------------------------------------------------------------------------------- 1 | package dbus 2 | 3 | import ( 4 | "os" 5 | "sync" 6 | ) 7 | 8 | var ( 9 | homeDir string 10 | homeDirLock sync.Mutex 11 | ) 12 | 13 | func getHomeDir() string { 14 | homeDirLock.Lock() 15 | defer homeDirLock.Unlock() 16 | 17 | if homeDir != "" { 18 | return homeDir 19 | } 20 | 21 | homeDir = os.Getenv("HOME") 22 | if homeDir != "" { 23 | return homeDir 24 | } 25 | 26 | homeDir = lookupHomeDir() 27 | return homeDir 28 | } 29 | -------------------------------------------------------------------------------- /vendor/github.com/armon/go-socks5/credentials.go: -------------------------------------------------------------------------------- 1 | package socks5 2 | 3 | // CredentialStore is used to support user/pass authentication 4 | type CredentialStore interface { 5 | Valid(user, password string) bool 6 | } 7 | 8 | // StaticCredentials enables using a map directly as a credential store 9 | type StaticCredentials map[string]string 10 | 11 | func (s StaticCredentials) Valid(user, password string) bool { 12 | pass, ok := s[user] 13 | if !ok { 14 | return false 15 | } 16 | return password == pass 17 | } 18 | -------------------------------------------------------------------------------- /vendor/github.com/BurntSushi/toml/COPYING: -------------------------------------------------------------------------------- 1 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 2 | Version 2, December 2004 3 | 4 | Copyright (C) 2004 Sam Hocevar 5 | 6 | Everyone is permitted to copy and distribute verbatim or modified 7 | copies of this license document, and changing it is allowed as long 8 | as the name is changed. 9 | 10 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 11 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 12 | 13 | 0. You just DO WHAT THE FUCK YOU WANT TO. 14 | 15 | -------------------------------------------------------------------------------- /vendor/github.com/BurntSushi/toml/cmd/tomlv/COPYING: -------------------------------------------------------------------------------- 1 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 2 | Version 2, December 2004 3 | 4 | Copyright (C) 2004 Sam Hocevar 5 | 6 | Everyone is permitted to copy and distribute verbatim or modified 7 | copies of this license document, and changing it is allowed as long 8 | as the name is changed. 9 | 10 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 11 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 12 | 13 | 0. You just DO WHAT THE FUCK YOU WANT TO. 14 | 15 | -------------------------------------------------------------------------------- /vendor/github.com/BurntSushi/toml/cmd/toml-test-decoder/COPYING: -------------------------------------------------------------------------------- 1 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 2 | Version 2, December 2004 3 | 4 | Copyright (C) 2004 Sam Hocevar 5 | 6 | Everyone is permitted to copy and distribute verbatim or modified 7 | copies of this license document, and changing it is allowed as long 8 | as the name is changed. 9 | 10 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 11 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 12 | 13 | 0. You just DO WHAT THE FUCK YOU WANT TO. 14 | 15 | -------------------------------------------------------------------------------- /vendor/github.com/BurntSushi/toml/cmd/toml-test-encoder/COPYING: -------------------------------------------------------------------------------- 1 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 2 | Version 2, December 2004 3 | 4 | Copyright (C) 2004 Sam Hocevar 5 | 6 | Everyone is permitted to copy and distribute verbatim or modified 7 | copies of this license document, and changing it is allowed as long 8 | as the name is changed. 9 | 10 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 11 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 12 | 13 | 0. You just DO WHAT THE FUCK YOU WANT TO. 14 | 15 | -------------------------------------------------------------------------------- /vendor/github.com/BurntSushi/toml/encoding_types_1.1.go: -------------------------------------------------------------------------------- 1 | // +build !go1.2 2 | 3 | package toml 4 | 5 | // These interfaces were introduced in Go 1.2, so we add them manually when 6 | // compiling for Go 1.1. 7 | 8 | // TextMarshaler is a synonym for encoding.TextMarshaler. It is defined here 9 | // so that Go 1.1 can be supported. 10 | type TextMarshaler interface { 11 | MarshalText() (text []byte, err error) 12 | } 13 | 14 | // TextUnmarshaler is a synonym for encoding.TextUnmarshaler. It is defined 15 | // here so that Go 1.1 can be supported. 16 | type TextUnmarshaler interface { 17 | UnmarshalText(text []byte) error 18 | } 19 | -------------------------------------------------------------------------------- /vendor/github.com/BurntSushi/toml/encoding_types.go: -------------------------------------------------------------------------------- 1 | // +build go1.2 2 | 3 | package toml 4 | 5 | // In order to support Go 1.1, we define our own TextMarshaler and 6 | // TextUnmarshaler types. For Go 1.2+, we just alias them with the 7 | // standard library interfaces. 8 | 9 | import ( 10 | "encoding" 11 | ) 12 | 13 | // TextMarshaler is a synonym for encoding.TextMarshaler. It is defined here 14 | // so that Go 1.1 can be supported. 15 | type TextMarshaler encoding.TextMarshaler 16 | 17 | // TextUnmarshaler is a synonym for encoding.TextUnmarshaler. It is defined 18 | // here so that Go 1.1 can be supported. 19 | type TextUnmarshaler encoding.TextUnmarshaler 20 | -------------------------------------------------------------------------------- /vendor/github.com/armon/go-socks5/resolver.go: -------------------------------------------------------------------------------- 1 | package socks5 2 | 3 | import ( 4 | "net" 5 | 6 | "golang.org/x/net/context" 7 | ) 8 | 9 | // NameResolver is used to implement custom name resolution 10 | type NameResolver interface { 11 | Resolve(ctx context.Context, name string) (context.Context, net.IP, error) 12 | } 13 | 14 | // DNSResolver uses the system DNS to resolve host names 15 | type DNSResolver struct{} 16 | 17 | func (d DNSResolver) Resolve(ctx context.Context, name string) (context.Context, net.IP, error) { 18 | addr, err := net.ResolveIPAddr("ip", name) 19 | if err != nil { 20 | return ctx, nil, err 21 | } 22 | return ctx, addr.IP, err 23 | } 24 | -------------------------------------------------------------------------------- /vendor/github.com/godbus/dbus/auth_external.go: -------------------------------------------------------------------------------- 1 | package dbus 2 | 3 | import ( 4 | "encoding/hex" 5 | ) 6 | 7 | // AuthExternal returns an Auth that authenticates as the given user with the 8 | // EXTERNAL mechanism. 9 | func AuthExternal(user string) Auth { 10 | return authExternal{user} 11 | } 12 | 13 | // AuthExternal implements the EXTERNAL authentication mechanism. 14 | type authExternal struct { 15 | user string 16 | } 17 | 18 | func (a authExternal) FirstData() ([]byte, []byte, AuthStatus) { 19 | b := make([]byte, 2*len(a.user)) 20 | hex.Encode(b, []byte(a.user)) 21 | return []byte("EXTERNAL"), b, AuthOk 22 | } 23 | 24 | func (a authExternal) HandleData(b []byte) ([]byte, AuthStatus) { 25 | return nil, AuthError 26 | } 27 | -------------------------------------------------------------------------------- /vendor/golang.org/x/net/context/go19.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The Go Authors. 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 | // +build go1.9 6 | 7 | package context 8 | 9 | import "context" // standard library's context, as of Go 1.7 10 | 11 | // A Context carries a deadline, a cancelation signal, and other values across 12 | // API boundaries. 13 | // 14 | // Context's methods may be called by multiple goroutines simultaneously. 15 | type Context = context.Context 16 | 17 | // A CancelFunc tells an operation to abandon its work. 18 | // A CancelFunc does not wait for the work to stop. 19 | // After the first call, subsequent calls to a CancelFunc do nothing. 20 | type CancelFunc = context.CancelFunc 21 | -------------------------------------------------------------------------------- /vendor/github.com/godbus/dbus/transport_unixcred_linux.go: -------------------------------------------------------------------------------- 1 | // The UnixCredentials system call is currently only implemented on Linux 2 | // http://golang.org/src/pkg/syscall/sockcmsg_linux.go 3 | // https://golang.org/s/go1.4-syscall 4 | // http://code.google.com/p/go/source/browse/unix/sockcmsg_linux.go?repo=sys 5 | 6 | package dbus 7 | 8 | import ( 9 | "io" 10 | "os" 11 | "syscall" 12 | ) 13 | 14 | func (t *unixTransport) SendNullByte() error { 15 | ucred := &syscall.Ucred{Pid: int32(os.Getpid()), Uid: uint32(os.Getuid()), Gid: uint32(os.Getgid())} 16 | b := syscall.UnixCredentials(ucred) 17 | _, oobn, err := t.UnixConn.WriteMsgUnix([]byte{0}, b, nil) 18 | if err != nil { 19 | return err 20 | } 21 | if oobn != len(b) { 22 | return io.ErrShortWrite 23 | } 24 | return nil 25 | } 26 | -------------------------------------------------------------------------------- /vendor/github.com/godbus/dbus/homedir_static.go: -------------------------------------------------------------------------------- 1 | // +build static_build 2 | 3 | package dbus 4 | 5 | import ( 6 | "bufio" 7 | "os" 8 | "strconv" 9 | "strings" 10 | ) 11 | 12 | func lookupHomeDir() string { 13 | myUid := os.Getuid() 14 | 15 | f, err := os.Open("/etc/passwd") 16 | if err != nil { 17 | return "/" 18 | } 19 | defer f.Close() 20 | 21 | s := bufio.NewScanner(f) 22 | 23 | for s.Scan() { 24 | if err := s.Err(); err != nil { 25 | break 26 | } 27 | 28 | line := strings.TrimSpace(s.Text()) 29 | if line == "" { 30 | continue 31 | } 32 | 33 | parts := strings.Split(line, ":") 34 | 35 | if len(parts) >= 6 { 36 | uid, err := strconv.Atoi(parts[2]) 37 | if err == nil && uid == myUid { 38 | return parts[5] 39 | } 40 | } 41 | } 42 | 43 | // Default to / if we can't get a better value 44 | return "/" 45 | } 46 | -------------------------------------------------------------------------------- /vendor/github.com/godbus/dbus/conn_darwin.go: -------------------------------------------------------------------------------- 1 | package dbus 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "os" 7 | "os/exec" 8 | ) 9 | 10 | const defaultSystemBusAddress = "unix:path=/opt/local/var/run/dbus/system_bus_socket" 11 | 12 | func getSessionBusPlatformAddress() (string, error) { 13 | cmd := exec.Command("launchctl", "getenv", "DBUS_LAUNCHD_SESSION_BUS_SOCKET") 14 | b, err := cmd.CombinedOutput() 15 | 16 | if err != nil { 17 | return "", err 18 | } 19 | 20 | if len(b) == 0 { 21 | return "", errors.New("dbus: couldn't determine address of session bus") 22 | } 23 | 24 | return "unix:path=" + string(b[:len(b)-1]), nil 25 | } 26 | 27 | func getSystemBusPlatformAddress() string { 28 | address := os.Getenv("DBUS_LAUNCHD_SESSION_BUS_SOCKET") 29 | if address != "" { 30 | return fmt.Sprintf("unix:path=%s", address) 31 | } 32 | return defaultSystemBusAddress 33 | } 34 | -------------------------------------------------------------------------------- /vendor/github.com/godbus/dbus/conn_other.go: -------------------------------------------------------------------------------- 1 | // +build !darwin 2 | 3 | package dbus 4 | 5 | import ( 6 | "bytes" 7 | "errors" 8 | "fmt" 9 | "os" 10 | "os/exec" 11 | ) 12 | 13 | const defaultSystemBusAddress = "unix:path=/var/run/dbus/system_bus_socket" 14 | 15 | func getSessionBusPlatformAddress() (string, error) { 16 | cmd := exec.Command("dbus-launch") 17 | b, err := cmd.CombinedOutput() 18 | 19 | if err != nil { 20 | return "", err 21 | } 22 | 23 | i := bytes.IndexByte(b, '=') 24 | j := bytes.IndexByte(b, '\n') 25 | 26 | if i == -1 || j == -1 { 27 | return "", errors.New("dbus: couldn't determine address of session bus") 28 | } 29 | 30 | env, addr := string(b[0:i]), string(b[i+1:j]) 31 | os.Setenv(env, addr) 32 | 33 | return addr, nil 34 | } 35 | 36 | func getSystemBusPlatformAddress() string { 37 | address := os.Getenv("DBUS_SYSTEM_BUS_ADDRESS") 38 | if address != "" { 39 | return fmt.Sprintf("unix:path=%s", address) 40 | } 41 | return defaultSystemBusAddress 42 | } 43 | -------------------------------------------------------------------------------- /Gopkg.lock: -------------------------------------------------------------------------------- 1 | # This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. 2 | 3 | 4 | [[projects]] 5 | name = "github.com/BurntSushi/toml" 6 | packages = ["."] 7 | revision = "b26d9c308763d68093482582cea63d69be07a0f0" 8 | version = "v0.3.0" 9 | 10 | [[projects]] 11 | branch = "master" 12 | name = "github.com/armon/go-socks5" 13 | packages = ["."] 14 | revision = "e75332964ef517daa070d7c38a9466a0d687e0a5" 15 | 16 | [[projects]] 17 | name = "github.com/godbus/dbus" 18 | packages = ["."] 19 | revision = "a389bdde4dd695d414e47b755e95e72b7826432c" 20 | version = "v4.1.0" 21 | 22 | [[projects]] 23 | branch = "master" 24 | name = "golang.org/x/net" 25 | packages = ["context"] 26 | revision = "8351a756f30f1297fe94bbf4b767ec589c6ea6d0" 27 | 28 | [solve-meta] 29 | analyzer-name = "dep" 30 | analyzer-version = 1 31 | inputs-digest = "bab8765a4979191d24ce71b27b71f68f56ae0d505d46535738d7b683fc172ad0" 32 | solver-name = "gps-cdcl" 33 | solver-version = 1 34 | -------------------------------------------------------------------------------- /vendor/github.com/godbus/dbus/transport_tcp.go: -------------------------------------------------------------------------------- 1 | //+build !windows 2 | 3 | package dbus 4 | 5 | import ( 6 | "errors" 7 | "net" 8 | ) 9 | 10 | func init() { 11 | transports["tcp"] = newTcpTransport 12 | } 13 | 14 | func tcpFamily(keys string) (string, error) { 15 | switch getKey(keys, "family") { 16 | case "": 17 | return "tcp", nil 18 | case "ipv4": 19 | return "tcp4", nil 20 | case "ipv6": 21 | return "tcp6", nil 22 | default: 23 | return "", errors.New("dbus: invalid tcp family (must be ipv4 or ipv6)") 24 | } 25 | } 26 | 27 | func newTcpTransport(keys string) (transport, error) { 28 | host := getKey(keys, "host") 29 | port := getKey(keys, "port") 30 | if host == "" || port == "" { 31 | return nil, errors.New("dbus: unsupported address (must set host and port)") 32 | } 33 | 34 | protocol, err := tcpFamily(keys) 35 | if err != nil { 36 | return nil, err 37 | } 38 | socket, err := net.Dial(protocol, net.JoinHostPort(host, port)) 39 | if err != nil { 40 | return nil, err 41 | } 42 | return NewConn(socket) 43 | } 44 | -------------------------------------------------------------------------------- /vendor/github.com/godbus/dbus/call.go: -------------------------------------------------------------------------------- 1 | package dbus 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | // Call represents a pending or completed method call. 8 | type Call struct { 9 | Destination string 10 | Path ObjectPath 11 | Method string 12 | Args []interface{} 13 | 14 | // Strobes when the call is complete. 15 | Done chan *Call 16 | 17 | // After completion, the error status. If this is non-nil, it may be an 18 | // error message from the peer (with Error as its type) or some other error. 19 | Err error 20 | 21 | // Holds the response once the call is done. 22 | Body []interface{} 23 | } 24 | 25 | var errSignature = errors.New("dbus: mismatched signature") 26 | 27 | // Store stores the body of the reply into the provided pointers. It returns 28 | // an error if the signatures of the body and retvalues don't match, or if 29 | // the error status is not nil. 30 | func (c *Call) Store(retvalues ...interface{}) error { 31 | if c.Err != nil { 32 | return c.Err 33 | } 34 | 35 | return Store(c.Body, retvalues...) 36 | } 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Filippo Valsorda 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /vendor/github.com/godbus/dbus/transport_generic.go: -------------------------------------------------------------------------------- 1 | package dbus 2 | 3 | import ( 4 | "encoding/binary" 5 | "errors" 6 | "io" 7 | "unsafe" 8 | ) 9 | 10 | var nativeEndian binary.ByteOrder 11 | 12 | func detectEndianness() binary.ByteOrder { 13 | var x uint32 = 0x01020304 14 | if *(*byte)(unsafe.Pointer(&x)) == 0x01 { 15 | return binary.BigEndian 16 | } 17 | return binary.LittleEndian 18 | } 19 | 20 | func init() { 21 | nativeEndian = detectEndianness() 22 | } 23 | 24 | type genericTransport struct { 25 | io.ReadWriteCloser 26 | } 27 | 28 | func (t genericTransport) SendNullByte() error { 29 | _, err := t.Write([]byte{0}) 30 | return err 31 | } 32 | 33 | func (t genericTransport) SupportsUnixFDs() bool { 34 | return false 35 | } 36 | 37 | func (t genericTransport) EnableUnixFDs() {} 38 | 39 | func (t genericTransport) ReadMessage() (*Message, error) { 40 | return DecodeMessage(t) 41 | } 42 | 43 | func (t genericTransport) SendMessage(msg *Message) error { 44 | for _, v := range msg.Body { 45 | if _, ok := v.(UnixFD); ok { 46 | return errors.New("dbus: unix fd passing not enabled") 47 | } 48 | } 49 | return msg.EncodeTo(t, nativeEndian) 50 | } 51 | -------------------------------------------------------------------------------- /vendor/github.com/armon/go-socks5/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Armon Dadgar 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /captive-browser-dhcpcd-chromium.toml: -------------------------------------------------------------------------------- 1 | # browser is the shell (/bin/sh) command executed once the proxy starts. 2 | # When browser exits, the proxy exits. An extra env var PROXY is available. 3 | # 4 | # Here, we use a separate Chrome instance in Incognito mode, so that 5 | # it can run (and be waited for) alongside the default one, and that 6 | # it maintains no state across runs. To configure this browser open a 7 | # normal window in it, settings will be preserved. 8 | browser = """ 9 | chromium \ 10 | --user-data-dir="$HOME/.chromium-captive" \ 11 | --proxy-server="socks5://$PROXY" \ 12 | --host-resolver-rules="MAP * ~NOTFOUND , EXCLUDE localhost" \ 13 | --no-first-run --new-window --incognito \ 14 | http://example.com 15 | """ 16 | 17 | # dhcp-dns is the shell (/bin/sh) command executed to obtain the DHCP 18 | # DNS server address. The first match of an IPv4 regex is used. 19 | # IPv4 only, because let's be real, it's a captive portal. 20 | # 21 | # `wlan0` is your network interface. 22 | # 23 | dhcp-dns = "dhcpcd -U wlan0 | grep domain_name_servers" 24 | 25 | # socks5-addr is the listen address for the SOCKS5 proxy server. 26 | socks5-addr = "localhost:1666" 27 | 28 | -------------------------------------------------------------------------------- /captive-browser-ubuntu-chrome.toml: -------------------------------------------------------------------------------- 1 | # browser is the shell (/bin/sh) command executed once the proxy starts. 2 | # When browser exits, the proxy exits. An extra env var PROXY is available. 3 | # 4 | # Here, we use a separate Chrome instance in Incognito mode, so that 5 | # it can run (and be waited for) alongside the default one, and that 6 | # it maintains no state across runs. To configure this browser open a 7 | # normal window in it, settings will be preserved. 8 | browser = """ 9 | google-chrome \ 10 | --user-data-dir="$HOME/.google-chrome-captive" \ 11 | --proxy-server="socks5://$PROXY" \ 12 | --host-resolver-rules="MAP * ~NOTFOUND , EXCLUDE localhost" \ 13 | --no-first-run --new-window --incognito \ 14 | http://example.com 15 | """ 16 | 17 | # dhcp-dns is the shell (/bin/sh) command executed to obtain the DHCP 18 | # DNS server address. The first match of an IPv4 regex is used. 19 | # IPv4 only, because let's be real, it's a captive portal. 20 | # 21 | # `wlp3s0` is your network interface (eth0, wlan0 ...) 22 | # 23 | dhcp-dns = "nmcli dev show | grep IP4.DNS" 24 | 25 | # socks5-addr is the listen address for the SOCKS5 proxy server. 26 | socks5-addr = "localhost:1666" 27 | 28 | -------------------------------------------------------------------------------- /vendor/github.com/armon/go-socks5/ruleset.go: -------------------------------------------------------------------------------- 1 | package socks5 2 | 3 | import ( 4 | "golang.org/x/net/context" 5 | ) 6 | 7 | // RuleSet is used to provide custom rules to allow or prohibit actions 8 | type RuleSet interface { 9 | Allow(ctx context.Context, req *Request) (context.Context, bool) 10 | } 11 | 12 | // PermitAll returns a RuleSet which allows all types of connections 13 | func PermitAll() RuleSet { 14 | return &PermitCommand{true, true, true} 15 | } 16 | 17 | // PermitNone returns a RuleSet which disallows all types of connections 18 | func PermitNone() RuleSet { 19 | return &PermitCommand{false, false, false} 20 | } 21 | 22 | // PermitCommand is an implementation of the RuleSet which 23 | // enables filtering supported commands 24 | type PermitCommand struct { 25 | EnableConnect bool 26 | EnableBind bool 27 | EnableAssociate bool 28 | } 29 | 30 | func (p *PermitCommand) Allow(ctx context.Context, req *Request) (context.Context, bool) { 31 | switch req.Command { 32 | case ConnectCommand: 33 | return ctx, p.EnableConnect 34 | case BindCommand: 35 | return ctx, p.EnableBind 36 | case AssociateCommand: 37 | return ctx, p.EnableAssociate 38 | } 39 | 40 | return ctx, false 41 | } 42 | -------------------------------------------------------------------------------- /vendor/github.com/BurntSushi/toml/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package toml provides facilities for decoding and encoding TOML configuration 3 | files via reflection. There is also support for delaying decoding with 4 | the Primitive type, and querying the set of keys in a TOML document with the 5 | MetaData type. 6 | 7 | The specification implemented: https://github.com/toml-lang/toml 8 | 9 | The sub-command github.com/BurntSushi/toml/cmd/tomlv can be used to verify 10 | whether a file is a valid TOML document. It can also be used to print the 11 | type of each key in a TOML document. 12 | 13 | Testing 14 | 15 | There are two important types of tests used for this package. The first is 16 | contained inside '*_test.go' files and uses the standard Go unit testing 17 | framework. These tests are primarily devoted to holistically testing the 18 | decoder and encoder. 19 | 20 | The second type of testing is used to verify the implementation's adherence 21 | to the TOML specification. These tests have been factored into their own 22 | project: https://github.com/BurntSushi/toml-test 23 | 24 | The reason the tests are in a separate project is so that they can be used by 25 | any implementation of TOML. Namely, it is language agnostic. 26 | */ 27 | package toml 28 | -------------------------------------------------------------------------------- /vendor/golang.org/x/net/PATENTS: -------------------------------------------------------------------------------- 1 | Additional IP Rights Grant (Patents) 2 | 3 | "This implementation" means the copyrightable works distributed by 4 | Google as part of the Go project. 5 | 6 | Google hereby grants to You a perpetual, worldwide, non-exclusive, 7 | no-charge, royalty-free, irrevocable (except as stated in this section) 8 | patent license to make, have made, use, offer to sell, sell, import, 9 | transfer and otherwise run, modify and propagate the contents of this 10 | implementation of Go, where such license applies only to those patent 11 | claims, both currently owned or controlled by Google and acquired in 12 | the future, licensable by Google that are necessarily infringed by this 13 | implementation of Go. This grant does not include claims that would be 14 | infringed only as a consequence of further modification of this 15 | implementation. If you or your agent or exclusive licensee institute or 16 | order or agree to the institution of patent litigation against any 17 | entity (including a cross-claim or counterclaim in a lawsuit) alleging 18 | that this implementation of Go or any code incorporated within this 19 | implementation of Go constitutes direct or contributory patent 20 | infringement, or inducement of patent infringement, then any patent 21 | rights granted to you under this License for this implementation of Go 22 | shall terminate as of the date such litigation is filed. 23 | -------------------------------------------------------------------------------- /vendor/github.com/godbus/dbus/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, Georg Reinke (), Google 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 | 11 | 2. Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /captive-browser-mac-chrome.toml: -------------------------------------------------------------------------------- 1 | # browser is the shell (/bin/sh) command executed once the proxy starts. 2 | # When browser exits, the proxy exits. An extra env var PROXY is available. 3 | # 4 | # Here, we use a separate Chrome instance in Incognito mode, so that 5 | # it can run (and be waited for) alongside the default one, and that 6 | # it maintains no state across runs. To configure this browser open a 7 | # normal window in it, settings will be preserved. 8 | browser = """ 9 | open -n -W -a "Google Chrome" --args \ 10 | --user-data-dir="$HOME/Library/Application Support/Google/Captive" \ 11 | --proxy-server="socks5://$PROXY" \ 12 | --host-resolver-rules="MAP * ~NOTFOUND , EXCLUDE localhost" \ 13 | --no-first-run --new-window --incognito \ 14 | http://example.com 15 | """ 16 | 17 | # dhcp-dns is the shell (/bin/sh) command executed to obtain the DHCP 18 | # DNS server address. The first match of an IPv4 regex is used. 19 | # IPv4 only, because let's be real, it's a captive portal. 20 | dhcp-dns = "ipconfig getoption en0 domain_name_server" 21 | 22 | # socks5-addr is the listen address for the SOCKS5 proxy server. 23 | socks5-addr = "localhost:1666" 24 | 25 | # ProTip: to disable the insecure system captive browser see here: 26 | # https://github.com/drduh/macOS-Security-and-Privacy-Guide#captive-portal 27 | # If that doesn't work, disable SIP (remember to re-enable it), and 28 | # rename "/System/Library/CoreServices/Captive Network Assistant.app". 29 | -------------------------------------------------------------------------------- /vendor/golang.org/x/net/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 The Go Authors. 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 | -------------------------------------------------------------------------------- /captive-browser-arch-chrome.toml: -------------------------------------------------------------------------------- 1 | # browser is the shell (/bin/sh) command executed once the proxy starts. 2 | # When browser exits, the proxy exits. An extra env var PROXY is available. 3 | # 4 | # Here, we use a separate Chrome instance in Incognito mode, so that 5 | # it can run (and be waited for) alongside the default one, and that 6 | # it maintains no state across runs. To configure this browser open a 7 | # normal window in it, settings will be preserved. 8 | browser = """ 9 | google-chrome \ 10 | --user-data-dir="$HOME/.google-chrome-captive" \ 11 | --proxy-server="socks5://$PROXY" \ 12 | --host-resolver-rules="MAP * ~NOTFOUND , EXCLUDE localhost" \ 13 | --no-first-run --new-window --incognito \ 14 | http://example.com 15 | """ 16 | 17 | # dhcp-dns is the shell (/bin/sh) command executed to obtain the DHCP 18 | # DNS server address. The first match of an IPv4 regex is used. 19 | # IPv4 only, because let's be real, it's a captive portal. 20 | # 21 | # `wlp3s0` is your network interface (eth0, wlan0 ...) 22 | # 23 | # To install the systemd-networkd-dns command, run: 24 | # 25 | # $ go get github.com/FiloSottile/captive-browser/cmd/systemd-networkd-dns 26 | # 27 | dhcp-dns = "$(go env GOPATH)/bin/systemd-networkd-dns wlp3s0" 28 | 29 | # socks5-addr is the listen address for the SOCKS5 proxy server. 30 | socks5-addr = "localhost:1666" 31 | 32 | # bind-device is the interface over which outbound connections (both HTTP 33 | # and DNS) will be established. It can be used to avoid address space collisions 34 | # but it requires CAP_NET_RAW or root privileges. Disabled by default. 35 | #bind-device = "wlan0" 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # captive-browser 2 | 3 | A more secure, dedicated, Chrome-based captive portal browser that automatically bypasses custom DNS servers. 4 | 5 | `captive-browser` detects the DHCP DNS server and runs a SOCKS5 proxy that resolves hostnames through it. Then it starts a Chrome instance in Incognito mode with a separate data directory and waits for it to exit. 6 | 7 | [Read more on my blog.](https://blog.filippo.io/captive-browser) 8 | 9 | ## Installation 10 | 11 | You'll need Chrome and Go 1.9 or newer. 12 | 13 | ``` 14 | go get -u github.com/FiloSottile/captive-browser 15 | ``` 16 | 17 | You have to install a config file in `$XDG_CONFIG_HOME/captive-browser.toml` (if set) or `~/.config/captive-browser.toml`. You can probably use one of the stock ones below. You might have to modify the network interface. 18 | 19 | ### macOS 20 | 21 | ``` 22 | cp $(go env GOPATH)/src/github.com/FiloSottile/captive-browser/captive-browser-mac-chrome.toml ~/.config/captive-browser.toml 23 | ``` 24 | 25 | To disable the insecure system captive browser [see here](https://github.com/drduh/macOS-Security-and-Privacy-Guide#captive-portal). If that doesn't work, disable SIP (remember to re-enable it), and rename `/System/Library/CoreServices/Captive Network Assistant.app`. 26 | 27 | ### Ubuntu 28 | 29 | ``` 30 | cp $(go env GOPATH)/src/github.com/FiloSottile/captive-browser/captive-browser-ubuntu-chrome.toml ~/.config/captive-browser.toml 31 | ``` 32 | 33 | ### Arch / systemd-networkd 34 | 35 | ``` 36 | go get -u github.com/FiloSottile/captive-browser/cmd/systemd-networkd-dns 37 | cp $(go env GOPATH)/src/github.com/FiloSottile/captive-browser/captive-browser-arch-chrome.toml ~/.config/captive-browser.toml 38 | ``` 39 | 40 | ### Arch / dhcpcd 41 | 42 | ``` 43 | cp $(go env GOPATH)/src/github.com/FiloSottile/captive-browser/captive-browser-dhcpcd-chromium.toml ~/.config/captive-browser.toml 44 | ``` 45 | 46 | ## Usage 47 | 48 | Simply run `captive-browser`, log into the captive portal, and then *quit* (⌘Q / Ctrl-Q) the Chrome instance. 49 | 50 | If the binary is not found, try `$(go env GOPATH)/bin/captive-browser`. 51 | 52 | To configure the browser, open a non-Incognito window (⌘N / Ctrl-N). 53 | -------------------------------------------------------------------------------- /vendor/golang.org/x/net/context/context.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. 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 context defines the Context type, which carries deadlines, 6 | // cancelation signals, and other request-scoped values across API boundaries 7 | // and between processes. 8 | // 9 | // Incoming requests to a server should create a Context, and outgoing calls to 10 | // servers should accept a Context. The chain of function calls between must 11 | // propagate the Context, optionally replacing it with a modified copy created 12 | // using WithDeadline, WithTimeout, WithCancel, or WithValue. 13 | // 14 | // Programs that use Contexts should follow these rules to keep interfaces 15 | // consistent across packages and enable static analysis tools to check context 16 | // propagation: 17 | // 18 | // Do not store Contexts inside a struct type; instead, pass a Context 19 | // explicitly to each function that needs it. The Context should be the first 20 | // parameter, typically named ctx: 21 | // 22 | // func DoSomething(ctx context.Context, arg Arg) error { 23 | // // ... use ctx ... 24 | // } 25 | // 26 | // Do not pass a nil Context, even if a function permits it. Pass context.TODO 27 | // if you are unsure about which Context to use. 28 | // 29 | // Use context Values only for request-scoped data that transits processes and 30 | // APIs, not for passing optional parameters to functions. 31 | // 32 | // The same Context may be passed to functions running in different goroutines; 33 | // Contexts are safe for simultaneous use by multiple goroutines. 34 | // 35 | // See http://blog.golang.org/context for example code for a server that uses 36 | // Contexts. 37 | package context // import "golang.org/x/net/context" 38 | 39 | // Background returns a non-nil, empty Context. It is never canceled, has no 40 | // values, and has no deadline. It is typically used by the main function, 41 | // initialization, and tests, and as the top-level Context for incoming 42 | // requests. 43 | func Background() Context { 44 | return background 45 | } 46 | 47 | // TODO returns a non-nil, empty Context. Code should use context.TODO when 48 | // it's unclear which Context to use or it is not yet available (because the 49 | // surrounding function has not yet been extended to accept a Context 50 | // parameter). TODO is recognized by static analysis tools that determine 51 | // whether Contexts are propagated correctly in a program. 52 | func TODO() Context { 53 | return todo 54 | } 55 | -------------------------------------------------------------------------------- /vendor/github.com/godbus/dbus/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package dbus implements bindings to the D-Bus message bus system. 3 | 4 | To use the message bus API, you first need to connect to a bus (usually the 5 | session or system bus). The acquired connection then can be used to call methods 6 | on remote objects and emit or receive signals. Using the Export method, you can 7 | arrange D-Bus methods calls to be directly translated to method calls on a Go 8 | value. 9 | 10 | Conversion Rules 11 | 12 | For outgoing messages, Go types are automatically converted to the 13 | corresponding D-Bus types. The following types are directly encoded as their 14 | respective D-Bus equivalents: 15 | 16 | Go type | D-Bus type 17 | ------------+----------- 18 | byte | BYTE 19 | bool | BOOLEAN 20 | int16 | INT16 21 | uint16 | UINT16 22 | int | INT32 23 | uint | UINT32 24 | int32 | INT32 25 | uint32 | UINT32 26 | int64 | INT64 27 | uint64 | UINT64 28 | float64 | DOUBLE 29 | string | STRING 30 | ObjectPath | OBJECT_PATH 31 | Signature | SIGNATURE 32 | Variant | VARIANT 33 | interface{} | VARIANT 34 | UnixFDIndex | UNIX_FD 35 | 36 | Slices and arrays encode as ARRAYs of their element type. 37 | 38 | Maps encode as DICTs, provided that their key type can be used as a key for 39 | a DICT. 40 | 41 | Structs other than Variant and Signature encode as a STRUCT containing their 42 | exported fields. Fields whose tags contain `dbus:"-"` and unexported fields will 43 | be skipped. 44 | 45 | Pointers encode as the value they're pointed to. 46 | 47 | Types convertible to one of the base types above will be mapped as the 48 | base type. 49 | 50 | Trying to encode any other type or a slice, map or struct containing an 51 | unsupported type will result in an InvalidTypeError. 52 | 53 | For incoming messages, the inverse of these rules are used, with the exception 54 | of STRUCTs. Incoming STRUCTS are represented as a slice of empty interfaces 55 | containing the struct fields in the correct order. The Store function can be 56 | used to convert such values to Go structs. 57 | 58 | Unix FD passing 59 | 60 | Handling Unix file descriptors deserves special mention. To use them, you should 61 | first check that they are supported on a connection by calling SupportsUnixFDs. 62 | If it returns true, all method of Connection will translate messages containing 63 | UnixFD's to messages that are accompanied by the given file descriptors with the 64 | UnixFD values being substituted by the correct indices. Similarily, the indices 65 | of incoming messages are automatically resolved. It shouldn't be necessary to use 66 | UnixFDIndex. 67 | 68 | */ 69 | package dbus 70 | -------------------------------------------------------------------------------- /cmd/systemd-networkd-dns/main.go: -------------------------------------------------------------------------------- 1 | // The systemd-networkd-dns command obtains the DHCP DNS server via DBus. 2 | // 3 | // For this to work, you must be running both systemd-networkd and 4 | // systemd-resolved and provide the network interface name for your NIC 5 | // that's connected to the DHCP network. 6 | package main 7 | 8 | import ( 9 | "flag" 10 | "fmt" 11 | "log" 12 | "net" 13 | "os" 14 | "strconv" 15 | "strings" 16 | 17 | "github.com/godbus/dbus" 18 | ) 19 | 20 | func main() { 21 | args := os.Args 22 | flag.Usage = func() { 23 | fmt.Printf(`usage: %s 24 | 25 | The systemd-networkd-dns command obtains the DHCP DNS server via DBus. 26 | 27 | For this to work, you must be running both systemd-networkd and 28 | systemd-resolved and provide the network interface name for your NIC 29 | that's connected to the DHCP network. 30 | `, args[0]) 31 | flag.PrintDefaults() 32 | } 33 | flag.Parse() 34 | if len(args) < 2 { 35 | log.Println("error: must provide interface name for DHCP-enabled NIC") 36 | flag.Usage() 37 | os.Exit(2) 38 | } 39 | 40 | dns, err := getDHCPDNSForInterfaceFromDBus(args[1]) 41 | if err != nil { 42 | log.Fatalln(err) 43 | } 44 | fmt.Println(dns) 45 | } 46 | 47 | func getDHCPDNSForInterfaceFromDBus(iface string) (string, error) { 48 | 49 | // First, we need to determine the index of the interface 50 | // for this given interface name. Indicies start at 1. 51 | i, err := net.InterfaceByName(iface) 52 | if err != nil { 53 | return "", fmt.Errorf("net.InterfaceByName() failed: %v", err) 54 | } 55 | 56 | // Connect to the system DBus 57 | conn, err := dbus.SystemBus() 58 | if err != nil { 59 | return "", fmt.Errorf("failed to connect to system DBus: %v", err) 60 | } 61 | 62 | var linkPath dbus.ObjectPath 63 | var callFlags dbus.Flags 64 | 65 | netO := conn.Object("org.freedesktop.resolve1", "/org/freedesktop/resolve1") 66 | netO.Call("org.freedesktop.resolve1.Manager.GetLink", callFlags, i.Index).Store(&linkPath) 67 | 68 | linkO := conn.Object("org.freedesktop.resolve1", linkPath) 69 | variant, err := linkO.GetProperty("org.freedesktop.resolve1.Link.DNS") 70 | if err != nil { 71 | return "", fmt.Errorf("error fetching DNS property from DBus: %v", err) 72 | } 73 | 74 | var variantVal [][]interface{} 75 | variantVal = variant.Value().([][]interface{}) 76 | 77 | // Check the IP version of the nameserver address that was returned 78 | // 2 == AF_INET, 26 == AF_INET6 79 | if variantVal[0][0].(int32) != 2 { 80 | return "", fmt.Errorf("IPv6 nameserver addresses are not currently supported") 81 | 82 | } 83 | 84 | ipVariantBytes := variantVal[0][1].([]uint8) 85 | 86 | s := make([]string, len(ipVariantBytes)) 87 | 88 | for v := range ipVariantBytes { 89 | s[v] = strconv.Itoa(int(ipVariantBytes[v])) 90 | } 91 | return strings.Join(s, "."), nil 92 | } 93 | -------------------------------------------------------------------------------- /vendor/github.com/BurntSushi/toml/type_check.go: -------------------------------------------------------------------------------- 1 | package toml 2 | 3 | // tomlType represents any Go type that corresponds to a TOML type. 4 | // While the first draft of the TOML spec has a simplistic type system that 5 | // probably doesn't need this level of sophistication, we seem to be militating 6 | // toward adding real composite types. 7 | type tomlType interface { 8 | typeString() string 9 | } 10 | 11 | // typeEqual accepts any two types and returns true if they are equal. 12 | func typeEqual(t1, t2 tomlType) bool { 13 | if t1 == nil || t2 == nil { 14 | return false 15 | } 16 | return t1.typeString() == t2.typeString() 17 | } 18 | 19 | func typeIsHash(t tomlType) bool { 20 | return typeEqual(t, tomlHash) || typeEqual(t, tomlArrayHash) 21 | } 22 | 23 | type tomlBaseType string 24 | 25 | func (btype tomlBaseType) typeString() string { 26 | return string(btype) 27 | } 28 | 29 | func (btype tomlBaseType) String() string { 30 | return btype.typeString() 31 | } 32 | 33 | var ( 34 | tomlInteger tomlBaseType = "Integer" 35 | tomlFloat tomlBaseType = "Float" 36 | tomlDatetime tomlBaseType = "Datetime" 37 | tomlString tomlBaseType = "String" 38 | tomlBool tomlBaseType = "Bool" 39 | tomlArray tomlBaseType = "Array" 40 | tomlHash tomlBaseType = "Hash" 41 | tomlArrayHash tomlBaseType = "ArrayHash" 42 | ) 43 | 44 | // typeOfPrimitive returns a tomlType of any primitive value in TOML. 45 | // Primitive values are: Integer, Float, Datetime, String and Bool. 46 | // 47 | // Passing a lexer item other than the following will cause a BUG message 48 | // to occur: itemString, itemBool, itemInteger, itemFloat, itemDatetime. 49 | func (p *parser) typeOfPrimitive(lexItem item) tomlType { 50 | switch lexItem.typ { 51 | case itemInteger: 52 | return tomlInteger 53 | case itemFloat: 54 | return tomlFloat 55 | case itemDatetime: 56 | return tomlDatetime 57 | case itemString: 58 | return tomlString 59 | case itemMultilineString: 60 | return tomlString 61 | case itemRawString: 62 | return tomlString 63 | case itemRawMultilineString: 64 | return tomlString 65 | case itemBool: 66 | return tomlBool 67 | } 68 | p.bug("Cannot infer primitive type of lex item '%s'.", lexItem) 69 | panic("unreachable") 70 | } 71 | 72 | // typeOfArray returns a tomlType for an array given a list of types of its 73 | // values. 74 | // 75 | // In the current spec, if an array is homogeneous, then its type is always 76 | // "Array". If the array is not homogeneous, an error is generated. 77 | func (p *parser) typeOfArray(types []tomlType) tomlType { 78 | // Empty arrays are cool. 79 | if len(types) == 0 { 80 | return tomlArray 81 | } 82 | 83 | theType := types[0] 84 | for _, t := range types[1:] { 85 | if !typeEqual(theType, t) { 86 | p.panicf("Array contains values of type '%s' and '%s', but "+ 87 | "arrays must be homogeneous.", theType, t) 88 | } 89 | } 90 | return tomlArray 91 | } 92 | -------------------------------------------------------------------------------- /vendor/github.com/godbus/dbus/auth_sha1.go: -------------------------------------------------------------------------------- 1 | package dbus 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "crypto/rand" 7 | "crypto/sha1" 8 | "encoding/hex" 9 | "os" 10 | ) 11 | 12 | // AuthCookieSha1 returns an Auth that authenticates as the given user with the 13 | // DBUS_COOKIE_SHA1 mechanism. The home parameter should specify the home 14 | // directory of the user. 15 | func AuthCookieSha1(user, home string) Auth { 16 | return authCookieSha1{user, home} 17 | } 18 | 19 | type authCookieSha1 struct { 20 | user, home string 21 | } 22 | 23 | func (a authCookieSha1) FirstData() ([]byte, []byte, AuthStatus) { 24 | b := make([]byte, 2*len(a.user)) 25 | hex.Encode(b, []byte(a.user)) 26 | return []byte("DBUS_COOKIE_SHA1"), b, AuthContinue 27 | } 28 | 29 | func (a authCookieSha1) HandleData(data []byte) ([]byte, AuthStatus) { 30 | challenge := make([]byte, len(data)/2) 31 | _, err := hex.Decode(challenge, data) 32 | if err != nil { 33 | return nil, AuthError 34 | } 35 | b := bytes.Split(challenge, []byte{' '}) 36 | if len(b) != 3 { 37 | return nil, AuthError 38 | } 39 | context := b[0] 40 | id := b[1] 41 | svchallenge := b[2] 42 | cookie := a.getCookie(context, id) 43 | if cookie == nil { 44 | return nil, AuthError 45 | } 46 | clchallenge := a.generateChallenge() 47 | if clchallenge == nil { 48 | return nil, AuthError 49 | } 50 | hash := sha1.New() 51 | hash.Write(bytes.Join([][]byte{svchallenge, clchallenge, cookie}, []byte{':'})) 52 | hexhash := make([]byte, 2*hash.Size()) 53 | hex.Encode(hexhash, hash.Sum(nil)) 54 | data = append(clchallenge, ' ') 55 | data = append(data, hexhash...) 56 | resp := make([]byte, 2*len(data)) 57 | hex.Encode(resp, data) 58 | return resp, AuthOk 59 | } 60 | 61 | // getCookie searches for the cookie identified by id in context and returns 62 | // the cookie content or nil. (Since HandleData can't return a specific error, 63 | // but only whether an error occured, this function also doesn't bother to 64 | // return an error.) 65 | func (a authCookieSha1) getCookie(context, id []byte) []byte { 66 | file, err := os.Open(a.home + "/.dbus-keyrings/" + string(context)) 67 | if err != nil { 68 | return nil 69 | } 70 | defer file.Close() 71 | rd := bufio.NewReader(file) 72 | for { 73 | line, err := rd.ReadBytes('\n') 74 | if err != nil { 75 | return nil 76 | } 77 | line = line[:len(line)-1] 78 | b := bytes.Split(line, []byte{' '}) 79 | if len(b) != 3 { 80 | return nil 81 | } 82 | if bytes.Equal(b[0], id) { 83 | return b[2] 84 | } 85 | } 86 | } 87 | 88 | // generateChallenge returns a random, hex-encoded challenge, or nil on error 89 | // (see above). 90 | func (a authCookieSha1) generateChallenge() []byte { 91 | b := make([]byte, 16) 92 | n, err := rand.Read(b) 93 | if err != nil { 94 | return nil 95 | } 96 | if n != 16 { 97 | return nil 98 | } 99 | enc := make([]byte, 32) 100 | hex.Encode(enc, b) 101 | return enc 102 | } 103 | -------------------------------------------------------------------------------- /vendor/github.com/godbus/dbus/transport_unixcred_freebsd.go: -------------------------------------------------------------------------------- 1 | // The UnixCredentials system call is currently only implemented on Linux 2 | // http://golang.org/src/pkg/syscall/sockcmsg_linux.go 3 | // https://golang.org/s/go1.4-syscall 4 | // http://code.google.com/p/go/source/browse/unix/sockcmsg_linux.go?repo=sys 5 | 6 | // Local implementation of the UnixCredentials system call for FreeBSD 7 | 8 | package dbus 9 | 10 | /* 11 | const int sizeofPtr = sizeof(void*); 12 | #define _WANT_UCRED 13 | #include 14 | */ 15 | import "C" 16 | 17 | import ( 18 | "io" 19 | "os" 20 | "syscall" 21 | "unsafe" 22 | ) 23 | 24 | // http://golang.org/src/pkg/syscall/ztypes_linux_amd64.go 25 | // https://golang.org/src/syscall/ztypes_freebsd_amd64.go 26 | type Ucred struct { 27 | Pid int32 28 | Uid uint32 29 | Gid uint32 30 | } 31 | 32 | // http://golang.org/src/pkg/syscall/types_linux.go 33 | // https://golang.org/src/syscall/types_freebsd.go 34 | // https://github.com/freebsd/freebsd/blob/master/sys/sys/ucred.h 35 | const ( 36 | SizeofUcred = C.sizeof_struct_ucred 37 | ) 38 | 39 | // http://golang.org/src/pkg/syscall/sockcmsg_unix.go 40 | func cmsgAlignOf(salen int) int { 41 | salign := C.sizeofPtr 42 | 43 | return (salen + salign - 1) & ^(salign - 1) 44 | } 45 | 46 | // http://golang.org/src/pkg/syscall/sockcmsg_unix.go 47 | func cmsgData(h *syscall.Cmsghdr) unsafe.Pointer { 48 | return unsafe.Pointer(uintptr(unsafe.Pointer(h)) + uintptr(cmsgAlignOf(syscall.SizeofCmsghdr))) 49 | } 50 | 51 | // http://golang.org/src/pkg/syscall/sockcmsg_linux.go 52 | // UnixCredentials encodes credentials into a socket control message 53 | // for sending to another process. This can be used for 54 | // authentication. 55 | func UnixCredentials(ucred *Ucred) []byte { 56 | b := make([]byte, syscall.CmsgSpace(SizeofUcred)) 57 | h := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0])) 58 | h.Level = syscall.SOL_SOCKET 59 | h.Type = syscall.SCM_CREDS 60 | h.SetLen(syscall.CmsgLen(SizeofUcred)) 61 | *((*Ucred)(cmsgData(h))) = *ucred 62 | return b 63 | } 64 | 65 | // http://golang.org/src/pkg/syscall/sockcmsg_linux.go 66 | // ParseUnixCredentials decodes a socket control message that contains 67 | // credentials in a Ucred structure. To receive such a message, the 68 | // SO_PASSCRED option must be enabled on the socket. 69 | func ParseUnixCredentials(m *syscall.SocketControlMessage) (*Ucred, error) { 70 | if m.Header.Level != syscall.SOL_SOCKET { 71 | return nil, syscall.EINVAL 72 | } 73 | if m.Header.Type != syscall.SCM_CREDS { 74 | return nil, syscall.EINVAL 75 | } 76 | ucred := *(*Ucred)(unsafe.Pointer(&m.Data[0])) 77 | return &ucred, nil 78 | } 79 | 80 | func (t *unixTransport) SendNullByte() error { 81 | ucred := &Ucred{Pid: int32(os.Getpid()), Uid: uint32(os.Getuid()), Gid: uint32(os.Getgid())} 82 | b := UnixCredentials(ucred) 83 | _, oobn, err := t.UnixConn.WriteMsgUnix([]byte{0}, b, nil) 84 | if err != nil { 85 | return err 86 | } 87 | if oobn != len(b) { 88 | return io.ErrShortWrite 89 | } 90 | return nil 91 | } 92 | -------------------------------------------------------------------------------- /vendor/golang.org/x/net/context/go17.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Go Authors. 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 | // +build go1.7 6 | 7 | package context 8 | 9 | import ( 10 | "context" // standard library's context, as of Go 1.7 11 | "time" 12 | ) 13 | 14 | var ( 15 | todo = context.TODO() 16 | background = context.Background() 17 | ) 18 | 19 | // Canceled is the error returned by Context.Err when the context is canceled. 20 | var Canceled = context.Canceled 21 | 22 | // DeadlineExceeded is the error returned by Context.Err when the context's 23 | // deadline passes. 24 | var DeadlineExceeded = context.DeadlineExceeded 25 | 26 | // WithCancel returns a copy of parent with a new Done channel. The returned 27 | // context's Done channel is closed when the returned cancel function is called 28 | // or when the parent context's Done channel is closed, whichever happens first. 29 | // 30 | // Canceling this context releases resources associated with it, so code should 31 | // call cancel as soon as the operations running in this Context complete. 32 | func WithCancel(parent Context) (ctx Context, cancel CancelFunc) { 33 | ctx, f := context.WithCancel(parent) 34 | return ctx, CancelFunc(f) 35 | } 36 | 37 | // WithDeadline returns a copy of the parent context with the deadline adjusted 38 | // to be no later than d. If the parent's deadline is already earlier than d, 39 | // WithDeadline(parent, d) is semantically equivalent to parent. The returned 40 | // context's Done channel is closed when the deadline expires, when the returned 41 | // cancel function is called, or when the parent context's Done channel is 42 | // closed, whichever happens first. 43 | // 44 | // Canceling this context releases resources associated with it, so code should 45 | // call cancel as soon as the operations running in this Context complete. 46 | func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) { 47 | ctx, f := context.WithDeadline(parent, deadline) 48 | return ctx, CancelFunc(f) 49 | } 50 | 51 | // WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)). 52 | // 53 | // Canceling this context releases resources associated with it, so code should 54 | // call cancel as soon as the operations running in this Context complete: 55 | // 56 | // func slowOperationWithTimeout(ctx context.Context) (Result, error) { 57 | // ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond) 58 | // defer cancel() // releases resources if slowOperation completes before timeout elapses 59 | // return slowOperation(ctx) 60 | // } 61 | func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) { 62 | return WithDeadline(parent, time.Now().Add(timeout)) 63 | } 64 | 65 | // WithValue returns a copy of parent in which the value associated with key is 66 | // val. 67 | // 68 | // Use context Values only for request-scoped data that transits processes and 69 | // APIs, not for passing optional parameters to functions. 70 | func WithValue(parent Context, key interface{}, val interface{}) Context { 71 | return context.WithValue(parent, key, val) 72 | } 73 | -------------------------------------------------------------------------------- /vendor/github.com/godbus/dbus/transport_unixcred_dragonfly.go: -------------------------------------------------------------------------------- 1 | // The UnixCredentials system call is currently only implemented on Linux 2 | // http://golang.org/src/pkg/syscall/sockcmsg_linux.go 3 | // https://golang.org/s/go1.4-syscall 4 | // http://code.google.com/p/go/source/browse/unix/sockcmsg_linux.go?repo=sys 5 | 6 | // Local implementation of the UnixCredentials system call for DragonFly BSD 7 | 8 | package dbus 9 | 10 | /* 11 | #include 12 | */ 13 | import "C" 14 | 15 | import ( 16 | "io" 17 | "os" 18 | "syscall" 19 | "unsafe" 20 | ) 21 | 22 | // http://golang.org/src/pkg/syscall/ztypes_linux_amd64.go 23 | // http://golang.org/src/pkg/syscall/ztypes_dragonfly_amd64.go 24 | type Ucred struct { 25 | Pid int32 26 | Uid uint32 27 | Gid uint32 28 | } 29 | 30 | // http://golang.org/src/pkg/syscall/types_linux.go 31 | // http://golang.org/src/pkg/syscall/types_dragonfly.go 32 | // https://github.com/DragonFlyBSD/DragonFlyBSD/blob/master/sys/sys/ucred.h 33 | const ( 34 | SizeofUcred = C.sizeof_struct_ucred 35 | ) 36 | 37 | // http://golang.org/src/pkg/syscall/sockcmsg_unix.go 38 | func cmsgAlignOf(salen int) int { 39 | // From http://golang.org/src/pkg/syscall/sockcmsg_unix.go 40 | //salign := sizeofPtr 41 | // NOTE: It seems like 64-bit Darwin and DragonFly BSD kernels 42 | // still require 32-bit aligned access to network subsystem. 43 | //if darwin64Bit || dragonfly64Bit { 44 | // salign = 4 45 | //} 46 | salign := 4 47 | return (salen + salign - 1) & ^(salign - 1) 48 | } 49 | 50 | // http://golang.org/src/pkg/syscall/sockcmsg_unix.go 51 | func cmsgData(h *syscall.Cmsghdr) unsafe.Pointer { 52 | return unsafe.Pointer(uintptr(unsafe.Pointer(h)) + uintptr(cmsgAlignOf(syscall.SizeofCmsghdr))) 53 | } 54 | 55 | // http://golang.org/src/pkg/syscall/sockcmsg_linux.go 56 | // UnixCredentials encodes credentials into a socket control message 57 | // for sending to another process. This can be used for 58 | // authentication. 59 | func UnixCredentials(ucred *Ucred) []byte { 60 | b := make([]byte, syscall.CmsgSpace(SizeofUcred)) 61 | h := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0])) 62 | h.Level = syscall.SOL_SOCKET 63 | h.Type = syscall.SCM_CREDS 64 | h.SetLen(syscall.CmsgLen(SizeofUcred)) 65 | *((*Ucred)(cmsgData(h))) = *ucred 66 | return b 67 | } 68 | 69 | // http://golang.org/src/pkg/syscall/sockcmsg_linux.go 70 | // ParseUnixCredentials decodes a socket control message that contains 71 | // credentials in a Ucred structure. To receive such a message, the 72 | // SO_PASSCRED option must be enabled on the socket. 73 | func ParseUnixCredentials(m *syscall.SocketControlMessage) (*Ucred, error) { 74 | if m.Header.Level != syscall.SOL_SOCKET { 75 | return nil, syscall.EINVAL 76 | } 77 | if m.Header.Type != syscall.SCM_CREDS { 78 | return nil, syscall.EINVAL 79 | } 80 | ucred := *(*Ucred)(unsafe.Pointer(&m.Data[0])) 81 | return &ucred, nil 82 | } 83 | 84 | func (t *unixTransport) SendNullByte() error { 85 | ucred := &Ucred{Pid: int32(os.Getpid()), Uid: uint32(os.Getuid()), Gid: uint32(os.Getgid())} 86 | b := UnixCredentials(ucred) 87 | _, oobn, err := t.UnixConn.WriteMsgUnix([]byte{0}, b, nil) 88 | if err != nil { 89 | return err 90 | } 91 | if oobn != len(b) { 92 | return io.ErrShortWrite 93 | } 94 | return nil 95 | } 96 | -------------------------------------------------------------------------------- /vendor/github.com/godbus/dbus/server_interfaces.go: -------------------------------------------------------------------------------- 1 | package dbus 2 | 3 | // Terminator allows a handler to implement a shutdown mechanism that 4 | // is called when the connection terminates. 5 | type Terminator interface { 6 | Terminate() 7 | } 8 | 9 | // Handler is the representation of a D-Bus Application. 10 | // 11 | // The Handler must have a way to lookup objects given 12 | // an ObjectPath. The returned object must implement the 13 | // ServerObject interface. 14 | type Handler interface { 15 | LookupObject(path ObjectPath) (ServerObject, bool) 16 | } 17 | 18 | // ServerObject is the representation of an D-Bus Object. 19 | // 20 | // Objects are registered at a path for a given Handler. 21 | // The Objects implement D-Bus interfaces. The semantics 22 | // of Interface lookup is up to the implementation of 23 | // the ServerObject. The ServerObject implementation may 24 | // choose to implement empty string as a valid interface 25 | // represeting all methods or not per the D-Bus specification. 26 | type ServerObject interface { 27 | LookupInterface(name string) (Interface, bool) 28 | } 29 | 30 | // An Interface is the representation of a D-Bus Interface. 31 | // 32 | // Interfaces are a grouping of methods implemented by the Objects. 33 | // Interfaces are responsible for routing method calls. 34 | type Interface interface { 35 | LookupMethod(name string) (Method, bool) 36 | } 37 | 38 | // A Method represents the exposed methods on D-Bus. 39 | type Method interface { 40 | // Call requires that all arguments are decoded before being passed to it. 41 | Call(args ...interface{}) ([]interface{}, error) 42 | NumArguments() int 43 | NumReturns() int 44 | // ArgumentValue returns a representative value for the argument at position 45 | // it should be of the proper type. reflect.Zero would be a good mechanism 46 | // to use for this Value. 47 | ArgumentValue(position int) interface{} 48 | // ReturnValue returns a representative value for the return at position 49 | // it should be of the proper type. reflect.Zero would be a good mechanism 50 | // to use for this Value. 51 | ReturnValue(position int) interface{} 52 | } 53 | 54 | // An Argument Decoder can decode arguments using the non-standard mechanism 55 | // 56 | // If a method implements this interface then the non-standard 57 | // decoder will be used. 58 | // 59 | // Method arguments must be decoded from the message. 60 | // The mechanism for doing this will vary based on the 61 | // implementation of the method. A normal approach is provided 62 | // as part of this library, but may be replaced with 63 | // any other decoding scheme. 64 | type ArgumentDecoder interface { 65 | // To decode the arguments of a method the sender and message are 66 | // provided incase the semantics of the implementer provides access 67 | // to these as part of the method invocation. 68 | DecodeArguments(conn *Conn, sender string, msg *Message, args []interface{}) ([]interface{}, error) 69 | } 70 | 71 | // A SignalHandler is responsible for delivering a signal. 72 | // 73 | // Signal delivery may be changed from the default channel 74 | // based approach by Handlers implementing the SignalHandler 75 | // interface. 76 | type SignalHandler interface { 77 | DeliverSignal(iface, name string, signal *Signal) 78 | } 79 | 80 | // A DBusError is used to convert a generic object to a D-Bus error. 81 | // 82 | // Any custom error mechanism may implement this interface to provide 83 | // a custom encoding of the error on D-Bus. By default if a normal 84 | // error is returned, it will be encoded as the generic 85 | // "org.freedesktop.DBus.Error.Failed" error. By implementing this 86 | // interface as well a custom encoding may be provided. 87 | type DBusError interface { 88 | DBusError() (string, []interface{}) 89 | } 90 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "io/ioutil" 6 | "log" 7 | "net" 8 | "os" 9 | "os/exec" 10 | "os/user" 11 | "path/filepath" 12 | "regexp" 13 | 14 | "github.com/BurntSushi/toml" 15 | "github.com/armon/go-socks5" 16 | ) 17 | 18 | type UpstreamResolver struct { 19 | r *net.Resolver 20 | } 21 | 22 | func NewUpstreamResolver(upstream string, dialer *net.Dialer) *UpstreamResolver { 23 | return &UpstreamResolver{ 24 | r: &net.Resolver{ 25 | PreferGo: true, 26 | Dial: func(ctx context.Context, network, address string) (net.Conn, error) { 27 | // Redirect all Resolver dials to the upstream. 28 | return dialer.DialContext(ctx, network, net.JoinHostPort(upstream, "53")) 29 | }, 30 | }, 31 | } 32 | } 33 | 34 | func (u *UpstreamResolver) Resolve(ctx context.Context, name string) (context.Context, net.IP, error) { 35 | log.Println("Redirected DNS lookup:", name) 36 | addrs, err := u.r.LookupIPAddr(ctx, name) 37 | if err != nil { 38 | return ctx, nil, err 39 | } 40 | if len(addrs) == 0 { 41 | return ctx, nil, nil 42 | } 43 | // Prefer IPv4, like ResolveIPAddr. I can hear Olafur screaming, but the default 44 | // go-socks5 Resolver uses ResolveIPAddr, and the interface does not allow any better. 45 | for _, addr := range addrs { 46 | if addr.IP.To4() != nil { 47 | return ctx, addr.IP, nil 48 | } 49 | } 50 | return ctx, addrs[0].IP, nil 51 | // (Why the hell does this *return* a context?) 52 | } 53 | 54 | type Config struct { 55 | SOCKS5Addr string `toml:"socks5-addr"` 56 | Browser string `toml:"browser"` 57 | DHCP string `toml:"dhcp-dns"` 58 | BindDevice string `toml:"bind-device"` 59 | } 60 | 61 | func main() { 62 | configPath := os.Getenv("XDG_CONFIG_HOME") 63 | if configPath == "" { 64 | usr, _ := user.Current() 65 | configPath = filepath.Join(usr.HomeDir, ".config") 66 | } 67 | configPath = filepath.Join(configPath, "captive-browser.toml") 68 | tomlData, err := ioutil.ReadFile(configPath) 69 | if err != nil { 70 | log.Fatalln("Failed to read config:", err) 71 | } 72 | var conf Config 73 | if err := toml.Unmarshal(tomlData, &conf); err != nil { 74 | log.Fatalln("Failed to parse config:", err) 75 | } 76 | 77 | log.Printf("Obtaining DHCP DNS server...") 78 | out, err := exec.Command("/bin/sh", "-c", conf.DHCP).Output() 79 | if err != nil { 80 | if err, ok := err.(*exec.ExitError); ok { 81 | os.Stderr.Write(err.Stderr) 82 | } 83 | log.Fatalln("Failed to execute dhcp-dns:", err) 84 | } 85 | match := regexp.MustCompile(`\d{1,3}\.\d{1,3}\.\d{1,3}.\d{1,3}`).Find(out) 86 | if match == nil { 87 | log.Fatalln("IPs not found in dhcp-dns output.") 88 | } 89 | upstream := string(match) 90 | 91 | dialer := &net.Dialer{} 92 | if conf.BindDevice != "" { 93 | dialer.Control = bindToDevice(conf.BindDevice) 94 | } 95 | 96 | srv, err := socks5.New(&socks5.Config{ 97 | Resolver: NewUpstreamResolver(upstream, dialer), 98 | Dial: func(ctx context.Context, network, address string) (net.Conn, error) { 99 | return dialer.DialContext(ctx, network, address) 100 | }, 101 | }) 102 | if err != nil { 103 | log.Fatalln(err) 104 | } 105 | go func() { 106 | log.Printf("SOCKS5 proxy pointing to DNS %s started at %s...", upstream, conf.SOCKS5Addr) 107 | log.Fatalln(srv.ListenAndServe("tcp", conf.SOCKS5Addr)) 108 | }() 109 | 110 | log.Printf("Starting browser...") 111 | cmd := exec.Command("/bin/sh", "-c", conf.Browser) 112 | cmd.Stdout = os.Stdout 113 | cmd.Stderr = os.Stderr 114 | cmd.Env = append(os.Environ(), "PROXY="+conf.SOCKS5Addr) 115 | if err := cmd.Run(); err != nil { 116 | log.Fatalln(err) 117 | } 118 | log.Printf("Browser exited, shutting down...") 119 | } 120 | -------------------------------------------------------------------------------- /vendor/github.com/BurntSushi/toml/decode_meta.go: -------------------------------------------------------------------------------- 1 | package toml 2 | 3 | import "strings" 4 | 5 | // MetaData allows access to meta information about TOML data that may not 6 | // be inferrable via reflection. In particular, whether a key has been defined 7 | // and the TOML type of a key. 8 | type MetaData struct { 9 | mapping map[string]interface{} 10 | types map[string]tomlType 11 | keys []Key 12 | decoded map[string]bool 13 | context Key // Used only during decoding. 14 | } 15 | 16 | // IsDefined returns true if the key given exists in the TOML data. The key 17 | // should be specified hierarchially. e.g., 18 | // 19 | // // access the TOML key 'a.b.c' 20 | // IsDefined("a", "b", "c") 21 | // 22 | // IsDefined will return false if an empty key given. Keys are case sensitive. 23 | func (md *MetaData) IsDefined(key ...string) bool { 24 | if len(key) == 0 { 25 | return false 26 | } 27 | 28 | var hash map[string]interface{} 29 | var ok bool 30 | var hashOrVal interface{} = md.mapping 31 | for _, k := range key { 32 | if hash, ok = hashOrVal.(map[string]interface{}); !ok { 33 | return false 34 | } 35 | if hashOrVal, ok = hash[k]; !ok { 36 | return false 37 | } 38 | } 39 | return true 40 | } 41 | 42 | // Type returns a string representation of the type of the key specified. 43 | // 44 | // Type will return the empty string if given an empty key or a key that 45 | // does not exist. Keys are case sensitive. 46 | func (md *MetaData) Type(key ...string) string { 47 | fullkey := strings.Join(key, ".") 48 | if typ, ok := md.types[fullkey]; ok { 49 | return typ.typeString() 50 | } 51 | return "" 52 | } 53 | 54 | // Key is the type of any TOML key, including key groups. Use (MetaData).Keys 55 | // to get values of this type. 56 | type Key []string 57 | 58 | func (k Key) String() string { 59 | return strings.Join(k, ".") 60 | } 61 | 62 | func (k Key) maybeQuotedAll() string { 63 | var ss []string 64 | for i := range k { 65 | ss = append(ss, k.maybeQuoted(i)) 66 | } 67 | return strings.Join(ss, ".") 68 | } 69 | 70 | func (k Key) maybeQuoted(i int) string { 71 | quote := false 72 | for _, c := range k[i] { 73 | if !isBareKeyChar(c) { 74 | quote = true 75 | break 76 | } 77 | } 78 | if quote { 79 | return "\"" + strings.Replace(k[i], "\"", "\\\"", -1) + "\"" 80 | } 81 | return k[i] 82 | } 83 | 84 | func (k Key) add(piece string) Key { 85 | newKey := make(Key, len(k)+1) 86 | copy(newKey, k) 87 | newKey[len(k)] = piece 88 | return newKey 89 | } 90 | 91 | // Keys returns a slice of every key in the TOML data, including key groups. 92 | // Each key is itself a slice, where the first element is the top of the 93 | // hierarchy and the last is the most specific. 94 | // 95 | // The list will have the same order as the keys appeared in the TOML data. 96 | // 97 | // All keys returned are non-empty. 98 | func (md *MetaData) Keys() []Key { 99 | return md.keys 100 | } 101 | 102 | // Undecoded returns all keys that have not been decoded in the order in which 103 | // they appear in the original TOML document. 104 | // 105 | // This includes keys that haven't been decoded because of a Primitive value. 106 | // Once the Primitive value is decoded, the keys will be considered decoded. 107 | // 108 | // Also note that decoding into an empty interface will result in no decoding, 109 | // and so no keys will be considered decoded. 110 | // 111 | // In this sense, the Undecoded keys correspond to keys in the TOML document 112 | // that do not have a concrete type in your representation. 113 | func (md *MetaData) Undecoded() []Key { 114 | undecoded := make([]Key, 0, len(md.keys)) 115 | for _, key := range md.keys { 116 | if !md.decoded[key.String()] { 117 | undecoded = append(undecoded, key) 118 | } 119 | } 120 | return undecoded 121 | } 122 | -------------------------------------------------------------------------------- /vendor/github.com/godbus/dbus/variant.go: -------------------------------------------------------------------------------- 1 | package dbus 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "reflect" 7 | "sort" 8 | "strconv" 9 | ) 10 | 11 | // Variant represents the D-Bus variant type. 12 | type Variant struct { 13 | sig Signature 14 | value interface{} 15 | } 16 | 17 | // MakeVariant converts the given value to a Variant. It panics if v cannot be 18 | // represented as a D-Bus type. 19 | func MakeVariant(v interface{}) Variant { 20 | return MakeVariantWithSignature(v, SignatureOf(v)) 21 | } 22 | 23 | // MakeVariantWithSignature converts the given value to a Variant. 24 | func MakeVariantWithSignature(v interface{}, s Signature) Variant { 25 | return Variant{s, v} 26 | } 27 | 28 | // ParseVariant parses the given string as a variant as described at 29 | // https://developer.gnome.org/glib/unstable/gvariant-text.html. If sig is not 30 | // empty, it is taken to be the expected signature for the variant. 31 | func ParseVariant(s string, sig Signature) (Variant, error) { 32 | tokens := varLex(s) 33 | p := &varParser{tokens: tokens} 34 | n, err := varMakeNode(p) 35 | if err != nil { 36 | return Variant{}, err 37 | } 38 | if sig.str == "" { 39 | sig, err = varInfer(n) 40 | if err != nil { 41 | return Variant{}, err 42 | } 43 | } 44 | v, err := n.Value(sig) 45 | if err != nil { 46 | return Variant{}, err 47 | } 48 | return MakeVariant(v), nil 49 | } 50 | 51 | // format returns a formatted version of v and whether this string can be parsed 52 | // unambigously. 53 | func (v Variant) format() (string, bool) { 54 | switch v.sig.str[0] { 55 | case 'b', 'i': 56 | return fmt.Sprint(v.value), true 57 | case 'n', 'q', 'u', 'x', 't', 'd', 'h': 58 | return fmt.Sprint(v.value), false 59 | case 's': 60 | return strconv.Quote(v.value.(string)), true 61 | case 'o': 62 | return strconv.Quote(string(v.value.(ObjectPath))), false 63 | case 'g': 64 | return strconv.Quote(v.value.(Signature).str), false 65 | case 'v': 66 | s, unamb := v.value.(Variant).format() 67 | if !unamb { 68 | return "<@" + v.value.(Variant).sig.str + " " + s + ">", true 69 | } 70 | return "<" + s + ">", true 71 | case 'y': 72 | return fmt.Sprintf("%#x", v.value.(byte)), false 73 | } 74 | rv := reflect.ValueOf(v.value) 75 | switch rv.Kind() { 76 | case reflect.Slice: 77 | if rv.Len() == 0 { 78 | return "[]", false 79 | } 80 | unamb := true 81 | buf := bytes.NewBuffer([]byte("[")) 82 | for i := 0; i < rv.Len(); i++ { 83 | // TODO: slooow 84 | s, b := MakeVariant(rv.Index(i).Interface()).format() 85 | unamb = unamb && b 86 | buf.WriteString(s) 87 | if i != rv.Len()-1 { 88 | buf.WriteString(", ") 89 | } 90 | } 91 | buf.WriteByte(']') 92 | return buf.String(), unamb 93 | case reflect.Map: 94 | if rv.Len() == 0 { 95 | return "{}", false 96 | } 97 | unamb := true 98 | var buf bytes.Buffer 99 | kvs := make([]string, rv.Len()) 100 | for i, k := range rv.MapKeys() { 101 | s, b := MakeVariant(k.Interface()).format() 102 | unamb = unamb && b 103 | buf.Reset() 104 | buf.WriteString(s) 105 | buf.WriteString(": ") 106 | s, b = MakeVariant(rv.MapIndex(k).Interface()).format() 107 | unamb = unamb && b 108 | buf.WriteString(s) 109 | kvs[i] = buf.String() 110 | } 111 | buf.Reset() 112 | buf.WriteByte('{') 113 | sort.Strings(kvs) 114 | for i, kv := range kvs { 115 | if i > 0 { 116 | buf.WriteString(", ") 117 | } 118 | buf.WriteString(kv) 119 | } 120 | buf.WriteByte('}') 121 | return buf.String(), unamb 122 | } 123 | return `"INVALID"`, true 124 | } 125 | 126 | // Signature returns the D-Bus signature of the underlying value of v. 127 | func (v Variant) Signature() Signature { 128 | return v.sig 129 | } 130 | 131 | // String returns the string representation of the underlying value of v as 132 | // described at https://developer.gnome.org/glib/unstable/gvariant-text.html. 133 | func (v Variant) String() string { 134 | s, unamb := v.format() 135 | if !unamb { 136 | return "@" + v.sig.str + " " + s 137 | } 138 | return s 139 | } 140 | 141 | // Value returns the underlying value of v. 142 | func (v Variant) Value() interface{} { 143 | return v.value 144 | } 145 | -------------------------------------------------------------------------------- /vendor/golang.org/x/net/context/pre_go19.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. 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 | // +build !go1.9 6 | 7 | package context 8 | 9 | import "time" 10 | 11 | // A Context carries a deadline, a cancelation signal, and other values across 12 | // API boundaries. 13 | // 14 | // Context's methods may be called by multiple goroutines simultaneously. 15 | type Context interface { 16 | // Deadline returns the time when work done on behalf of this context 17 | // should be canceled. Deadline returns ok==false when no deadline is 18 | // set. Successive calls to Deadline return the same results. 19 | Deadline() (deadline time.Time, ok bool) 20 | 21 | // Done returns a channel that's closed when work done on behalf of this 22 | // context should be canceled. Done may return nil if this context can 23 | // never be canceled. Successive calls to Done return the same value. 24 | // 25 | // WithCancel arranges for Done to be closed when cancel is called; 26 | // WithDeadline arranges for Done to be closed when the deadline 27 | // expires; WithTimeout arranges for Done to be closed when the timeout 28 | // elapses. 29 | // 30 | // Done is provided for use in select statements: 31 | // 32 | // // Stream generates values with DoSomething and sends them to out 33 | // // until DoSomething returns an error or ctx.Done is closed. 34 | // func Stream(ctx context.Context, out chan<- Value) error { 35 | // for { 36 | // v, err := DoSomething(ctx) 37 | // if err != nil { 38 | // return err 39 | // } 40 | // select { 41 | // case <-ctx.Done(): 42 | // return ctx.Err() 43 | // case out <- v: 44 | // } 45 | // } 46 | // } 47 | // 48 | // See http://blog.golang.org/pipelines for more examples of how to use 49 | // a Done channel for cancelation. 50 | Done() <-chan struct{} 51 | 52 | // Err returns a non-nil error value after Done is closed. Err returns 53 | // Canceled if the context was canceled or DeadlineExceeded if the 54 | // context's deadline passed. No other values for Err are defined. 55 | // After Done is closed, successive calls to Err return the same value. 56 | Err() error 57 | 58 | // Value returns the value associated with this context for key, or nil 59 | // if no value is associated with key. Successive calls to Value with 60 | // the same key returns the same result. 61 | // 62 | // Use context values only for request-scoped data that transits 63 | // processes and API boundaries, not for passing optional parameters to 64 | // functions. 65 | // 66 | // A key identifies a specific value in a Context. Functions that wish 67 | // to store values in Context typically allocate a key in a global 68 | // variable then use that key as the argument to context.WithValue and 69 | // Context.Value. A key can be any type that supports equality; 70 | // packages should define keys as an unexported type to avoid 71 | // collisions. 72 | // 73 | // Packages that define a Context key should provide type-safe accessors 74 | // for the values stores using that key: 75 | // 76 | // // Package user defines a User type that's stored in Contexts. 77 | // package user 78 | // 79 | // import "golang.org/x/net/context" 80 | // 81 | // // User is the type of value stored in the Contexts. 82 | // type User struct {...} 83 | // 84 | // // key is an unexported type for keys defined in this package. 85 | // // This prevents collisions with keys defined in other packages. 86 | // type key int 87 | // 88 | // // userKey is the key for user.User values in Contexts. It is 89 | // // unexported; clients use user.NewContext and user.FromContext 90 | // // instead of using this key directly. 91 | // var userKey key = 0 92 | // 93 | // // NewContext returns a new Context that carries value u. 94 | // func NewContext(ctx context.Context, u *User) context.Context { 95 | // return context.WithValue(ctx, userKey, u) 96 | // } 97 | // 98 | // // FromContext returns the User value stored in ctx, if any. 99 | // func FromContext(ctx context.Context) (*User, bool) { 100 | // u, ok := ctx.Value(userKey).(*User) 101 | // return u, ok 102 | // } 103 | Value(key interface{}) interface{} 104 | } 105 | 106 | // A CancelFunc tells an operation to abandon its work. 107 | // A CancelFunc does not wait for the work to stop. 108 | // After the first call, subsequent calls to a CancelFunc do nothing. 109 | type CancelFunc func() 110 | -------------------------------------------------------------------------------- /vendor/github.com/armon/go-socks5/auth.go: -------------------------------------------------------------------------------- 1 | package socks5 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | ) 7 | 8 | const ( 9 | NoAuth = uint8(0) 10 | noAcceptable = uint8(255) 11 | UserPassAuth = uint8(2) 12 | userAuthVersion = uint8(1) 13 | authSuccess = uint8(0) 14 | authFailure = uint8(1) 15 | ) 16 | 17 | var ( 18 | UserAuthFailed = fmt.Errorf("User authentication failed") 19 | NoSupportedAuth = fmt.Errorf("No supported authentication mechanism") 20 | ) 21 | 22 | // A Request encapsulates authentication state provided 23 | // during negotiation 24 | type AuthContext struct { 25 | // Provided auth method 26 | Method uint8 27 | // Payload provided during negotiation. 28 | // Keys depend on the used auth method. 29 | // For UserPassauth contains Username 30 | Payload map[string]string 31 | } 32 | 33 | type Authenticator interface { 34 | Authenticate(reader io.Reader, writer io.Writer) (*AuthContext, error) 35 | GetCode() uint8 36 | } 37 | 38 | // NoAuthAuthenticator is used to handle the "No Authentication" mode 39 | type NoAuthAuthenticator struct{} 40 | 41 | func (a NoAuthAuthenticator) GetCode() uint8 { 42 | return NoAuth 43 | } 44 | 45 | func (a NoAuthAuthenticator) Authenticate(reader io.Reader, writer io.Writer) (*AuthContext, error) { 46 | _, err := writer.Write([]byte{socks5Version, NoAuth}) 47 | return &AuthContext{NoAuth, nil}, err 48 | } 49 | 50 | // UserPassAuthenticator is used to handle username/password based 51 | // authentication 52 | type UserPassAuthenticator struct { 53 | Credentials CredentialStore 54 | } 55 | 56 | func (a UserPassAuthenticator) GetCode() uint8 { 57 | return UserPassAuth 58 | } 59 | 60 | func (a UserPassAuthenticator) Authenticate(reader io.Reader, writer io.Writer) (*AuthContext, error) { 61 | // Tell the client to use user/pass auth 62 | if _, err := writer.Write([]byte{socks5Version, UserPassAuth}); err != nil { 63 | return nil, err 64 | } 65 | 66 | // Get the version and username length 67 | header := []byte{0, 0} 68 | if _, err := io.ReadAtLeast(reader, header, 2); err != nil { 69 | return nil, err 70 | } 71 | 72 | // Ensure we are compatible 73 | if header[0] != userAuthVersion { 74 | return nil, fmt.Errorf("Unsupported auth version: %v", header[0]) 75 | } 76 | 77 | // Get the user name 78 | userLen := int(header[1]) 79 | user := make([]byte, userLen) 80 | if _, err := io.ReadAtLeast(reader, user, userLen); err != nil { 81 | return nil, err 82 | } 83 | 84 | // Get the password length 85 | if _, err := reader.Read(header[:1]); err != nil { 86 | return nil, err 87 | } 88 | 89 | // Get the password 90 | passLen := int(header[0]) 91 | pass := make([]byte, passLen) 92 | if _, err := io.ReadAtLeast(reader, pass, passLen); err != nil { 93 | return nil, err 94 | } 95 | 96 | // Verify the password 97 | if a.Credentials.Valid(string(user), string(pass)) { 98 | if _, err := writer.Write([]byte{userAuthVersion, authSuccess}); err != nil { 99 | return nil, err 100 | } 101 | } else { 102 | if _, err := writer.Write([]byte{userAuthVersion, authFailure}); err != nil { 103 | return nil, err 104 | } 105 | return nil, UserAuthFailed 106 | } 107 | 108 | // Done 109 | return &AuthContext{UserPassAuth, map[string]string{"Username": string(user)}}, nil 110 | } 111 | 112 | // authenticate is used to handle connection authentication 113 | func (s *Server) authenticate(conn io.Writer, bufConn io.Reader) (*AuthContext, error) { 114 | // Get the methods 115 | methods, err := readMethods(bufConn) 116 | if err != nil { 117 | return nil, fmt.Errorf("Failed to get auth methods: %v", err) 118 | } 119 | 120 | // Select a usable method 121 | for _, method := range methods { 122 | cator, found := s.authMethods[method] 123 | if found { 124 | return cator.Authenticate(bufConn, conn) 125 | } 126 | } 127 | 128 | // No usable method found 129 | return nil, noAcceptableAuth(conn) 130 | } 131 | 132 | // noAcceptableAuth is used to handle when we have no eligible 133 | // authentication mechanism 134 | func noAcceptableAuth(conn io.Writer) error { 135 | conn.Write([]byte{socks5Version, noAcceptable}) 136 | return NoSupportedAuth 137 | } 138 | 139 | // readMethods is used to read the number of methods 140 | // and proceeding auth methods 141 | func readMethods(r io.Reader) ([]byte, error) { 142 | header := []byte{0} 143 | if _, err := r.Read(header); err != nil { 144 | return nil, err 145 | } 146 | 147 | numMethods := int(header[0]) 148 | methods := make([]byte, numMethods) 149 | _, err := io.ReadAtLeast(r, methods, numMethods) 150 | return methods, err 151 | } 152 | -------------------------------------------------------------------------------- /vendor/github.com/godbus/dbus/object.go: -------------------------------------------------------------------------------- 1 | package dbus 2 | 3 | import ( 4 | "errors" 5 | "strings" 6 | ) 7 | 8 | // BusObject is the interface of a remote object on which methods can be 9 | // invoked. 10 | type BusObject interface { 11 | Call(method string, flags Flags, args ...interface{}) *Call 12 | Go(method string, flags Flags, ch chan *Call, args ...interface{}) *Call 13 | GetProperty(p string) (Variant, error) 14 | Destination() string 15 | Path() ObjectPath 16 | } 17 | 18 | // Object represents a remote object on which methods can be invoked. 19 | type Object struct { 20 | conn *Conn 21 | dest string 22 | path ObjectPath 23 | } 24 | 25 | // Call calls a method with (*Object).Go and waits for its reply. 26 | func (o *Object) Call(method string, flags Flags, args ...interface{}) *Call { 27 | return <-o.Go(method, flags, make(chan *Call, 1), args...).Done 28 | } 29 | 30 | // AddMatchSignal subscribes BusObject to signals from specified interface and 31 | // method (member). 32 | func (o *Object) AddMatchSignal(iface, member string) *Call { 33 | return o.Call( 34 | "org.freedesktop.DBus.AddMatch", 35 | 0, 36 | "type='signal',interface='"+iface+"',member='"+member+"'", 37 | ) 38 | } 39 | 40 | // Go calls a method with the given arguments asynchronously. It returns a 41 | // Call structure representing this method call. The passed channel will 42 | // return the same value once the call is done. If ch is nil, a new channel 43 | // will be allocated. Otherwise, ch has to be buffered or Go will panic. 44 | // 45 | // If the flags include FlagNoReplyExpected, ch is ignored and a Call structure 46 | // is returned with any error in Err and a closed channel in Done containing 47 | // the returned Call as it's one entry. 48 | // 49 | // If the method parameter contains a dot ('.'), the part before the last dot 50 | // specifies the interface on which the method is called. 51 | func (o *Object) Go(method string, flags Flags, ch chan *Call, args ...interface{}) *Call { 52 | iface := "" 53 | i := strings.LastIndex(method, ".") 54 | if i != -1 { 55 | iface = method[:i] 56 | } 57 | method = method[i+1:] 58 | msg := new(Message) 59 | msg.Type = TypeMethodCall 60 | msg.serial = o.conn.getSerial() 61 | msg.Flags = flags & (FlagNoAutoStart | FlagNoReplyExpected) 62 | msg.Headers = make(map[HeaderField]Variant) 63 | msg.Headers[FieldPath] = MakeVariant(o.path) 64 | msg.Headers[FieldDestination] = MakeVariant(o.dest) 65 | msg.Headers[FieldMember] = MakeVariant(method) 66 | if iface != "" { 67 | msg.Headers[FieldInterface] = MakeVariant(iface) 68 | } 69 | msg.Body = args 70 | if len(args) > 0 { 71 | msg.Headers[FieldSignature] = MakeVariant(SignatureOf(args...)) 72 | } 73 | if msg.Flags&FlagNoReplyExpected == 0 { 74 | if ch == nil { 75 | ch = make(chan *Call, 10) 76 | } else if cap(ch) == 0 { 77 | panic("dbus: unbuffered channel passed to (*Object).Go") 78 | } 79 | call := &Call{ 80 | Destination: o.dest, 81 | Path: o.path, 82 | Method: method, 83 | Args: args, 84 | Done: ch, 85 | } 86 | o.conn.callsLck.Lock() 87 | o.conn.calls[msg.serial] = call 88 | o.conn.callsLck.Unlock() 89 | o.conn.outLck.RLock() 90 | if o.conn.closed { 91 | call.Err = ErrClosed 92 | call.Done <- call 93 | } else { 94 | o.conn.out <- msg 95 | } 96 | o.conn.outLck.RUnlock() 97 | return call 98 | } 99 | o.conn.outLck.RLock() 100 | defer o.conn.outLck.RUnlock() 101 | done := make(chan *Call, 1) 102 | call := &Call{ 103 | Err: nil, 104 | Done: done, 105 | } 106 | defer func() { 107 | call.Done <- call 108 | close(done) 109 | }() 110 | if o.conn.closed { 111 | call.Err = ErrClosed 112 | return call 113 | } 114 | o.conn.out <- msg 115 | return call 116 | } 117 | 118 | // GetProperty calls org.freedesktop.DBus.Properties.GetProperty on the given 119 | // object. The property name must be given in interface.member notation. 120 | func (o *Object) GetProperty(p string) (Variant, error) { 121 | idx := strings.LastIndex(p, ".") 122 | if idx == -1 || idx+1 == len(p) { 123 | return Variant{}, errors.New("dbus: invalid property " + p) 124 | } 125 | 126 | iface := p[:idx] 127 | prop := p[idx+1:] 128 | 129 | result := Variant{} 130 | err := o.Call("org.freedesktop.DBus.Properties.Get", 0, iface, prop).Store(&result) 131 | 132 | if err != nil { 133 | return Variant{}, err 134 | } 135 | 136 | return result, nil 137 | } 138 | 139 | // Destination returns the destination that calls on (o *Object) are sent to. 140 | func (o *Object) Destination() string { 141 | return o.dest 142 | } 143 | 144 | // Path returns the path that calls on (o *Object") are sent to. 145 | func (o *Object) Path() ObjectPath { 146 | return o.path 147 | } 148 | -------------------------------------------------------------------------------- /vendor/github.com/armon/go-socks5/socks5.go: -------------------------------------------------------------------------------- 1 | package socks5 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "log" 7 | "net" 8 | "os" 9 | 10 | "golang.org/x/net/context" 11 | ) 12 | 13 | const ( 14 | socks5Version = uint8(5) 15 | ) 16 | 17 | // Config is used to setup and configure a Server 18 | type Config struct { 19 | // AuthMethods can be provided to implement custom authentication 20 | // By default, "auth-less" mode is enabled. 21 | // For password-based auth use UserPassAuthenticator. 22 | AuthMethods []Authenticator 23 | 24 | // If provided, username/password authentication is enabled, 25 | // by appending a UserPassAuthenticator to AuthMethods. If not provided, 26 | // and AUthMethods is nil, then "auth-less" mode is enabled. 27 | Credentials CredentialStore 28 | 29 | // Resolver can be provided to do custom name resolution. 30 | // Defaults to DNSResolver if not provided. 31 | Resolver NameResolver 32 | 33 | // Rules is provided to enable custom logic around permitting 34 | // various commands. If not provided, PermitAll is used. 35 | Rules RuleSet 36 | 37 | // Rewriter can be used to transparently rewrite addresses. 38 | // This is invoked before the RuleSet is invoked. 39 | // Defaults to NoRewrite. 40 | Rewriter AddressRewriter 41 | 42 | // BindIP is used for bind or udp associate 43 | BindIP net.IP 44 | 45 | // Logger can be used to provide a custom log target. 46 | // Defaults to stdout. 47 | Logger *log.Logger 48 | 49 | // Optional function for dialing out 50 | Dial func(ctx context.Context, network, addr string) (net.Conn, error) 51 | } 52 | 53 | // Server is reponsible for accepting connections and handling 54 | // the details of the SOCKS5 protocol 55 | type Server struct { 56 | config *Config 57 | authMethods map[uint8]Authenticator 58 | } 59 | 60 | // New creates a new Server and potentially returns an error 61 | func New(conf *Config) (*Server, error) { 62 | // Ensure we have at least one authentication method enabled 63 | if len(conf.AuthMethods) == 0 { 64 | if conf.Credentials != nil { 65 | conf.AuthMethods = []Authenticator{&UserPassAuthenticator{conf.Credentials}} 66 | } else { 67 | conf.AuthMethods = []Authenticator{&NoAuthAuthenticator{}} 68 | } 69 | } 70 | 71 | // Ensure we have a DNS resolver 72 | if conf.Resolver == nil { 73 | conf.Resolver = DNSResolver{} 74 | } 75 | 76 | // Ensure we have a rule set 77 | if conf.Rules == nil { 78 | conf.Rules = PermitAll() 79 | } 80 | 81 | // Ensure we have a log target 82 | if conf.Logger == nil { 83 | conf.Logger = log.New(os.Stdout, "", log.LstdFlags) 84 | } 85 | 86 | server := &Server{ 87 | config: conf, 88 | } 89 | 90 | server.authMethods = make(map[uint8]Authenticator) 91 | 92 | for _, a := range conf.AuthMethods { 93 | server.authMethods[a.GetCode()] = a 94 | } 95 | 96 | return server, nil 97 | } 98 | 99 | // ListenAndServe is used to create a listener and serve on it 100 | func (s *Server) ListenAndServe(network, addr string) error { 101 | l, err := net.Listen(network, addr) 102 | if err != nil { 103 | return err 104 | } 105 | return s.Serve(l) 106 | } 107 | 108 | // Serve is used to serve connections from a listener 109 | func (s *Server) Serve(l net.Listener) error { 110 | for { 111 | conn, err := l.Accept() 112 | if err != nil { 113 | return err 114 | } 115 | go s.ServeConn(conn) 116 | } 117 | return nil 118 | } 119 | 120 | // ServeConn is used to serve a single connection. 121 | func (s *Server) ServeConn(conn net.Conn) error { 122 | defer conn.Close() 123 | bufConn := bufio.NewReader(conn) 124 | 125 | // Read the version byte 126 | version := []byte{0} 127 | if _, err := bufConn.Read(version); err != nil { 128 | s.config.Logger.Printf("[ERR] socks: Failed to get version byte: %v", err) 129 | return err 130 | } 131 | 132 | // Ensure we are compatible 133 | if version[0] != socks5Version { 134 | err := fmt.Errorf("Unsupported SOCKS version: %v", version) 135 | s.config.Logger.Printf("[ERR] socks: %v", err) 136 | return err 137 | } 138 | 139 | // Authenticate the connection 140 | authContext, err := s.authenticate(conn, bufConn) 141 | if err != nil { 142 | err = fmt.Errorf("Failed to authenticate: %v", err) 143 | s.config.Logger.Printf("[ERR] socks: %v", err) 144 | return err 145 | } 146 | 147 | request, err := NewRequest(bufConn) 148 | if err != nil { 149 | if err == unrecognizedAddrType { 150 | if err := sendReply(conn, addrTypeNotSupported, nil); err != nil { 151 | return fmt.Errorf("Failed to send reply: %v", err) 152 | } 153 | } 154 | return fmt.Errorf("Failed to read destination address: %v", err) 155 | } 156 | request.AuthContext = authContext 157 | if client, ok := conn.RemoteAddr().(*net.TCPAddr); ok { 158 | request.RemoteAddr = &AddrSpec{IP: client.IP, Port: client.Port} 159 | } 160 | 161 | // Process the client request 162 | if err := s.handleRequest(request, conn); err != nil { 163 | err = fmt.Errorf("Failed to handle request: %v", err) 164 | s.config.Logger.Printf("[ERR] socks: %v", err) 165 | return err 166 | } 167 | 168 | return nil 169 | } 170 | -------------------------------------------------------------------------------- /vendor/github.com/godbus/dbus/transport_unix.go: -------------------------------------------------------------------------------- 1 | //+build !windows,!solaris 2 | 3 | package dbus 4 | 5 | import ( 6 | "bytes" 7 | "encoding/binary" 8 | "errors" 9 | "io" 10 | "net" 11 | "syscall" 12 | ) 13 | 14 | type oobReader struct { 15 | conn *net.UnixConn 16 | oob []byte 17 | buf [4096]byte 18 | } 19 | 20 | func (o *oobReader) Read(b []byte) (n int, err error) { 21 | n, oobn, flags, _, err := o.conn.ReadMsgUnix(b, o.buf[:]) 22 | if err != nil { 23 | return n, err 24 | } 25 | if flags&syscall.MSG_CTRUNC != 0 { 26 | return n, errors.New("dbus: control data truncated (too many fds received)") 27 | } 28 | o.oob = append(o.oob, o.buf[:oobn]...) 29 | return n, nil 30 | } 31 | 32 | type unixTransport struct { 33 | *net.UnixConn 34 | hasUnixFDs bool 35 | } 36 | 37 | func newUnixTransport(keys string) (transport, error) { 38 | var err error 39 | 40 | t := new(unixTransport) 41 | abstract := getKey(keys, "abstract") 42 | path := getKey(keys, "path") 43 | switch { 44 | case abstract == "" && path == "": 45 | return nil, errors.New("dbus: invalid address (neither path nor abstract set)") 46 | case abstract != "" && path == "": 47 | t.UnixConn, err = net.DialUnix("unix", nil, &net.UnixAddr{Name: "@" + abstract, Net: "unix"}) 48 | if err != nil { 49 | return nil, err 50 | } 51 | return t, nil 52 | case abstract == "" && path != "": 53 | t.UnixConn, err = net.DialUnix("unix", nil, &net.UnixAddr{Name: path, Net: "unix"}) 54 | if err != nil { 55 | return nil, err 56 | } 57 | return t, nil 58 | default: 59 | return nil, errors.New("dbus: invalid address (both path and abstract set)") 60 | } 61 | } 62 | 63 | func init() { 64 | transports["unix"] = newUnixTransport 65 | } 66 | 67 | func (t *unixTransport) EnableUnixFDs() { 68 | t.hasUnixFDs = true 69 | } 70 | 71 | func (t *unixTransport) ReadMessage() (*Message, error) { 72 | var ( 73 | blen, hlen uint32 74 | csheader [16]byte 75 | headers []header 76 | order binary.ByteOrder 77 | unixfds uint32 78 | ) 79 | // To be sure that all bytes of out-of-band data are read, we use a special 80 | // reader that uses ReadUnix on the underlying connection instead of Read 81 | // and gathers the out-of-band data in a buffer. 82 | rd := &oobReader{conn: t.UnixConn} 83 | // read the first 16 bytes (the part of the header that has a constant size), 84 | // from which we can figure out the length of the rest of the message 85 | if _, err := io.ReadFull(rd, csheader[:]); err != nil { 86 | return nil, err 87 | } 88 | switch csheader[0] { 89 | case 'l': 90 | order = binary.LittleEndian 91 | case 'B': 92 | order = binary.BigEndian 93 | default: 94 | return nil, InvalidMessageError("invalid byte order") 95 | } 96 | // csheader[4:8] -> length of message body, csheader[12:16] -> length of 97 | // header fields (without alignment) 98 | binary.Read(bytes.NewBuffer(csheader[4:8]), order, &blen) 99 | binary.Read(bytes.NewBuffer(csheader[12:]), order, &hlen) 100 | if hlen%8 != 0 { 101 | hlen += 8 - (hlen % 8) 102 | } 103 | 104 | // decode headers and look for unix fds 105 | headerdata := make([]byte, hlen+4) 106 | copy(headerdata, csheader[12:]) 107 | if _, err := io.ReadFull(t, headerdata[4:]); err != nil { 108 | return nil, err 109 | } 110 | dec := newDecoder(bytes.NewBuffer(headerdata), order) 111 | dec.pos = 12 112 | vs, err := dec.Decode(Signature{"a(yv)"}) 113 | if err != nil { 114 | return nil, err 115 | } 116 | Store(vs, &headers) 117 | for _, v := range headers { 118 | if v.Field == byte(FieldUnixFDs) { 119 | unixfds, _ = v.Variant.value.(uint32) 120 | } 121 | } 122 | all := make([]byte, 16+hlen+blen) 123 | copy(all, csheader[:]) 124 | copy(all[16:], headerdata[4:]) 125 | if _, err := io.ReadFull(rd, all[16+hlen:]); err != nil { 126 | return nil, err 127 | } 128 | if unixfds != 0 { 129 | if !t.hasUnixFDs { 130 | return nil, errors.New("dbus: got unix fds on unsupported transport") 131 | } 132 | // read the fds from the OOB data 133 | scms, err := syscall.ParseSocketControlMessage(rd.oob) 134 | if err != nil { 135 | return nil, err 136 | } 137 | if len(scms) != 1 { 138 | return nil, errors.New("dbus: received more than one socket control message") 139 | } 140 | fds, err := syscall.ParseUnixRights(&scms[0]) 141 | if err != nil { 142 | return nil, err 143 | } 144 | msg, err := DecodeMessage(bytes.NewBuffer(all)) 145 | if err != nil { 146 | return nil, err 147 | } 148 | // substitute the values in the message body (which are indices for the 149 | // array receiver via OOB) with the actual values 150 | for i, v := range msg.Body { 151 | if j, ok := v.(UnixFDIndex); ok { 152 | if uint32(j) >= unixfds { 153 | return nil, InvalidMessageError("invalid index for unix fd") 154 | } 155 | msg.Body[i] = UnixFD(fds[j]) 156 | } 157 | } 158 | return msg, nil 159 | } 160 | return DecodeMessage(bytes.NewBuffer(all)) 161 | } 162 | 163 | func (t *unixTransport) SendMessage(msg *Message) error { 164 | fds := make([]int, 0) 165 | for i, v := range msg.Body { 166 | if fd, ok := v.(UnixFD); ok { 167 | msg.Body[i] = UnixFDIndex(len(fds)) 168 | fds = append(fds, int(fd)) 169 | } 170 | } 171 | if len(fds) != 0 { 172 | if !t.hasUnixFDs { 173 | return errors.New("dbus: unix fd passing not enabled") 174 | } 175 | msg.Headers[FieldUnixFDs] = MakeVariant(uint32(len(fds))) 176 | oob := syscall.UnixRights(fds...) 177 | buf := new(bytes.Buffer) 178 | msg.EncodeTo(buf, nativeEndian) 179 | n, oobn, err := t.UnixConn.WriteMsgUnix(buf.Bytes(), oob, nil) 180 | if err != nil { 181 | return err 182 | } 183 | if n != buf.Len() || oobn != len(oob) { 184 | return io.ErrShortWrite 185 | } 186 | } else { 187 | if err := msg.EncodeTo(t, nativeEndian); err != nil { 188 | return nil 189 | } 190 | } 191 | return nil 192 | } 193 | 194 | func (t *unixTransport) SupportsUnixFDs() bool { 195 | return true 196 | } 197 | -------------------------------------------------------------------------------- /vendor/github.com/godbus/dbus/decoder.go: -------------------------------------------------------------------------------- 1 | package dbus 2 | 3 | import ( 4 | "encoding/binary" 5 | "io" 6 | "reflect" 7 | ) 8 | 9 | type decoder struct { 10 | in io.Reader 11 | order binary.ByteOrder 12 | pos int 13 | } 14 | 15 | // newDecoder returns a new decoder that reads values from in. The input is 16 | // expected to be in the given byte order. 17 | func newDecoder(in io.Reader, order binary.ByteOrder) *decoder { 18 | dec := new(decoder) 19 | dec.in = in 20 | dec.order = order 21 | return dec 22 | } 23 | 24 | // align aligns the input to the given boundary and panics on error. 25 | func (dec *decoder) align(n int) { 26 | if dec.pos%n != 0 { 27 | newpos := (dec.pos + n - 1) & ^(n - 1) 28 | empty := make([]byte, newpos-dec.pos) 29 | if _, err := io.ReadFull(dec.in, empty); err != nil { 30 | panic(err) 31 | } 32 | dec.pos = newpos 33 | } 34 | } 35 | 36 | // Calls binary.Read(dec.in, dec.order, v) and panics on read errors. 37 | func (dec *decoder) binread(v interface{}) { 38 | if err := binary.Read(dec.in, dec.order, v); err != nil { 39 | panic(err) 40 | } 41 | } 42 | 43 | func (dec *decoder) Decode(sig Signature) (vs []interface{}, err error) { 44 | defer func() { 45 | var ok bool 46 | v := recover() 47 | if err, ok = v.(error); ok { 48 | if err == io.EOF || err == io.ErrUnexpectedEOF { 49 | err = FormatError("unexpected EOF") 50 | } 51 | } 52 | }() 53 | vs = make([]interface{}, 0) 54 | s := sig.str 55 | for s != "" { 56 | err, rem := validSingle(s, 0) 57 | if err != nil { 58 | return nil, err 59 | } 60 | v := dec.decode(s[:len(s)-len(rem)], 0) 61 | vs = append(vs, v) 62 | s = rem 63 | } 64 | return vs, nil 65 | } 66 | 67 | func (dec *decoder) decode(s string, depth int) interface{} { 68 | dec.align(alignment(typeFor(s))) 69 | switch s[0] { 70 | case 'y': 71 | var b [1]byte 72 | if _, err := dec.in.Read(b[:]); err != nil { 73 | panic(err) 74 | } 75 | dec.pos++ 76 | return b[0] 77 | case 'b': 78 | i := dec.decode("u", depth).(uint32) 79 | switch { 80 | case i == 0: 81 | return false 82 | case i == 1: 83 | return true 84 | default: 85 | panic(FormatError("invalid value for boolean")) 86 | } 87 | case 'n': 88 | var i int16 89 | dec.binread(&i) 90 | dec.pos += 2 91 | return i 92 | case 'i': 93 | var i int32 94 | dec.binread(&i) 95 | dec.pos += 4 96 | return i 97 | case 'x': 98 | var i int64 99 | dec.binread(&i) 100 | dec.pos += 8 101 | return i 102 | case 'q': 103 | var i uint16 104 | dec.binread(&i) 105 | dec.pos += 2 106 | return i 107 | case 'u': 108 | var i uint32 109 | dec.binread(&i) 110 | dec.pos += 4 111 | return i 112 | case 't': 113 | var i uint64 114 | dec.binread(&i) 115 | dec.pos += 8 116 | return i 117 | case 'd': 118 | var f float64 119 | dec.binread(&f) 120 | dec.pos += 8 121 | return f 122 | case 's': 123 | length := dec.decode("u", depth).(uint32) 124 | b := make([]byte, int(length)+1) 125 | if _, err := io.ReadFull(dec.in, b); err != nil { 126 | panic(err) 127 | } 128 | dec.pos += int(length) + 1 129 | return string(b[:len(b)-1]) 130 | case 'o': 131 | return ObjectPath(dec.decode("s", depth).(string)) 132 | case 'g': 133 | length := dec.decode("y", depth).(byte) 134 | b := make([]byte, int(length)+1) 135 | if _, err := io.ReadFull(dec.in, b); err != nil { 136 | panic(err) 137 | } 138 | dec.pos += int(length) + 1 139 | sig, err := ParseSignature(string(b[:len(b)-1])) 140 | if err != nil { 141 | panic(err) 142 | } 143 | return sig 144 | case 'v': 145 | if depth >= 64 { 146 | panic(FormatError("input exceeds container depth limit")) 147 | } 148 | var variant Variant 149 | sig := dec.decode("g", depth).(Signature) 150 | if len(sig.str) == 0 { 151 | panic(FormatError("variant signature is empty")) 152 | } 153 | err, rem := validSingle(sig.str, 0) 154 | if err != nil { 155 | panic(err) 156 | } 157 | if rem != "" { 158 | panic(FormatError("variant signature has multiple types")) 159 | } 160 | variant.sig = sig 161 | variant.value = dec.decode(sig.str, depth+1) 162 | return variant 163 | case 'h': 164 | return UnixFDIndex(dec.decode("u", depth).(uint32)) 165 | case 'a': 166 | if len(s) > 1 && s[1] == '{' { 167 | ksig := s[2:3] 168 | vsig := s[3 : len(s)-1] 169 | v := reflect.MakeMap(reflect.MapOf(typeFor(ksig), typeFor(vsig))) 170 | if depth >= 63 { 171 | panic(FormatError("input exceeds container depth limit")) 172 | } 173 | length := dec.decode("u", depth).(uint32) 174 | // Even for empty maps, the correct padding must be included 175 | dec.align(8) 176 | spos := dec.pos 177 | for dec.pos < spos+int(length) { 178 | dec.align(8) 179 | if !isKeyType(v.Type().Key()) { 180 | panic(InvalidTypeError{v.Type()}) 181 | } 182 | kv := dec.decode(ksig, depth+2) 183 | vv := dec.decode(vsig, depth+2) 184 | v.SetMapIndex(reflect.ValueOf(kv), reflect.ValueOf(vv)) 185 | } 186 | return v.Interface() 187 | } 188 | if depth >= 64 { 189 | panic(FormatError("input exceeds container depth limit")) 190 | } 191 | length := dec.decode("u", depth).(uint32) 192 | v := reflect.MakeSlice(reflect.SliceOf(typeFor(s[1:])), 0, int(length)) 193 | // Even for empty arrays, the correct padding must be included 194 | dec.align(alignment(typeFor(s[1:]))) 195 | spos := dec.pos 196 | for dec.pos < spos+int(length) { 197 | ev := dec.decode(s[1:], depth+1) 198 | v = reflect.Append(v, reflect.ValueOf(ev)) 199 | } 200 | return v.Interface() 201 | case '(': 202 | if depth >= 64 { 203 | panic(FormatError("input exceeds container depth limit")) 204 | } 205 | dec.align(8) 206 | v := make([]interface{}, 0) 207 | s = s[1 : len(s)-1] 208 | for s != "" { 209 | err, rem := validSingle(s, 0) 210 | if err != nil { 211 | panic(err) 212 | } 213 | ev := dec.decode(s[:len(s)-len(rem)], depth+1) 214 | v = append(v, ev) 215 | s = rem 216 | } 217 | return v 218 | default: 219 | panic(SignatureError{Sig: s}) 220 | } 221 | } 222 | 223 | // A FormatError is an error in the wire format. 224 | type FormatError string 225 | 226 | func (e FormatError) Error() string { 227 | return "dbus: wire format error: " + string(e) 228 | } 229 | -------------------------------------------------------------------------------- /vendor/github.com/godbus/dbus/variant_lexer.go: -------------------------------------------------------------------------------- 1 | package dbus 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | "unicode" 7 | "unicode/utf8" 8 | ) 9 | 10 | // Heavily inspired by the lexer from text/template. 11 | 12 | type varToken struct { 13 | typ varTokenType 14 | val string 15 | } 16 | 17 | type varTokenType byte 18 | 19 | const ( 20 | tokEOF varTokenType = iota 21 | tokError 22 | tokNumber 23 | tokString 24 | tokBool 25 | tokArrayStart 26 | tokArrayEnd 27 | tokDictStart 28 | tokDictEnd 29 | tokVariantStart 30 | tokVariantEnd 31 | tokComma 32 | tokColon 33 | tokType 34 | tokByteString 35 | ) 36 | 37 | type varLexer struct { 38 | input string 39 | start int 40 | pos int 41 | width int 42 | tokens []varToken 43 | } 44 | 45 | type lexState func(*varLexer) lexState 46 | 47 | func varLex(s string) []varToken { 48 | l := &varLexer{input: s} 49 | l.run() 50 | return l.tokens 51 | } 52 | 53 | func (l *varLexer) accept(valid string) bool { 54 | if strings.IndexRune(valid, l.next()) >= 0 { 55 | return true 56 | } 57 | l.backup() 58 | return false 59 | } 60 | 61 | func (l *varLexer) backup() { 62 | l.pos -= l.width 63 | } 64 | 65 | func (l *varLexer) emit(t varTokenType) { 66 | l.tokens = append(l.tokens, varToken{t, l.input[l.start:l.pos]}) 67 | l.start = l.pos 68 | } 69 | 70 | func (l *varLexer) errorf(format string, v ...interface{}) lexState { 71 | l.tokens = append(l.tokens, varToken{ 72 | tokError, 73 | fmt.Sprintf(format, v...), 74 | }) 75 | return nil 76 | } 77 | 78 | func (l *varLexer) ignore() { 79 | l.start = l.pos 80 | } 81 | 82 | func (l *varLexer) next() rune { 83 | var r rune 84 | 85 | if l.pos >= len(l.input) { 86 | l.width = 0 87 | return -1 88 | } 89 | r, l.width = utf8.DecodeRuneInString(l.input[l.pos:]) 90 | l.pos += l.width 91 | return r 92 | } 93 | 94 | func (l *varLexer) run() { 95 | for state := varLexNormal; state != nil; { 96 | state = state(l) 97 | } 98 | } 99 | 100 | func (l *varLexer) peek() rune { 101 | r := l.next() 102 | l.backup() 103 | return r 104 | } 105 | 106 | func varLexNormal(l *varLexer) lexState { 107 | for { 108 | r := l.next() 109 | switch { 110 | case r == -1: 111 | l.emit(tokEOF) 112 | return nil 113 | case r == '[': 114 | l.emit(tokArrayStart) 115 | case r == ']': 116 | l.emit(tokArrayEnd) 117 | case r == '{': 118 | l.emit(tokDictStart) 119 | case r == '}': 120 | l.emit(tokDictEnd) 121 | case r == '<': 122 | l.emit(tokVariantStart) 123 | case r == '>': 124 | l.emit(tokVariantEnd) 125 | case r == ':': 126 | l.emit(tokColon) 127 | case r == ',': 128 | l.emit(tokComma) 129 | case r == '\'' || r == '"': 130 | l.backup() 131 | return varLexString 132 | case r == '@': 133 | l.backup() 134 | return varLexType 135 | case unicode.IsSpace(r): 136 | l.ignore() 137 | case unicode.IsNumber(r) || r == '+' || r == '-': 138 | l.backup() 139 | return varLexNumber 140 | case r == 'b': 141 | pos := l.start 142 | if n := l.peek(); n == '"' || n == '\'' { 143 | return varLexByteString 144 | } 145 | // not a byte string; try to parse it as a type or bool below 146 | l.pos = pos + 1 147 | l.width = 1 148 | fallthrough 149 | default: 150 | // either a bool or a type. Try bools first. 151 | l.backup() 152 | if l.pos+4 <= len(l.input) { 153 | if l.input[l.pos:l.pos+4] == "true" { 154 | l.pos += 4 155 | l.emit(tokBool) 156 | continue 157 | } 158 | } 159 | if l.pos+5 <= len(l.input) { 160 | if l.input[l.pos:l.pos+5] == "false" { 161 | l.pos += 5 162 | l.emit(tokBool) 163 | continue 164 | } 165 | } 166 | // must be a type. 167 | return varLexType 168 | } 169 | } 170 | } 171 | 172 | var varTypeMap = map[string]string{ 173 | "boolean": "b", 174 | "byte": "y", 175 | "int16": "n", 176 | "uint16": "q", 177 | "int32": "i", 178 | "uint32": "u", 179 | "int64": "x", 180 | "uint64": "t", 181 | "double": "f", 182 | "string": "s", 183 | "objectpath": "o", 184 | "signature": "g", 185 | } 186 | 187 | func varLexByteString(l *varLexer) lexState { 188 | q := l.next() 189 | Loop: 190 | for { 191 | switch l.next() { 192 | case '\\': 193 | if r := l.next(); r != -1 { 194 | break 195 | } 196 | fallthrough 197 | case -1: 198 | return l.errorf("unterminated bytestring") 199 | case q: 200 | break Loop 201 | } 202 | } 203 | l.emit(tokByteString) 204 | return varLexNormal 205 | } 206 | 207 | func varLexNumber(l *varLexer) lexState { 208 | l.accept("+-") 209 | digits := "0123456789" 210 | if l.accept("0") { 211 | if l.accept("x") { 212 | digits = "0123456789abcdefABCDEF" 213 | } else { 214 | digits = "01234567" 215 | } 216 | } 217 | for strings.IndexRune(digits, l.next()) >= 0 { 218 | } 219 | l.backup() 220 | if l.accept(".") { 221 | for strings.IndexRune(digits, l.next()) >= 0 { 222 | } 223 | l.backup() 224 | } 225 | if l.accept("eE") { 226 | l.accept("+-") 227 | for strings.IndexRune("0123456789", l.next()) >= 0 { 228 | } 229 | l.backup() 230 | } 231 | if r := l.peek(); unicode.IsLetter(r) { 232 | l.next() 233 | return l.errorf("bad number syntax: %q", l.input[l.start:l.pos]) 234 | } 235 | l.emit(tokNumber) 236 | return varLexNormal 237 | } 238 | 239 | func varLexString(l *varLexer) lexState { 240 | q := l.next() 241 | Loop: 242 | for { 243 | switch l.next() { 244 | case '\\': 245 | if r := l.next(); r != -1 { 246 | break 247 | } 248 | fallthrough 249 | case -1: 250 | return l.errorf("unterminated string") 251 | case q: 252 | break Loop 253 | } 254 | } 255 | l.emit(tokString) 256 | return varLexNormal 257 | } 258 | 259 | func varLexType(l *varLexer) lexState { 260 | at := l.accept("@") 261 | for { 262 | r := l.next() 263 | if r == -1 { 264 | break 265 | } 266 | if unicode.IsSpace(r) { 267 | l.backup() 268 | break 269 | } 270 | } 271 | if at { 272 | if _, err := ParseSignature(l.input[l.start+1 : l.pos]); err != nil { 273 | return l.errorf("%s", err) 274 | } 275 | } else { 276 | if _, ok := varTypeMap[l.input[l.start:l.pos]]; ok { 277 | l.emit(tokType) 278 | return varLexNormal 279 | } 280 | return l.errorf("unrecognized type %q", l.input[l.start:l.pos]) 281 | } 282 | l.emit(tokType) 283 | return varLexNormal 284 | } 285 | -------------------------------------------------------------------------------- /vendor/github.com/godbus/dbus/encoder.go: -------------------------------------------------------------------------------- 1 | package dbus 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "io" 7 | "reflect" 8 | ) 9 | 10 | // An encoder encodes values to the D-Bus wire format. 11 | type encoder struct { 12 | out io.Writer 13 | order binary.ByteOrder 14 | pos int 15 | } 16 | 17 | // NewEncoder returns a new encoder that writes to out in the given byte order. 18 | func newEncoder(out io.Writer, order binary.ByteOrder) *encoder { 19 | return newEncoderAtOffset(out, 0, order) 20 | } 21 | 22 | // newEncoderAtOffset returns a new encoder that writes to out in the given 23 | // byte order. Specify the offset to initialize pos for proper alignment 24 | // computation. 25 | func newEncoderAtOffset(out io.Writer, offset int, order binary.ByteOrder) *encoder { 26 | enc := new(encoder) 27 | enc.out = out 28 | enc.order = order 29 | enc.pos = offset 30 | return enc 31 | } 32 | 33 | // Aligns the next output to be on a multiple of n. Panics on write errors. 34 | func (enc *encoder) align(n int) { 35 | pad := enc.padding(0, n) 36 | if pad > 0 { 37 | empty := make([]byte, pad) 38 | if _, err := enc.out.Write(empty); err != nil { 39 | panic(err) 40 | } 41 | enc.pos += pad 42 | } 43 | } 44 | 45 | // pad returns the number of bytes of padding, based on current position and additional offset. 46 | // and alignment. 47 | func (enc *encoder) padding(offset, algn int) int { 48 | abs := enc.pos + offset 49 | if abs%algn != 0 { 50 | newabs := (abs + algn - 1) & ^(algn - 1) 51 | return newabs - abs 52 | } 53 | return 0 54 | } 55 | 56 | // Calls binary.Write(enc.out, enc.order, v) and panics on write errors. 57 | func (enc *encoder) binwrite(v interface{}) { 58 | if err := binary.Write(enc.out, enc.order, v); err != nil { 59 | panic(err) 60 | } 61 | } 62 | 63 | // Encode encodes the given values to the underyling reader. All written values 64 | // are aligned properly as required by the D-Bus spec. 65 | func (enc *encoder) Encode(vs ...interface{}) (err error) { 66 | defer func() { 67 | err, _ = recover().(error) 68 | }() 69 | for _, v := range vs { 70 | enc.encode(reflect.ValueOf(v), 0) 71 | } 72 | return nil 73 | } 74 | 75 | // encode encodes the given value to the writer and panics on error. depth holds 76 | // the depth of the container nesting. 77 | func (enc *encoder) encode(v reflect.Value, depth int) { 78 | enc.align(alignment(v.Type())) 79 | switch v.Kind() { 80 | case reflect.Uint8: 81 | var b [1]byte 82 | b[0] = byte(v.Uint()) 83 | if _, err := enc.out.Write(b[:]); err != nil { 84 | panic(err) 85 | } 86 | enc.pos++ 87 | case reflect.Bool: 88 | if v.Bool() { 89 | enc.encode(reflect.ValueOf(uint32(1)), depth) 90 | } else { 91 | enc.encode(reflect.ValueOf(uint32(0)), depth) 92 | } 93 | case reflect.Int16: 94 | enc.binwrite(int16(v.Int())) 95 | enc.pos += 2 96 | case reflect.Uint16: 97 | enc.binwrite(uint16(v.Uint())) 98 | enc.pos += 2 99 | case reflect.Int, reflect.Int32: 100 | enc.binwrite(int32(v.Int())) 101 | enc.pos += 4 102 | case reflect.Uint, reflect.Uint32: 103 | enc.binwrite(uint32(v.Uint())) 104 | enc.pos += 4 105 | case reflect.Int64: 106 | enc.binwrite(v.Int()) 107 | enc.pos += 8 108 | case reflect.Uint64: 109 | enc.binwrite(v.Uint()) 110 | enc.pos += 8 111 | case reflect.Float64: 112 | enc.binwrite(v.Float()) 113 | enc.pos += 8 114 | case reflect.String: 115 | enc.encode(reflect.ValueOf(uint32(len(v.String()))), depth) 116 | b := make([]byte, v.Len()+1) 117 | copy(b, v.String()) 118 | b[len(b)-1] = 0 119 | n, err := enc.out.Write(b) 120 | if err != nil { 121 | panic(err) 122 | } 123 | enc.pos += n 124 | case reflect.Ptr: 125 | enc.encode(v.Elem(), depth) 126 | case reflect.Slice, reflect.Array: 127 | if depth >= 64 { 128 | panic(FormatError("input exceeds container depth limit")) 129 | } 130 | // Lookahead offset: 4 bytes for uint32 length (with alignment), 131 | // plus alignment for elements. 132 | n := enc.padding(0, 4) + 4 133 | offset := enc.pos + n + enc.padding(n, alignment(v.Type().Elem())) 134 | 135 | var buf bytes.Buffer 136 | bufenc := newEncoderAtOffset(&buf, offset, enc.order) 137 | 138 | for i := 0; i < v.Len(); i++ { 139 | bufenc.encode(v.Index(i), depth+1) 140 | } 141 | enc.encode(reflect.ValueOf(uint32(buf.Len())), depth) 142 | length := buf.Len() 143 | enc.align(alignment(v.Type().Elem())) 144 | if _, err := buf.WriteTo(enc.out); err != nil { 145 | panic(err) 146 | } 147 | enc.pos += length 148 | case reflect.Struct: 149 | if depth >= 64 && v.Type() != signatureType { 150 | panic(FormatError("input exceeds container depth limit")) 151 | } 152 | switch t := v.Type(); t { 153 | case signatureType: 154 | str := v.Field(0) 155 | enc.encode(reflect.ValueOf(byte(str.Len())), depth+1) 156 | b := make([]byte, str.Len()+1) 157 | copy(b, str.String()) 158 | b[len(b)-1] = 0 159 | n, err := enc.out.Write(b) 160 | if err != nil { 161 | panic(err) 162 | } 163 | enc.pos += n 164 | case variantType: 165 | variant := v.Interface().(Variant) 166 | enc.encode(reflect.ValueOf(variant.sig), depth+1) 167 | enc.encode(reflect.ValueOf(variant.value), depth+1) 168 | default: 169 | for i := 0; i < v.Type().NumField(); i++ { 170 | field := t.Field(i) 171 | if field.PkgPath == "" && field.Tag.Get("dbus") != "-" { 172 | enc.encode(v.Field(i), depth+1) 173 | } 174 | } 175 | } 176 | case reflect.Map: 177 | // Maps are arrays of structures, so they actually increase the depth by 178 | // 2. 179 | if depth >= 63 { 180 | panic(FormatError("input exceeds container depth limit")) 181 | } 182 | if !isKeyType(v.Type().Key()) { 183 | panic(InvalidTypeError{v.Type()}) 184 | } 185 | keys := v.MapKeys() 186 | // Lookahead offset: 4 bytes for uint32 length (with alignment), 187 | // plus 8-byte alignment 188 | n := enc.padding(0, 4) + 4 189 | offset := enc.pos + n + enc.padding(n, 8) 190 | 191 | var buf bytes.Buffer 192 | bufenc := newEncoderAtOffset(&buf, offset, enc.order) 193 | for _, k := range keys { 194 | bufenc.align(8) 195 | bufenc.encode(k, depth+2) 196 | bufenc.encode(v.MapIndex(k), depth+2) 197 | } 198 | enc.encode(reflect.ValueOf(uint32(buf.Len())), depth) 199 | length := buf.Len() 200 | enc.align(8) 201 | if _, err := buf.WriteTo(enc.out); err != nil { 202 | panic(err) 203 | } 204 | enc.pos += length 205 | case reflect.Interface: 206 | enc.encode(reflect.ValueOf(MakeVariant(v.Interface())), depth) 207 | default: 208 | panic(InvalidTypeError{v.Type()}) 209 | } 210 | } 211 | -------------------------------------------------------------------------------- /vendor/github.com/godbus/dbus/sig.go: -------------------------------------------------------------------------------- 1 | package dbus 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "strings" 7 | ) 8 | 9 | var sigToType = map[byte]reflect.Type{ 10 | 'y': byteType, 11 | 'b': boolType, 12 | 'n': int16Type, 13 | 'q': uint16Type, 14 | 'i': int32Type, 15 | 'u': uint32Type, 16 | 'x': int64Type, 17 | 't': uint64Type, 18 | 'd': float64Type, 19 | 's': stringType, 20 | 'g': signatureType, 21 | 'o': objectPathType, 22 | 'v': variantType, 23 | 'h': unixFDIndexType, 24 | } 25 | 26 | // Signature represents a correct type signature as specified by the D-Bus 27 | // specification. The zero value represents the empty signature, "". 28 | type Signature struct { 29 | str string 30 | } 31 | 32 | // SignatureOf returns the concatenation of all the signatures of the given 33 | // values. It panics if one of them is not representable in D-Bus. 34 | func SignatureOf(vs ...interface{}) Signature { 35 | var s string 36 | for _, v := range vs { 37 | s += getSignature(reflect.TypeOf(v)) 38 | } 39 | return Signature{s} 40 | } 41 | 42 | // SignatureOfType returns the signature of the given type. It panics if the 43 | // type is not representable in D-Bus. 44 | func SignatureOfType(t reflect.Type) Signature { 45 | return Signature{getSignature(t)} 46 | } 47 | 48 | // getSignature returns the signature of the given type and panics on unknown types. 49 | func getSignature(t reflect.Type) string { 50 | // handle simple types first 51 | switch t.Kind() { 52 | case reflect.Uint8: 53 | return "y" 54 | case reflect.Bool: 55 | return "b" 56 | case reflect.Int16: 57 | return "n" 58 | case reflect.Uint16: 59 | return "q" 60 | case reflect.Int, reflect.Int32: 61 | if t == unixFDType { 62 | return "h" 63 | } 64 | return "i" 65 | case reflect.Uint, reflect.Uint32: 66 | if t == unixFDIndexType { 67 | return "h" 68 | } 69 | return "u" 70 | case reflect.Int64: 71 | return "x" 72 | case reflect.Uint64: 73 | return "t" 74 | case reflect.Float64: 75 | return "d" 76 | case reflect.Ptr: 77 | return getSignature(t.Elem()) 78 | case reflect.String: 79 | if t == objectPathType { 80 | return "o" 81 | } 82 | return "s" 83 | case reflect.Struct: 84 | if t == variantType { 85 | return "v" 86 | } else if t == signatureType { 87 | return "g" 88 | } 89 | var s string 90 | for i := 0; i < t.NumField(); i++ { 91 | field := t.Field(i) 92 | if field.PkgPath == "" && field.Tag.Get("dbus") != "-" { 93 | s += getSignature(t.Field(i).Type) 94 | } 95 | } 96 | return "(" + s + ")" 97 | case reflect.Array, reflect.Slice: 98 | return "a" + getSignature(t.Elem()) 99 | case reflect.Map: 100 | if !isKeyType(t.Key()) { 101 | panic(InvalidTypeError{t}) 102 | } 103 | return "a{" + getSignature(t.Key()) + getSignature(t.Elem()) + "}" 104 | case reflect.Interface: 105 | return "v" 106 | } 107 | panic(InvalidTypeError{t}) 108 | } 109 | 110 | // ParseSignature returns the signature represented by this string, or a 111 | // SignatureError if the string is not a valid signature. 112 | func ParseSignature(s string) (sig Signature, err error) { 113 | if len(s) == 0 { 114 | return 115 | } 116 | if len(s) > 255 { 117 | return Signature{""}, SignatureError{s, "too long"} 118 | } 119 | sig.str = s 120 | for err == nil && len(s) != 0 { 121 | err, s = validSingle(s, 0) 122 | } 123 | if err != nil { 124 | sig = Signature{""} 125 | } 126 | 127 | return 128 | } 129 | 130 | // ParseSignatureMust behaves like ParseSignature, except that it panics if s 131 | // is not valid. 132 | func ParseSignatureMust(s string) Signature { 133 | sig, err := ParseSignature(s) 134 | if err != nil { 135 | panic(err) 136 | } 137 | return sig 138 | } 139 | 140 | // Empty retruns whether the signature is the empty signature. 141 | func (s Signature) Empty() bool { 142 | return s.str == "" 143 | } 144 | 145 | // Single returns whether the signature represents a single, complete type. 146 | func (s Signature) Single() bool { 147 | err, r := validSingle(s.str, 0) 148 | return err != nil && r == "" 149 | } 150 | 151 | // String returns the signature's string representation. 152 | func (s Signature) String() string { 153 | return s.str 154 | } 155 | 156 | // A SignatureError indicates that a signature passed to a function or received 157 | // on a connection is not a valid signature. 158 | type SignatureError struct { 159 | Sig string 160 | Reason string 161 | } 162 | 163 | func (e SignatureError) Error() string { 164 | return fmt.Sprintf("dbus: invalid signature: %q (%s)", e.Sig, e.Reason) 165 | } 166 | 167 | // Try to read a single type from this string. If it was successful, err is nil 168 | // and rem is the remaining unparsed part. Otherwise, err is a non-nil 169 | // SignatureError and rem is "". depth is the current recursion depth which may 170 | // not be greater than 64 and should be given as 0 on the first call. 171 | func validSingle(s string, depth int) (err error, rem string) { 172 | if s == "" { 173 | return SignatureError{Sig: s, Reason: "empty signature"}, "" 174 | } 175 | if depth > 64 { 176 | return SignatureError{Sig: s, Reason: "container nesting too deep"}, "" 177 | } 178 | switch s[0] { 179 | case 'y', 'b', 'n', 'q', 'i', 'u', 'x', 't', 'd', 's', 'g', 'o', 'v', 'h': 180 | return nil, s[1:] 181 | case 'a': 182 | if len(s) > 1 && s[1] == '{' { 183 | i := findMatching(s[1:], '{', '}') 184 | if i == -1 { 185 | return SignatureError{Sig: s, Reason: "unmatched '{'"}, "" 186 | } 187 | i++ 188 | rem = s[i+1:] 189 | s = s[2:i] 190 | if err, _ = validSingle(s[:1], depth+1); err != nil { 191 | return err, "" 192 | } 193 | err, nr := validSingle(s[1:], depth+1) 194 | if err != nil { 195 | return err, "" 196 | } 197 | if nr != "" { 198 | return SignatureError{Sig: s, Reason: "too many types in dict"}, "" 199 | } 200 | return nil, rem 201 | } 202 | return validSingle(s[1:], depth+1) 203 | case '(': 204 | i := findMatching(s, '(', ')') 205 | if i == -1 { 206 | return SignatureError{Sig: s, Reason: "unmatched ')'"}, "" 207 | } 208 | rem = s[i+1:] 209 | s = s[1:i] 210 | for err == nil && s != "" { 211 | err, s = validSingle(s, depth+1) 212 | } 213 | if err != nil { 214 | rem = "" 215 | } 216 | return 217 | } 218 | return SignatureError{Sig: s, Reason: "invalid type character"}, "" 219 | } 220 | 221 | func findMatching(s string, left, right rune) int { 222 | n := 0 223 | for i, v := range s { 224 | if v == left { 225 | n++ 226 | } else if v == right { 227 | n-- 228 | } 229 | if n == 0 { 230 | return i 231 | } 232 | } 233 | return -1 234 | } 235 | 236 | // typeFor returns the type of the given signature. It ignores any left over 237 | // characters and panics if s doesn't start with a valid type signature. 238 | func typeFor(s string) (t reflect.Type) { 239 | err, _ := validSingle(s, 0) 240 | if err != nil { 241 | panic(err) 242 | } 243 | 244 | if t, ok := sigToType[s[0]]; ok { 245 | return t 246 | } 247 | switch s[0] { 248 | case 'a': 249 | if s[1] == '{' { 250 | i := strings.LastIndex(s, "}") 251 | t = reflect.MapOf(sigToType[s[2]], typeFor(s[3:i])) 252 | } else { 253 | t = reflect.SliceOf(typeFor(s[1:])) 254 | } 255 | case '(': 256 | t = interfacesType 257 | } 258 | return 259 | } 260 | -------------------------------------------------------------------------------- /vendor/github.com/BurntSushi/toml/type_fields.go: -------------------------------------------------------------------------------- 1 | package toml 2 | 3 | // Struct field handling is adapted from code in encoding/json: 4 | // 5 | // Copyright 2010 The Go Authors. All rights reserved. 6 | // Use of this source code is governed by a BSD-style 7 | // license that can be found in the Go distribution. 8 | 9 | import ( 10 | "reflect" 11 | "sort" 12 | "sync" 13 | ) 14 | 15 | // A field represents a single field found in a struct. 16 | type field struct { 17 | name string // the name of the field (`toml` tag included) 18 | tag bool // whether field has a `toml` tag 19 | index []int // represents the depth of an anonymous field 20 | typ reflect.Type // the type of the field 21 | } 22 | 23 | // byName sorts field by name, breaking ties with depth, 24 | // then breaking ties with "name came from toml tag", then 25 | // breaking ties with index sequence. 26 | type byName []field 27 | 28 | func (x byName) Len() int { return len(x) } 29 | 30 | func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 31 | 32 | func (x byName) Less(i, j int) bool { 33 | if x[i].name != x[j].name { 34 | return x[i].name < x[j].name 35 | } 36 | if len(x[i].index) != len(x[j].index) { 37 | return len(x[i].index) < len(x[j].index) 38 | } 39 | if x[i].tag != x[j].tag { 40 | return x[i].tag 41 | } 42 | return byIndex(x).Less(i, j) 43 | } 44 | 45 | // byIndex sorts field by index sequence. 46 | type byIndex []field 47 | 48 | func (x byIndex) Len() int { return len(x) } 49 | 50 | func (x byIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 51 | 52 | func (x byIndex) Less(i, j int) bool { 53 | for k, xik := range x[i].index { 54 | if k >= len(x[j].index) { 55 | return false 56 | } 57 | if xik != x[j].index[k] { 58 | return xik < x[j].index[k] 59 | } 60 | } 61 | return len(x[i].index) < len(x[j].index) 62 | } 63 | 64 | // typeFields returns a list of fields that TOML should recognize for the given 65 | // type. The algorithm is breadth-first search over the set of structs to 66 | // include - the top struct and then any reachable anonymous structs. 67 | func typeFields(t reflect.Type) []field { 68 | // Anonymous fields to explore at the current level and the next. 69 | current := []field{} 70 | next := []field{{typ: t}} 71 | 72 | // Count of queued names for current level and the next. 73 | count := map[reflect.Type]int{} 74 | nextCount := map[reflect.Type]int{} 75 | 76 | // Types already visited at an earlier level. 77 | visited := map[reflect.Type]bool{} 78 | 79 | // Fields found. 80 | var fields []field 81 | 82 | for len(next) > 0 { 83 | current, next = next, current[:0] 84 | count, nextCount = nextCount, map[reflect.Type]int{} 85 | 86 | for _, f := range current { 87 | if visited[f.typ] { 88 | continue 89 | } 90 | visited[f.typ] = true 91 | 92 | // Scan f.typ for fields to include. 93 | for i := 0; i < f.typ.NumField(); i++ { 94 | sf := f.typ.Field(i) 95 | if sf.PkgPath != "" && !sf.Anonymous { // unexported 96 | continue 97 | } 98 | opts := getOptions(sf.Tag) 99 | if opts.skip { 100 | continue 101 | } 102 | index := make([]int, len(f.index)+1) 103 | copy(index, f.index) 104 | index[len(f.index)] = i 105 | 106 | ft := sf.Type 107 | if ft.Name() == "" && ft.Kind() == reflect.Ptr { 108 | // Follow pointer. 109 | ft = ft.Elem() 110 | } 111 | 112 | // Record found field and index sequence. 113 | if opts.name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct { 114 | tagged := opts.name != "" 115 | name := opts.name 116 | if name == "" { 117 | name = sf.Name 118 | } 119 | fields = append(fields, field{name, tagged, index, ft}) 120 | if count[f.typ] > 1 { 121 | // If there were multiple instances, add a second, 122 | // so that the annihilation code will see a duplicate. 123 | // It only cares about the distinction between 1 or 2, 124 | // so don't bother generating any more copies. 125 | fields = append(fields, fields[len(fields)-1]) 126 | } 127 | continue 128 | } 129 | 130 | // Record new anonymous struct to explore in next round. 131 | nextCount[ft]++ 132 | if nextCount[ft] == 1 { 133 | f := field{name: ft.Name(), index: index, typ: ft} 134 | next = append(next, f) 135 | } 136 | } 137 | } 138 | } 139 | 140 | sort.Sort(byName(fields)) 141 | 142 | // Delete all fields that are hidden by the Go rules for embedded fields, 143 | // except that fields with TOML tags are promoted. 144 | 145 | // The fields are sorted in primary order of name, secondary order 146 | // of field index length. Loop over names; for each name, delete 147 | // hidden fields by choosing the one dominant field that survives. 148 | out := fields[:0] 149 | for advance, i := 0, 0; i < len(fields); i += advance { 150 | // One iteration per name. 151 | // Find the sequence of fields with the name of this first field. 152 | fi := fields[i] 153 | name := fi.name 154 | for advance = 1; i+advance < len(fields); advance++ { 155 | fj := fields[i+advance] 156 | if fj.name != name { 157 | break 158 | } 159 | } 160 | if advance == 1 { // Only one field with this name 161 | out = append(out, fi) 162 | continue 163 | } 164 | dominant, ok := dominantField(fields[i : i+advance]) 165 | if ok { 166 | out = append(out, dominant) 167 | } 168 | } 169 | 170 | fields = out 171 | sort.Sort(byIndex(fields)) 172 | 173 | return fields 174 | } 175 | 176 | // dominantField looks through the fields, all of which are known to 177 | // have the same name, to find the single field that dominates the 178 | // others using Go's embedding rules, modified by the presence of 179 | // TOML tags. If there are multiple top-level fields, the boolean 180 | // will be false: This condition is an error in Go and we skip all 181 | // the fields. 182 | func dominantField(fields []field) (field, bool) { 183 | // The fields are sorted in increasing index-length order. The winner 184 | // must therefore be one with the shortest index length. Drop all 185 | // longer entries, which is easy: just truncate the slice. 186 | length := len(fields[0].index) 187 | tagged := -1 // Index of first tagged field. 188 | for i, f := range fields { 189 | if len(f.index) > length { 190 | fields = fields[:i] 191 | break 192 | } 193 | if f.tag { 194 | if tagged >= 0 { 195 | // Multiple tagged fields at the same level: conflict. 196 | // Return no field. 197 | return field{}, false 198 | } 199 | tagged = i 200 | } 201 | } 202 | if tagged >= 0 { 203 | return fields[tagged], true 204 | } 205 | // All remaining fields have the same length. If there's more than one, 206 | // we have a conflict (two fields named "X" at the same level) and we 207 | // return no field. 208 | if len(fields) > 1 { 209 | return field{}, false 210 | } 211 | return fields[0], true 212 | } 213 | 214 | var fieldCache struct { 215 | sync.RWMutex 216 | m map[reflect.Type][]field 217 | } 218 | 219 | // cachedTypeFields is like typeFields but uses a cache to avoid repeated work. 220 | func cachedTypeFields(t reflect.Type) []field { 221 | fieldCache.RLock() 222 | f := fieldCache.m[t] 223 | fieldCache.RUnlock() 224 | if f != nil { 225 | return f 226 | } 227 | 228 | // Compute fields without lock. 229 | // Might duplicate effort but won't hold other computations back. 230 | f = typeFields(t) 231 | if f == nil { 232 | f = []field{} 233 | } 234 | 235 | fieldCache.Lock() 236 | if fieldCache.m == nil { 237 | fieldCache.m = map[reflect.Type][]field{} 238 | } 239 | fieldCache.m[t] = f 240 | fieldCache.Unlock() 241 | return f 242 | } 243 | -------------------------------------------------------------------------------- /vendor/github.com/godbus/dbus/default_handler.go: -------------------------------------------------------------------------------- 1 | package dbus 2 | 3 | import ( 4 | "bytes" 5 | "reflect" 6 | "strings" 7 | "sync" 8 | ) 9 | 10 | func newIntrospectIntf(h *defaultHandler) *exportedIntf { 11 | methods := make(map[string]Method) 12 | methods["Introspect"] = exportedMethod{ 13 | reflect.ValueOf(func(msg Message) (string, *Error) { 14 | path := msg.Headers[FieldPath].value.(ObjectPath) 15 | return h.introspectPath(path), nil 16 | }), 17 | } 18 | return newExportedIntf(methods, true) 19 | } 20 | 21 | //NewDefaultHandler returns an instance of the default 22 | //call handler. This is useful if you want to implement only 23 | //one of the two handlers but not both. 24 | func NewDefaultHandler() *defaultHandler { 25 | h := &defaultHandler{ 26 | objects: make(map[ObjectPath]*exportedObj), 27 | defaultIntf: make(map[string]*exportedIntf), 28 | } 29 | h.defaultIntf["org.freedesktop.DBus.Introspectable"] = newIntrospectIntf(h) 30 | return h 31 | } 32 | 33 | type defaultHandler struct { 34 | sync.RWMutex 35 | objects map[ObjectPath]*exportedObj 36 | defaultIntf map[string]*exportedIntf 37 | } 38 | 39 | func (h *defaultHandler) PathExists(path ObjectPath) bool { 40 | _, ok := h.objects[path] 41 | return ok 42 | } 43 | 44 | func (h *defaultHandler) introspectPath(path ObjectPath) string { 45 | subpath := make(map[string]struct{}) 46 | var xml bytes.Buffer 47 | xml.WriteString("") 48 | for obj, _ := range h.objects { 49 | p := string(path) 50 | if p != "/" { 51 | p += "/" 52 | } 53 | if strings.HasPrefix(string(obj), p) { 54 | node_name := strings.Split(string(obj[len(p):]), "/")[0] 55 | subpath[node_name] = struct{}{} 56 | } 57 | } 58 | for s, _ := range subpath { 59 | xml.WriteString("\n\t") 60 | } 61 | xml.WriteString("\n") 62 | return xml.String() 63 | } 64 | 65 | func (h *defaultHandler) LookupObject(path ObjectPath) (ServerObject, bool) { 66 | h.RLock() 67 | defer h.RUnlock() 68 | object, ok := h.objects[path] 69 | if ok { 70 | return object, ok 71 | } 72 | 73 | // If an object wasn't found for this exact path, 74 | // look for a matching subtree registration 75 | subtreeObject := newExportedObject() 76 | path = path[:strings.LastIndex(string(path), "/")] 77 | for len(path) > 0 { 78 | object, ok = h.objects[path] 79 | if ok { 80 | for name, iface := range object.interfaces { 81 | // Only include this handler if it registered for the subtree 82 | if iface.isFallbackInterface() { 83 | subtreeObject.interfaces[name] = iface 84 | } 85 | } 86 | break 87 | } 88 | 89 | path = path[:strings.LastIndex(string(path), "/")] 90 | } 91 | 92 | for name, intf := range h.defaultIntf { 93 | if _, exists := subtreeObject.interfaces[name]; exists { 94 | continue 95 | } 96 | subtreeObject.interfaces[name] = intf 97 | } 98 | 99 | return subtreeObject, true 100 | } 101 | 102 | func (h *defaultHandler) AddObject(path ObjectPath, object *exportedObj) { 103 | h.Lock() 104 | h.objects[path] = object 105 | h.Unlock() 106 | } 107 | 108 | func (h *defaultHandler) DeleteObject(path ObjectPath) { 109 | h.Lock() 110 | delete(h.objects, path) 111 | h.Unlock() 112 | } 113 | 114 | type exportedMethod struct { 115 | reflect.Value 116 | } 117 | 118 | func (m exportedMethod) Call(args ...interface{}) ([]interface{}, error) { 119 | t := m.Type() 120 | 121 | params := make([]reflect.Value, len(args)) 122 | for i := 0; i < len(args); i++ { 123 | params[i] = reflect.ValueOf(args[i]).Elem() 124 | } 125 | 126 | ret := m.Value.Call(params) 127 | 128 | err := ret[t.NumOut()-1].Interface().(*Error) 129 | ret = ret[:t.NumOut()-1] 130 | out := make([]interface{}, len(ret)) 131 | for i, val := range ret { 132 | out[i] = val.Interface() 133 | } 134 | if err == nil { 135 | //concrete type to interface nil is a special case 136 | return out, nil 137 | } 138 | return out, err 139 | } 140 | 141 | func (m exportedMethod) NumArguments() int { 142 | return m.Value.Type().NumIn() 143 | } 144 | 145 | func (m exportedMethod) ArgumentValue(i int) interface{} { 146 | return reflect.Zero(m.Type().In(i)).Interface() 147 | } 148 | 149 | func (m exportedMethod) NumReturns() int { 150 | return m.Value.Type().NumOut() 151 | } 152 | 153 | func (m exportedMethod) ReturnValue(i int) interface{} { 154 | return reflect.Zero(m.Type().Out(i)).Interface() 155 | } 156 | 157 | func newExportedObject() *exportedObj { 158 | return &exportedObj{ 159 | interfaces: make(map[string]*exportedIntf), 160 | } 161 | } 162 | 163 | type exportedObj struct { 164 | interfaces map[string]*exportedIntf 165 | } 166 | 167 | func (obj *exportedObj) LookupInterface(name string) (Interface, bool) { 168 | if name == "" { 169 | return obj, true 170 | } 171 | intf, exists := obj.interfaces[name] 172 | return intf, exists 173 | } 174 | 175 | func (obj *exportedObj) AddInterface(name string, iface *exportedIntf) { 176 | obj.interfaces[name] = iface 177 | } 178 | 179 | func (obj *exportedObj) DeleteInterface(name string) { 180 | delete(obj.interfaces, name) 181 | } 182 | 183 | func (obj *exportedObj) LookupMethod(name string) (Method, bool) { 184 | for _, intf := range obj.interfaces { 185 | method, exists := intf.LookupMethod(name) 186 | if exists { 187 | return method, exists 188 | } 189 | } 190 | return nil, false 191 | } 192 | 193 | func (obj *exportedObj) isFallbackInterface() bool { 194 | return false 195 | } 196 | 197 | func newExportedIntf(methods map[string]Method, includeSubtree bool) *exportedIntf { 198 | return &exportedIntf{ 199 | methods: methods, 200 | includeSubtree: includeSubtree, 201 | } 202 | } 203 | 204 | type exportedIntf struct { 205 | methods map[string]Method 206 | 207 | // Whether or not this export is for the entire subtree 208 | includeSubtree bool 209 | } 210 | 211 | func (obj *exportedIntf) LookupMethod(name string) (Method, bool) { 212 | out, exists := obj.methods[name] 213 | return out, exists 214 | } 215 | 216 | func (obj *exportedIntf) isFallbackInterface() bool { 217 | return obj.includeSubtree 218 | } 219 | 220 | //NewDefaultSignalHandler returns an instance of the default 221 | //signal handler. This is useful if you want to implement only 222 | //one of the two handlers but not both. 223 | func NewDefaultSignalHandler() *defaultSignalHandler { 224 | return &defaultSignalHandler{} 225 | } 226 | 227 | func isDefaultSignalHandler(handler SignalHandler) bool { 228 | _, ok := handler.(*defaultSignalHandler) 229 | return ok 230 | } 231 | 232 | type defaultSignalHandler struct { 233 | sync.RWMutex 234 | closed bool 235 | signals []chan<- *Signal 236 | } 237 | 238 | func (sh *defaultSignalHandler) DeliverSignal(intf, name string, signal *Signal) { 239 | go func() { 240 | sh.RLock() 241 | defer sh.RUnlock() 242 | if sh.closed { 243 | return 244 | } 245 | for _, ch := range sh.signals { 246 | ch <- signal 247 | } 248 | }() 249 | } 250 | 251 | func (sh *defaultSignalHandler) Init() error { 252 | sh.Lock() 253 | sh.signals = make([]chan<- *Signal, 0) 254 | sh.Unlock() 255 | return nil 256 | } 257 | 258 | func (sh *defaultSignalHandler) Terminate() { 259 | sh.Lock() 260 | sh.closed = true 261 | for _, ch := range sh.signals { 262 | close(ch) 263 | } 264 | sh.signals = nil 265 | sh.Unlock() 266 | } 267 | 268 | func (sh *defaultSignalHandler) addSignal(ch chan<- *Signal) { 269 | sh.Lock() 270 | defer sh.Unlock() 271 | if sh.closed { 272 | return 273 | } 274 | sh.signals = append(sh.signals, ch) 275 | 276 | } 277 | 278 | func (sh *defaultSignalHandler) removeSignal(ch chan<- *Signal) { 279 | sh.Lock() 280 | defer sh.Unlock() 281 | if sh.closed { 282 | return 283 | } 284 | for i := len(sh.signals) - 1; i >= 0; i-- { 285 | if ch == sh.signals[i] { 286 | copy(sh.signals[i:], sh.signals[i+1:]) 287 | sh.signals[len(sh.signals)-1] = nil 288 | sh.signals = sh.signals[:len(sh.signals)-1] 289 | } 290 | } 291 | } 292 | -------------------------------------------------------------------------------- /vendor/github.com/godbus/dbus/auth.go: -------------------------------------------------------------------------------- 1 | package dbus 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "errors" 7 | "io" 8 | "os" 9 | "strconv" 10 | ) 11 | 12 | // AuthStatus represents the Status of an authentication mechanism. 13 | type AuthStatus byte 14 | 15 | const ( 16 | // AuthOk signals that authentication is finished; the next command 17 | // from the server should be an OK. 18 | AuthOk AuthStatus = iota 19 | 20 | // AuthContinue signals that additional data is needed; the next command 21 | // from the server should be a DATA. 22 | AuthContinue 23 | 24 | // AuthError signals an error; the server sent invalid data or some 25 | // other unexpected thing happened and the current authentication 26 | // process should be aborted. 27 | AuthError 28 | ) 29 | 30 | type authState byte 31 | 32 | const ( 33 | waitingForData authState = iota 34 | waitingForOk 35 | waitingForReject 36 | ) 37 | 38 | // Auth defines the behaviour of an authentication mechanism. 39 | type Auth interface { 40 | // Return the name of the mechnism, the argument to the first AUTH command 41 | // and the next status. 42 | FirstData() (name, resp []byte, status AuthStatus) 43 | 44 | // Process the given DATA command, and return the argument to the DATA 45 | // command and the next status. If len(resp) == 0, no DATA command is sent. 46 | HandleData(data []byte) (resp []byte, status AuthStatus) 47 | } 48 | 49 | // Auth authenticates the connection, trying the given list of authentication 50 | // mechanisms (in that order). If nil is passed, the EXTERNAL and 51 | // DBUS_COOKIE_SHA1 mechanisms are tried for the current user. For private 52 | // connections, this method must be called before sending any messages to the 53 | // bus. Auth must not be called on shared connections. 54 | func (conn *Conn) Auth(methods []Auth) error { 55 | if methods == nil { 56 | uid := strconv.Itoa(os.Getuid()) 57 | methods = []Auth{AuthExternal(uid), AuthCookieSha1(uid, getHomeDir())} 58 | } 59 | in := bufio.NewReader(conn.transport) 60 | err := conn.transport.SendNullByte() 61 | if err != nil { 62 | return err 63 | } 64 | err = authWriteLine(conn.transport, []byte("AUTH")) 65 | if err != nil { 66 | return err 67 | } 68 | s, err := authReadLine(in) 69 | if err != nil { 70 | return err 71 | } 72 | if len(s) < 2 || !bytes.Equal(s[0], []byte("REJECTED")) { 73 | return errors.New("dbus: authentication protocol error") 74 | } 75 | s = s[1:] 76 | for _, v := range s { 77 | for _, m := range methods { 78 | if name, data, status := m.FirstData(); bytes.Equal(v, name) { 79 | var ok bool 80 | err = authWriteLine(conn.transport, []byte("AUTH"), []byte(v), data) 81 | if err != nil { 82 | return err 83 | } 84 | switch status { 85 | case AuthOk: 86 | err, ok = conn.tryAuth(m, waitingForOk, in) 87 | case AuthContinue: 88 | err, ok = conn.tryAuth(m, waitingForData, in) 89 | default: 90 | panic("dbus: invalid authentication status") 91 | } 92 | if err != nil { 93 | return err 94 | } 95 | if ok { 96 | if conn.transport.SupportsUnixFDs() { 97 | err = authWriteLine(conn, []byte("NEGOTIATE_UNIX_FD")) 98 | if err != nil { 99 | return err 100 | } 101 | line, err := authReadLine(in) 102 | if err != nil { 103 | return err 104 | } 105 | switch { 106 | case bytes.Equal(line[0], []byte("AGREE_UNIX_FD")): 107 | conn.EnableUnixFDs() 108 | conn.unixFD = true 109 | case bytes.Equal(line[0], []byte("ERROR")): 110 | default: 111 | return errors.New("dbus: authentication protocol error") 112 | } 113 | } 114 | err = authWriteLine(conn.transport, []byte("BEGIN")) 115 | if err != nil { 116 | return err 117 | } 118 | go conn.inWorker() 119 | go conn.outWorker() 120 | return nil 121 | } 122 | } 123 | } 124 | } 125 | return errors.New("dbus: authentication failed") 126 | } 127 | 128 | // tryAuth tries to authenticate with m as the mechanism, using state as the 129 | // initial authState and in for reading input. It returns (nil, true) on 130 | // success, (nil, false) on a REJECTED and (someErr, false) if some other 131 | // error occured. 132 | func (conn *Conn) tryAuth(m Auth, state authState, in *bufio.Reader) (error, bool) { 133 | for { 134 | s, err := authReadLine(in) 135 | if err != nil { 136 | return err, false 137 | } 138 | switch { 139 | case state == waitingForData && string(s[0]) == "DATA": 140 | if len(s) != 2 { 141 | err = authWriteLine(conn.transport, []byte("ERROR")) 142 | if err != nil { 143 | return err, false 144 | } 145 | continue 146 | } 147 | data, status := m.HandleData(s[1]) 148 | switch status { 149 | case AuthOk, AuthContinue: 150 | if len(data) != 0 { 151 | err = authWriteLine(conn.transport, []byte("DATA"), data) 152 | if err != nil { 153 | return err, false 154 | } 155 | } 156 | if status == AuthOk { 157 | state = waitingForOk 158 | } 159 | case AuthError: 160 | err = authWriteLine(conn.transport, []byte("ERROR")) 161 | if err != nil { 162 | return err, false 163 | } 164 | } 165 | case state == waitingForData && string(s[0]) == "REJECTED": 166 | return nil, false 167 | case state == waitingForData && string(s[0]) == "ERROR": 168 | err = authWriteLine(conn.transport, []byte("CANCEL")) 169 | if err != nil { 170 | return err, false 171 | } 172 | state = waitingForReject 173 | case state == waitingForData && string(s[0]) == "OK": 174 | if len(s) != 2 { 175 | err = authWriteLine(conn.transport, []byte("CANCEL")) 176 | if err != nil { 177 | return err, false 178 | } 179 | state = waitingForReject 180 | } 181 | conn.uuid = string(s[1]) 182 | return nil, true 183 | case state == waitingForData: 184 | err = authWriteLine(conn.transport, []byte("ERROR")) 185 | if err != nil { 186 | return err, false 187 | } 188 | case state == waitingForOk && string(s[0]) == "OK": 189 | if len(s) != 2 { 190 | err = authWriteLine(conn.transport, []byte("CANCEL")) 191 | if err != nil { 192 | return err, false 193 | } 194 | state = waitingForReject 195 | } 196 | conn.uuid = string(s[1]) 197 | return nil, true 198 | case state == waitingForOk && string(s[0]) == "REJECTED": 199 | return nil, false 200 | case state == waitingForOk && (string(s[0]) == "DATA" || 201 | string(s[0]) == "ERROR"): 202 | 203 | err = authWriteLine(conn.transport, []byte("CANCEL")) 204 | if err != nil { 205 | return err, false 206 | } 207 | state = waitingForReject 208 | case state == waitingForOk: 209 | err = authWriteLine(conn.transport, []byte("ERROR")) 210 | if err != nil { 211 | return err, false 212 | } 213 | case state == waitingForReject && string(s[0]) == "REJECTED": 214 | return nil, false 215 | case state == waitingForReject: 216 | return errors.New("dbus: authentication protocol error"), false 217 | default: 218 | panic("dbus: invalid auth state") 219 | } 220 | } 221 | } 222 | 223 | // authReadLine reads a line and separates it into its fields. 224 | func authReadLine(in *bufio.Reader) ([][]byte, error) { 225 | data, err := in.ReadBytes('\n') 226 | if err != nil { 227 | return nil, err 228 | } 229 | data = bytes.TrimSuffix(data, []byte("\r\n")) 230 | return bytes.Split(data, []byte{' '}), nil 231 | } 232 | 233 | // authWriteLine writes the given line in the authentication protocol format 234 | // (elements of data separated by a " " and terminated by "\r\n"). 235 | func authWriteLine(out io.Writer, data ...[]byte) error { 236 | buf := make([]byte, 0) 237 | for i, v := range data { 238 | buf = append(buf, v...) 239 | if i != len(data)-1 { 240 | buf = append(buf, ' ') 241 | } 242 | } 243 | buf = append(buf, '\r') 244 | buf = append(buf, '\n') 245 | n, err := out.Write(buf) 246 | if err != nil { 247 | return err 248 | } 249 | if n != len(buf) { 250 | return io.ErrUnexpectedEOF 251 | } 252 | return nil 253 | } 254 | -------------------------------------------------------------------------------- /vendor/golang.org/x/net/context/pre_go17.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. 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 | // +build !go1.7 6 | 7 | package context 8 | 9 | import ( 10 | "errors" 11 | "fmt" 12 | "sync" 13 | "time" 14 | ) 15 | 16 | // An emptyCtx is never canceled, has no values, and has no deadline. It is not 17 | // struct{}, since vars of this type must have distinct addresses. 18 | type emptyCtx int 19 | 20 | func (*emptyCtx) Deadline() (deadline time.Time, ok bool) { 21 | return 22 | } 23 | 24 | func (*emptyCtx) Done() <-chan struct{} { 25 | return nil 26 | } 27 | 28 | func (*emptyCtx) Err() error { 29 | return nil 30 | } 31 | 32 | func (*emptyCtx) Value(key interface{}) interface{} { 33 | return nil 34 | } 35 | 36 | func (e *emptyCtx) String() string { 37 | switch e { 38 | case background: 39 | return "context.Background" 40 | case todo: 41 | return "context.TODO" 42 | } 43 | return "unknown empty Context" 44 | } 45 | 46 | var ( 47 | background = new(emptyCtx) 48 | todo = new(emptyCtx) 49 | ) 50 | 51 | // Canceled is the error returned by Context.Err when the context is canceled. 52 | var Canceled = errors.New("context canceled") 53 | 54 | // DeadlineExceeded is the error returned by Context.Err when the context's 55 | // deadline passes. 56 | var DeadlineExceeded = errors.New("context deadline exceeded") 57 | 58 | // WithCancel returns a copy of parent with a new Done channel. The returned 59 | // context's Done channel is closed when the returned cancel function is called 60 | // or when the parent context's Done channel is closed, whichever happens first. 61 | // 62 | // Canceling this context releases resources associated with it, so code should 63 | // call cancel as soon as the operations running in this Context complete. 64 | func WithCancel(parent Context) (ctx Context, cancel CancelFunc) { 65 | c := newCancelCtx(parent) 66 | propagateCancel(parent, c) 67 | return c, func() { c.cancel(true, Canceled) } 68 | } 69 | 70 | // newCancelCtx returns an initialized cancelCtx. 71 | func newCancelCtx(parent Context) *cancelCtx { 72 | return &cancelCtx{ 73 | Context: parent, 74 | done: make(chan struct{}), 75 | } 76 | } 77 | 78 | // propagateCancel arranges for child to be canceled when parent is. 79 | func propagateCancel(parent Context, child canceler) { 80 | if parent.Done() == nil { 81 | return // parent is never canceled 82 | } 83 | if p, ok := parentCancelCtx(parent); ok { 84 | p.mu.Lock() 85 | if p.err != nil { 86 | // parent has already been canceled 87 | child.cancel(false, p.err) 88 | } else { 89 | if p.children == nil { 90 | p.children = make(map[canceler]bool) 91 | } 92 | p.children[child] = true 93 | } 94 | p.mu.Unlock() 95 | } else { 96 | go func() { 97 | select { 98 | case <-parent.Done(): 99 | child.cancel(false, parent.Err()) 100 | case <-child.Done(): 101 | } 102 | }() 103 | } 104 | } 105 | 106 | // parentCancelCtx follows a chain of parent references until it finds a 107 | // *cancelCtx. This function understands how each of the concrete types in this 108 | // package represents its parent. 109 | func parentCancelCtx(parent Context) (*cancelCtx, bool) { 110 | for { 111 | switch c := parent.(type) { 112 | case *cancelCtx: 113 | return c, true 114 | case *timerCtx: 115 | return c.cancelCtx, true 116 | case *valueCtx: 117 | parent = c.Context 118 | default: 119 | return nil, false 120 | } 121 | } 122 | } 123 | 124 | // removeChild removes a context from its parent. 125 | func removeChild(parent Context, child canceler) { 126 | p, ok := parentCancelCtx(parent) 127 | if !ok { 128 | return 129 | } 130 | p.mu.Lock() 131 | if p.children != nil { 132 | delete(p.children, child) 133 | } 134 | p.mu.Unlock() 135 | } 136 | 137 | // A canceler is a context type that can be canceled directly. The 138 | // implementations are *cancelCtx and *timerCtx. 139 | type canceler interface { 140 | cancel(removeFromParent bool, err error) 141 | Done() <-chan struct{} 142 | } 143 | 144 | // A cancelCtx can be canceled. When canceled, it also cancels any children 145 | // that implement canceler. 146 | type cancelCtx struct { 147 | Context 148 | 149 | done chan struct{} // closed by the first cancel call. 150 | 151 | mu sync.Mutex 152 | children map[canceler]bool // set to nil by the first cancel call 153 | err error // set to non-nil by the first cancel call 154 | } 155 | 156 | func (c *cancelCtx) Done() <-chan struct{} { 157 | return c.done 158 | } 159 | 160 | func (c *cancelCtx) Err() error { 161 | c.mu.Lock() 162 | defer c.mu.Unlock() 163 | return c.err 164 | } 165 | 166 | func (c *cancelCtx) String() string { 167 | return fmt.Sprintf("%v.WithCancel", c.Context) 168 | } 169 | 170 | // cancel closes c.done, cancels each of c's children, and, if 171 | // removeFromParent is true, removes c from its parent's children. 172 | func (c *cancelCtx) cancel(removeFromParent bool, err error) { 173 | if err == nil { 174 | panic("context: internal error: missing cancel error") 175 | } 176 | c.mu.Lock() 177 | if c.err != nil { 178 | c.mu.Unlock() 179 | return // already canceled 180 | } 181 | c.err = err 182 | close(c.done) 183 | for child := range c.children { 184 | // NOTE: acquiring the child's lock while holding parent's lock. 185 | child.cancel(false, err) 186 | } 187 | c.children = nil 188 | c.mu.Unlock() 189 | 190 | if removeFromParent { 191 | removeChild(c.Context, c) 192 | } 193 | } 194 | 195 | // WithDeadline returns a copy of the parent context with the deadline adjusted 196 | // to be no later than d. If the parent's deadline is already earlier than d, 197 | // WithDeadline(parent, d) is semantically equivalent to parent. The returned 198 | // context's Done channel is closed when the deadline expires, when the returned 199 | // cancel function is called, or when the parent context's Done channel is 200 | // closed, whichever happens first. 201 | // 202 | // Canceling this context releases resources associated with it, so code should 203 | // call cancel as soon as the operations running in this Context complete. 204 | func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) { 205 | if cur, ok := parent.Deadline(); ok && cur.Before(deadline) { 206 | // The current deadline is already sooner than the new one. 207 | return WithCancel(parent) 208 | } 209 | c := &timerCtx{ 210 | cancelCtx: newCancelCtx(parent), 211 | deadline: deadline, 212 | } 213 | propagateCancel(parent, c) 214 | d := deadline.Sub(time.Now()) 215 | if d <= 0 { 216 | c.cancel(true, DeadlineExceeded) // deadline has already passed 217 | return c, func() { c.cancel(true, Canceled) } 218 | } 219 | c.mu.Lock() 220 | defer c.mu.Unlock() 221 | if c.err == nil { 222 | c.timer = time.AfterFunc(d, func() { 223 | c.cancel(true, DeadlineExceeded) 224 | }) 225 | } 226 | return c, func() { c.cancel(true, Canceled) } 227 | } 228 | 229 | // A timerCtx carries a timer and a deadline. It embeds a cancelCtx to 230 | // implement Done and Err. It implements cancel by stopping its timer then 231 | // delegating to cancelCtx.cancel. 232 | type timerCtx struct { 233 | *cancelCtx 234 | timer *time.Timer // Under cancelCtx.mu. 235 | 236 | deadline time.Time 237 | } 238 | 239 | func (c *timerCtx) Deadline() (deadline time.Time, ok bool) { 240 | return c.deadline, true 241 | } 242 | 243 | func (c *timerCtx) String() string { 244 | return fmt.Sprintf("%v.WithDeadline(%s [%s])", c.cancelCtx.Context, c.deadline, c.deadline.Sub(time.Now())) 245 | } 246 | 247 | func (c *timerCtx) cancel(removeFromParent bool, err error) { 248 | c.cancelCtx.cancel(false, err) 249 | if removeFromParent { 250 | // Remove this timerCtx from its parent cancelCtx's children. 251 | removeChild(c.cancelCtx.Context, c) 252 | } 253 | c.mu.Lock() 254 | if c.timer != nil { 255 | c.timer.Stop() 256 | c.timer = nil 257 | } 258 | c.mu.Unlock() 259 | } 260 | 261 | // WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)). 262 | // 263 | // Canceling this context releases resources associated with it, so code should 264 | // call cancel as soon as the operations running in this Context complete: 265 | // 266 | // func slowOperationWithTimeout(ctx context.Context) (Result, error) { 267 | // ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond) 268 | // defer cancel() // releases resources if slowOperation completes before timeout elapses 269 | // return slowOperation(ctx) 270 | // } 271 | func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) { 272 | return WithDeadline(parent, time.Now().Add(timeout)) 273 | } 274 | 275 | // WithValue returns a copy of parent in which the value associated with key is 276 | // val. 277 | // 278 | // Use context Values only for request-scoped data that transits processes and 279 | // APIs, not for passing optional parameters to functions. 280 | func WithValue(parent Context, key interface{}, val interface{}) Context { 281 | return &valueCtx{parent, key, val} 282 | } 283 | 284 | // A valueCtx carries a key-value pair. It implements Value for that key and 285 | // delegates all other calls to the embedded Context. 286 | type valueCtx struct { 287 | Context 288 | key, val interface{} 289 | } 290 | 291 | func (c *valueCtx) String() string { 292 | return fmt.Sprintf("%v.WithValue(%#v, %#v)", c.Context, c.key, c.val) 293 | } 294 | 295 | func (c *valueCtx) Value(key interface{}) interface{} { 296 | if c.key == key { 297 | return c.val 298 | } 299 | return c.Context.Value(key) 300 | } 301 | -------------------------------------------------------------------------------- /vendor/github.com/godbus/dbus/message.go: -------------------------------------------------------------------------------- 1 | package dbus 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "errors" 7 | "io" 8 | "reflect" 9 | "strconv" 10 | ) 11 | 12 | const protoVersion byte = 1 13 | 14 | // Flags represents the possible flags of a D-Bus message. 15 | type Flags byte 16 | 17 | const ( 18 | // FlagNoReplyExpected signals that the message is not expected to generate 19 | // a reply. If this flag is set on outgoing messages, any possible reply 20 | // will be discarded. 21 | FlagNoReplyExpected Flags = 1 << iota 22 | // FlagNoAutoStart signals that the message bus should not automatically 23 | // start an application when handling this message. 24 | FlagNoAutoStart 25 | // FlagAllowInteractiveAuthorization may be set on a method call 26 | // message to inform the receiving side that the caller is prepared 27 | // to wait for interactive authorization, which might take a 28 | // considerable time to complete. For instance, if this flag is set, 29 | // it would be appropriate to query the user for passwords or 30 | // confirmation via Polkit or a similar framework. 31 | FlagAllowInteractiveAuthorization 32 | ) 33 | 34 | // Type represents the possible types of a D-Bus message. 35 | type Type byte 36 | 37 | const ( 38 | TypeMethodCall Type = 1 + iota 39 | TypeMethodReply 40 | TypeError 41 | TypeSignal 42 | typeMax 43 | ) 44 | 45 | func (t Type) String() string { 46 | switch t { 47 | case TypeMethodCall: 48 | return "method call" 49 | case TypeMethodReply: 50 | return "reply" 51 | case TypeError: 52 | return "error" 53 | case TypeSignal: 54 | return "signal" 55 | } 56 | return "invalid" 57 | } 58 | 59 | // HeaderField represents the possible byte codes for the headers 60 | // of a D-Bus message. 61 | type HeaderField byte 62 | 63 | const ( 64 | FieldPath HeaderField = 1 + iota 65 | FieldInterface 66 | FieldMember 67 | FieldErrorName 68 | FieldReplySerial 69 | FieldDestination 70 | FieldSender 71 | FieldSignature 72 | FieldUnixFDs 73 | fieldMax 74 | ) 75 | 76 | // An InvalidMessageError describes the reason why a D-Bus message is regarded as 77 | // invalid. 78 | type InvalidMessageError string 79 | 80 | func (e InvalidMessageError) Error() string { 81 | return "dbus: invalid message: " + string(e) 82 | } 83 | 84 | // fieldType are the types of the various header fields. 85 | var fieldTypes = [fieldMax]reflect.Type{ 86 | FieldPath: objectPathType, 87 | FieldInterface: stringType, 88 | FieldMember: stringType, 89 | FieldErrorName: stringType, 90 | FieldReplySerial: uint32Type, 91 | FieldDestination: stringType, 92 | FieldSender: stringType, 93 | FieldSignature: signatureType, 94 | FieldUnixFDs: uint32Type, 95 | } 96 | 97 | // requiredFields lists the header fields that are required by the different 98 | // message types. 99 | var requiredFields = [typeMax][]HeaderField{ 100 | TypeMethodCall: {FieldPath, FieldMember}, 101 | TypeMethodReply: {FieldReplySerial}, 102 | TypeError: {FieldErrorName, FieldReplySerial}, 103 | TypeSignal: {FieldPath, FieldInterface, FieldMember}, 104 | } 105 | 106 | // Message represents a single D-Bus message. 107 | type Message struct { 108 | Type 109 | Flags 110 | Headers map[HeaderField]Variant 111 | Body []interface{} 112 | 113 | serial uint32 114 | } 115 | 116 | type header struct { 117 | Field byte 118 | Variant 119 | } 120 | 121 | // DecodeMessage tries to decode a single message in the D-Bus wire format 122 | // from the given reader. The byte order is figured out from the first byte. 123 | // The possibly returned error can be an error of the underlying reader, an 124 | // InvalidMessageError or a FormatError. 125 | func DecodeMessage(rd io.Reader) (msg *Message, err error) { 126 | var order binary.ByteOrder 127 | var hlength, length uint32 128 | var typ, flags, proto byte 129 | var headers []header 130 | 131 | b := make([]byte, 1) 132 | _, err = rd.Read(b) 133 | if err != nil { 134 | return 135 | } 136 | switch b[0] { 137 | case 'l': 138 | order = binary.LittleEndian 139 | case 'B': 140 | order = binary.BigEndian 141 | default: 142 | return nil, InvalidMessageError("invalid byte order") 143 | } 144 | 145 | dec := newDecoder(rd, order) 146 | dec.pos = 1 147 | 148 | msg = new(Message) 149 | vs, err := dec.Decode(Signature{"yyyuu"}) 150 | if err != nil { 151 | return nil, err 152 | } 153 | if err = Store(vs, &typ, &flags, &proto, &length, &msg.serial); err != nil { 154 | return nil, err 155 | } 156 | msg.Type = Type(typ) 157 | msg.Flags = Flags(flags) 158 | 159 | // get the header length separately because we need it later 160 | b = make([]byte, 4) 161 | _, err = io.ReadFull(rd, b) 162 | if err != nil { 163 | return nil, err 164 | } 165 | binary.Read(bytes.NewBuffer(b), order, &hlength) 166 | if hlength+length+16 > 1<<27 { 167 | return nil, InvalidMessageError("message is too long") 168 | } 169 | dec = newDecoder(io.MultiReader(bytes.NewBuffer(b), rd), order) 170 | dec.pos = 12 171 | vs, err = dec.Decode(Signature{"a(yv)"}) 172 | if err != nil { 173 | return nil, err 174 | } 175 | if err = Store(vs, &headers); err != nil { 176 | return nil, err 177 | } 178 | 179 | msg.Headers = make(map[HeaderField]Variant) 180 | for _, v := range headers { 181 | msg.Headers[HeaderField(v.Field)] = v.Variant 182 | } 183 | 184 | dec.align(8) 185 | body := make([]byte, int(length)) 186 | if length != 0 { 187 | _, err := io.ReadFull(rd, body) 188 | if err != nil { 189 | return nil, err 190 | } 191 | } 192 | 193 | if err = msg.IsValid(); err != nil { 194 | return nil, err 195 | } 196 | sig, _ := msg.Headers[FieldSignature].value.(Signature) 197 | if sig.str != "" { 198 | buf := bytes.NewBuffer(body) 199 | dec = newDecoder(buf, order) 200 | vs, err := dec.Decode(sig) 201 | if err != nil { 202 | return nil, err 203 | } 204 | msg.Body = vs 205 | } 206 | 207 | return 208 | } 209 | 210 | // EncodeTo encodes and sends a message to the given writer. The byte order must 211 | // be either binary.LittleEndian or binary.BigEndian. If the message is not 212 | // valid or an error occurs when writing, an error is returned. 213 | func (msg *Message) EncodeTo(out io.Writer, order binary.ByteOrder) error { 214 | if err := msg.IsValid(); err != nil { 215 | return err 216 | } 217 | var vs [7]interface{} 218 | switch order { 219 | case binary.LittleEndian: 220 | vs[0] = byte('l') 221 | case binary.BigEndian: 222 | vs[0] = byte('B') 223 | default: 224 | return errors.New("dbus: invalid byte order") 225 | } 226 | body := new(bytes.Buffer) 227 | enc := newEncoder(body, order) 228 | if len(msg.Body) != 0 { 229 | enc.Encode(msg.Body...) 230 | } 231 | vs[1] = msg.Type 232 | vs[2] = msg.Flags 233 | vs[3] = protoVersion 234 | vs[4] = uint32(len(body.Bytes())) 235 | vs[5] = msg.serial 236 | headers := make([]header, 0, len(msg.Headers)) 237 | for k, v := range msg.Headers { 238 | headers = append(headers, header{byte(k), v}) 239 | } 240 | vs[6] = headers 241 | var buf bytes.Buffer 242 | enc = newEncoder(&buf, order) 243 | enc.Encode(vs[:]...) 244 | enc.align(8) 245 | body.WriteTo(&buf) 246 | if buf.Len() > 1<<27 { 247 | return InvalidMessageError("message is too long") 248 | } 249 | if _, err := buf.WriteTo(out); err != nil { 250 | return err 251 | } 252 | return nil 253 | } 254 | 255 | // IsValid checks whether msg is a valid message and returns an 256 | // InvalidMessageError if it is not. 257 | func (msg *Message) IsValid() error { 258 | if msg.Flags & ^(FlagNoAutoStart|FlagNoReplyExpected|FlagAllowInteractiveAuthorization) != 0 { 259 | return InvalidMessageError("invalid flags") 260 | } 261 | if msg.Type == 0 || msg.Type >= typeMax { 262 | return InvalidMessageError("invalid message type") 263 | } 264 | for k, v := range msg.Headers { 265 | if k == 0 || k >= fieldMax { 266 | return InvalidMessageError("invalid header") 267 | } 268 | if reflect.TypeOf(v.value) != fieldTypes[k] { 269 | return InvalidMessageError("invalid type of header field") 270 | } 271 | } 272 | for _, v := range requiredFields[msg.Type] { 273 | if _, ok := msg.Headers[v]; !ok { 274 | return InvalidMessageError("missing required header") 275 | } 276 | } 277 | if path, ok := msg.Headers[FieldPath]; ok { 278 | if !path.value.(ObjectPath).IsValid() { 279 | return InvalidMessageError("invalid path name") 280 | } 281 | } 282 | if iface, ok := msg.Headers[FieldInterface]; ok { 283 | if !isValidInterface(iface.value.(string)) { 284 | return InvalidMessageError("invalid interface name") 285 | } 286 | } 287 | if member, ok := msg.Headers[FieldMember]; ok { 288 | if !isValidMember(member.value.(string)) { 289 | return InvalidMessageError("invalid member name") 290 | } 291 | } 292 | if errname, ok := msg.Headers[FieldErrorName]; ok { 293 | if !isValidInterface(errname.value.(string)) { 294 | return InvalidMessageError("invalid error name") 295 | } 296 | } 297 | if len(msg.Body) != 0 { 298 | if _, ok := msg.Headers[FieldSignature]; !ok { 299 | return InvalidMessageError("missing signature") 300 | } 301 | } 302 | return nil 303 | } 304 | 305 | // Serial returns the message's serial number. The returned value is only valid 306 | // for messages received by eavesdropping. 307 | func (msg *Message) Serial() uint32 { 308 | return msg.serial 309 | } 310 | 311 | // String returns a string representation of a message similar to the format of 312 | // dbus-monitor. 313 | func (msg *Message) String() string { 314 | if err := msg.IsValid(); err != nil { 315 | return "" 316 | } 317 | s := msg.Type.String() 318 | if v, ok := msg.Headers[FieldSender]; ok { 319 | s += " from " + v.value.(string) 320 | } 321 | if v, ok := msg.Headers[FieldDestination]; ok { 322 | s += " to " + v.value.(string) 323 | } 324 | s += " serial " + strconv.FormatUint(uint64(msg.serial), 10) 325 | if v, ok := msg.Headers[FieldReplySerial]; ok { 326 | s += " reply_serial " + strconv.FormatUint(uint64(v.value.(uint32)), 10) 327 | } 328 | if v, ok := msg.Headers[FieldUnixFDs]; ok { 329 | s += " unixfds " + strconv.FormatUint(uint64(v.value.(uint32)), 10) 330 | } 331 | if v, ok := msg.Headers[FieldPath]; ok { 332 | s += " path " + string(v.value.(ObjectPath)) 333 | } 334 | if v, ok := msg.Headers[FieldInterface]; ok { 335 | s += " interface " + v.value.(string) 336 | } 337 | if v, ok := msg.Headers[FieldErrorName]; ok { 338 | s += " error " + v.value.(string) 339 | } 340 | if v, ok := msg.Headers[FieldMember]; ok { 341 | s += " member " + v.value.(string) 342 | } 343 | if len(msg.Body) != 0 { 344 | s += "\n" 345 | } 346 | for i, v := range msg.Body { 347 | s += " " + MakeVariant(v).String() 348 | if i != len(msg.Body)-1 { 349 | s += "\n" 350 | } 351 | } 352 | return s 353 | } 354 | -------------------------------------------------------------------------------- /vendor/github.com/armon/go-socks5/request.go: -------------------------------------------------------------------------------- 1 | package socks5 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "net" 7 | "strconv" 8 | "strings" 9 | 10 | "golang.org/x/net/context" 11 | ) 12 | 13 | const ( 14 | ConnectCommand = uint8(1) 15 | BindCommand = uint8(2) 16 | AssociateCommand = uint8(3) 17 | ipv4Address = uint8(1) 18 | fqdnAddress = uint8(3) 19 | ipv6Address = uint8(4) 20 | ) 21 | 22 | const ( 23 | successReply uint8 = iota 24 | serverFailure 25 | ruleFailure 26 | networkUnreachable 27 | hostUnreachable 28 | connectionRefused 29 | ttlExpired 30 | commandNotSupported 31 | addrTypeNotSupported 32 | ) 33 | 34 | var ( 35 | unrecognizedAddrType = fmt.Errorf("Unrecognized address type") 36 | ) 37 | 38 | // AddressRewriter is used to rewrite a destination transparently 39 | type AddressRewriter interface { 40 | Rewrite(ctx context.Context, request *Request) (context.Context, *AddrSpec) 41 | } 42 | 43 | // AddrSpec is used to return the target AddrSpec 44 | // which may be specified as IPv4, IPv6, or a FQDN 45 | type AddrSpec struct { 46 | FQDN string 47 | IP net.IP 48 | Port int 49 | } 50 | 51 | func (a *AddrSpec) String() string { 52 | if a.FQDN != "" { 53 | return fmt.Sprintf("%s (%s):%d", a.FQDN, a.IP, a.Port) 54 | } 55 | return fmt.Sprintf("%s:%d", a.IP, a.Port) 56 | } 57 | 58 | // Address returns a string suitable to dial; prefer returning IP-based 59 | // address, fallback to FQDN 60 | func (a AddrSpec) Address() string { 61 | if 0 != len(a.IP) { 62 | return net.JoinHostPort(a.IP.String(), strconv.Itoa(a.Port)) 63 | } 64 | return net.JoinHostPort(a.FQDN, strconv.Itoa(a.Port)) 65 | } 66 | 67 | // A Request represents request received by a server 68 | type Request struct { 69 | // Protocol version 70 | Version uint8 71 | // Requested command 72 | Command uint8 73 | // AuthContext provided during negotiation 74 | AuthContext *AuthContext 75 | // AddrSpec of the the network that sent the request 76 | RemoteAddr *AddrSpec 77 | // AddrSpec of the desired destination 78 | DestAddr *AddrSpec 79 | // AddrSpec of the actual destination (might be affected by rewrite) 80 | realDestAddr *AddrSpec 81 | bufConn io.Reader 82 | } 83 | 84 | type conn interface { 85 | Write([]byte) (int, error) 86 | RemoteAddr() net.Addr 87 | } 88 | 89 | // NewRequest creates a new Request from the tcp connection 90 | func NewRequest(bufConn io.Reader) (*Request, error) { 91 | // Read the version byte 92 | header := []byte{0, 0, 0} 93 | if _, err := io.ReadAtLeast(bufConn, header, 3); err != nil { 94 | return nil, fmt.Errorf("Failed to get command version: %v", err) 95 | } 96 | 97 | // Ensure we are compatible 98 | if header[0] != socks5Version { 99 | return nil, fmt.Errorf("Unsupported command version: %v", header[0]) 100 | } 101 | 102 | // Read in the destination address 103 | dest, err := readAddrSpec(bufConn) 104 | if err != nil { 105 | return nil, err 106 | } 107 | 108 | request := &Request{ 109 | Version: socks5Version, 110 | Command: header[1], 111 | DestAddr: dest, 112 | bufConn: bufConn, 113 | } 114 | 115 | return request, nil 116 | } 117 | 118 | // handleRequest is used for request processing after authentication 119 | func (s *Server) handleRequest(req *Request, conn conn) error { 120 | ctx := context.Background() 121 | 122 | // Resolve the address if we have a FQDN 123 | dest := req.DestAddr 124 | if dest.FQDN != "" { 125 | ctx_, addr, err := s.config.Resolver.Resolve(ctx, dest.FQDN) 126 | if err != nil { 127 | if err := sendReply(conn, hostUnreachable, nil); err != nil { 128 | return fmt.Errorf("Failed to send reply: %v", err) 129 | } 130 | return fmt.Errorf("Failed to resolve destination '%v': %v", dest.FQDN, err) 131 | } 132 | ctx = ctx_ 133 | dest.IP = addr 134 | } 135 | 136 | // Apply any address rewrites 137 | req.realDestAddr = req.DestAddr 138 | if s.config.Rewriter != nil { 139 | ctx, req.realDestAddr = s.config.Rewriter.Rewrite(ctx, req) 140 | } 141 | 142 | // Switch on the command 143 | switch req.Command { 144 | case ConnectCommand: 145 | return s.handleConnect(ctx, conn, req) 146 | case BindCommand: 147 | return s.handleBind(ctx, conn, req) 148 | case AssociateCommand: 149 | return s.handleAssociate(ctx, conn, req) 150 | default: 151 | if err := sendReply(conn, commandNotSupported, nil); err != nil { 152 | return fmt.Errorf("Failed to send reply: %v", err) 153 | } 154 | return fmt.Errorf("Unsupported command: %v", req.Command) 155 | } 156 | } 157 | 158 | // handleConnect is used to handle a connect command 159 | func (s *Server) handleConnect(ctx context.Context, conn conn, req *Request) error { 160 | // Check if this is allowed 161 | if ctx_, ok := s.config.Rules.Allow(ctx, req); !ok { 162 | if err := sendReply(conn, ruleFailure, nil); err != nil { 163 | return fmt.Errorf("Failed to send reply: %v", err) 164 | } 165 | return fmt.Errorf("Connect to %v blocked by rules", req.DestAddr) 166 | } else { 167 | ctx = ctx_ 168 | } 169 | 170 | // Attempt to connect 171 | dial := s.config.Dial 172 | if dial == nil { 173 | dial = func(ctx context.Context, net_, addr string) (net.Conn, error) { 174 | return net.Dial(net_, addr) 175 | } 176 | } 177 | target, err := dial(ctx, "tcp", req.realDestAddr.Address()) 178 | if err != nil { 179 | msg := err.Error() 180 | resp := hostUnreachable 181 | if strings.Contains(msg, "refused") { 182 | resp = connectionRefused 183 | } else if strings.Contains(msg, "network is unreachable") { 184 | resp = networkUnreachable 185 | } 186 | if err := sendReply(conn, resp, nil); err != nil { 187 | return fmt.Errorf("Failed to send reply: %v", err) 188 | } 189 | return fmt.Errorf("Connect to %v failed: %v", req.DestAddr, err) 190 | } 191 | defer target.Close() 192 | 193 | // Send success 194 | local := target.LocalAddr().(*net.TCPAddr) 195 | bind := AddrSpec{IP: local.IP, Port: local.Port} 196 | if err := sendReply(conn, successReply, &bind); err != nil { 197 | return fmt.Errorf("Failed to send reply: %v", err) 198 | } 199 | 200 | // Start proxying 201 | errCh := make(chan error, 2) 202 | go proxy(target, req.bufConn, errCh) 203 | go proxy(conn, target, errCh) 204 | 205 | // Wait 206 | for i := 0; i < 2; i++ { 207 | e := <-errCh 208 | if e != nil { 209 | // return from this function closes target (and conn). 210 | return e 211 | } 212 | } 213 | return nil 214 | } 215 | 216 | // handleBind is used to handle a connect command 217 | func (s *Server) handleBind(ctx context.Context, conn conn, req *Request) error { 218 | // Check if this is allowed 219 | if ctx_, ok := s.config.Rules.Allow(ctx, req); !ok { 220 | if err := sendReply(conn, ruleFailure, nil); err != nil { 221 | return fmt.Errorf("Failed to send reply: %v", err) 222 | } 223 | return fmt.Errorf("Bind to %v blocked by rules", req.DestAddr) 224 | } else { 225 | ctx = ctx_ 226 | } 227 | 228 | // TODO: Support bind 229 | if err := sendReply(conn, commandNotSupported, nil); err != nil { 230 | return fmt.Errorf("Failed to send reply: %v", err) 231 | } 232 | return nil 233 | } 234 | 235 | // handleAssociate is used to handle a connect command 236 | func (s *Server) handleAssociate(ctx context.Context, conn conn, req *Request) error { 237 | // Check if this is allowed 238 | if ctx_, ok := s.config.Rules.Allow(ctx, req); !ok { 239 | if err := sendReply(conn, ruleFailure, nil); err != nil { 240 | return fmt.Errorf("Failed to send reply: %v", err) 241 | } 242 | return fmt.Errorf("Associate to %v blocked by rules", req.DestAddr) 243 | } else { 244 | ctx = ctx_ 245 | } 246 | 247 | // TODO: Support associate 248 | if err := sendReply(conn, commandNotSupported, nil); err != nil { 249 | return fmt.Errorf("Failed to send reply: %v", err) 250 | } 251 | return nil 252 | } 253 | 254 | // readAddrSpec is used to read AddrSpec. 255 | // Expects an address type byte, follwed by the address and port 256 | func readAddrSpec(r io.Reader) (*AddrSpec, error) { 257 | d := &AddrSpec{} 258 | 259 | // Get the address type 260 | addrType := []byte{0} 261 | if _, err := r.Read(addrType); err != nil { 262 | return nil, err 263 | } 264 | 265 | // Handle on a per type basis 266 | switch addrType[0] { 267 | case ipv4Address: 268 | addr := make([]byte, 4) 269 | if _, err := io.ReadAtLeast(r, addr, len(addr)); err != nil { 270 | return nil, err 271 | } 272 | d.IP = net.IP(addr) 273 | 274 | case ipv6Address: 275 | addr := make([]byte, 16) 276 | if _, err := io.ReadAtLeast(r, addr, len(addr)); err != nil { 277 | return nil, err 278 | } 279 | d.IP = net.IP(addr) 280 | 281 | case fqdnAddress: 282 | if _, err := r.Read(addrType); err != nil { 283 | return nil, err 284 | } 285 | addrLen := int(addrType[0]) 286 | fqdn := make([]byte, addrLen) 287 | if _, err := io.ReadAtLeast(r, fqdn, addrLen); err != nil { 288 | return nil, err 289 | } 290 | d.FQDN = string(fqdn) 291 | 292 | default: 293 | return nil, unrecognizedAddrType 294 | } 295 | 296 | // Read the port 297 | port := []byte{0, 0} 298 | if _, err := io.ReadAtLeast(r, port, 2); err != nil { 299 | return nil, err 300 | } 301 | d.Port = (int(port[0]) << 8) | int(port[1]) 302 | 303 | return d, nil 304 | } 305 | 306 | // sendReply is used to send a reply message 307 | func sendReply(w io.Writer, resp uint8, addr *AddrSpec) error { 308 | // Format the address 309 | var addrType uint8 310 | var addrBody []byte 311 | var addrPort uint16 312 | switch { 313 | case addr == nil: 314 | addrType = ipv4Address 315 | addrBody = []byte{0, 0, 0, 0} 316 | addrPort = 0 317 | 318 | case addr.FQDN != "": 319 | addrType = fqdnAddress 320 | addrBody = append([]byte{byte(len(addr.FQDN))}, addr.FQDN...) 321 | addrPort = uint16(addr.Port) 322 | 323 | case addr.IP.To4() != nil: 324 | addrType = ipv4Address 325 | addrBody = []byte(addr.IP.To4()) 326 | addrPort = uint16(addr.Port) 327 | 328 | case addr.IP.To16() != nil: 329 | addrType = ipv6Address 330 | addrBody = []byte(addr.IP.To16()) 331 | addrPort = uint16(addr.Port) 332 | 333 | default: 334 | return fmt.Errorf("Failed to format address: %v", addr) 335 | } 336 | 337 | // Format the message 338 | msg := make([]byte, 6+len(addrBody)) 339 | msg[0] = socks5Version 340 | msg[1] = resp 341 | msg[2] = 0 // Reserved 342 | msg[3] = addrType 343 | copy(msg[4:], addrBody) 344 | msg[4+len(addrBody)] = byte(addrPort >> 8) 345 | msg[4+len(addrBody)+1] = byte(addrPort & 0xff) 346 | 347 | // Send the message 348 | _, err := w.Write(msg) 349 | return err 350 | } 351 | 352 | type closeWriter interface { 353 | CloseWrite() error 354 | } 355 | 356 | // proxy is used to suffle data from src to destination, and sends errors 357 | // down a dedicated channel 358 | func proxy(dst io.Writer, src io.Reader, errCh chan error) { 359 | _, err := io.Copy(dst, src) 360 | if tcpConn, ok := dst.(closeWriter); ok { 361 | tcpConn.CloseWrite() 362 | } 363 | errCh <- err 364 | } 365 | -------------------------------------------------------------------------------- /vendor/github.com/godbus/dbus/dbus.go: -------------------------------------------------------------------------------- 1 | package dbus 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "reflect" 7 | "strings" 8 | ) 9 | 10 | var ( 11 | byteType = reflect.TypeOf(byte(0)) 12 | boolType = reflect.TypeOf(false) 13 | uint8Type = reflect.TypeOf(uint8(0)) 14 | int16Type = reflect.TypeOf(int16(0)) 15 | uint16Type = reflect.TypeOf(uint16(0)) 16 | intType = reflect.TypeOf(int(0)) 17 | uintType = reflect.TypeOf(uint(0)) 18 | int32Type = reflect.TypeOf(int32(0)) 19 | uint32Type = reflect.TypeOf(uint32(0)) 20 | int64Type = reflect.TypeOf(int64(0)) 21 | uint64Type = reflect.TypeOf(uint64(0)) 22 | float64Type = reflect.TypeOf(float64(0)) 23 | stringType = reflect.TypeOf("") 24 | signatureType = reflect.TypeOf(Signature{""}) 25 | objectPathType = reflect.TypeOf(ObjectPath("")) 26 | variantType = reflect.TypeOf(Variant{Signature{""}, nil}) 27 | interfacesType = reflect.TypeOf([]interface{}{}) 28 | interfaceType = reflect.TypeOf((*interface{})(nil)).Elem() 29 | unixFDType = reflect.TypeOf(UnixFD(0)) 30 | unixFDIndexType = reflect.TypeOf(UnixFDIndex(0)) 31 | ) 32 | 33 | // An InvalidTypeError signals that a value which cannot be represented in the 34 | // D-Bus wire format was passed to a function. 35 | type InvalidTypeError struct { 36 | Type reflect.Type 37 | } 38 | 39 | func (e InvalidTypeError) Error() string { 40 | return "dbus: invalid type " + e.Type.String() 41 | } 42 | 43 | // Store copies the values contained in src to dest, which must be a slice of 44 | // pointers. It converts slices of interfaces from src to corresponding structs 45 | // in dest. An error is returned if the lengths of src and dest or the types of 46 | // their elements don't match. 47 | func Store(src []interface{}, dest ...interface{}) error { 48 | if len(src) != len(dest) { 49 | return errors.New("dbus.Store: length mismatch") 50 | } 51 | 52 | for i := range src { 53 | if err := storeInterfaces(src[i], dest[i]); err != nil { 54 | return err 55 | } 56 | } 57 | return nil 58 | } 59 | 60 | func storeInterfaces(src, dest interface{}) error { 61 | return store(reflect.ValueOf(dest), reflect.ValueOf(src)) 62 | } 63 | 64 | func store(dest, src reflect.Value) error { 65 | if dest.Kind() == reflect.Ptr { 66 | return store(dest.Elem(), src) 67 | } 68 | switch src.Kind() { 69 | case reflect.Slice: 70 | return storeSlice(dest, src) 71 | case reflect.Map: 72 | return storeMap(dest, src) 73 | default: 74 | return storeBase(dest, src) 75 | } 76 | } 77 | 78 | func storeBase(dest, src reflect.Value) error { 79 | return setDest(dest, src) 80 | } 81 | 82 | func setDest(dest, src reflect.Value) error { 83 | if !isVariant(src.Type()) && isVariant(dest.Type()) { 84 | //special conversion for dbus.Variant 85 | dest.Set(reflect.ValueOf(MakeVariant(src.Interface()))) 86 | return nil 87 | } 88 | if isVariant(src.Type()) && !isVariant(dest.Type()) { 89 | src = getVariantValue(src) 90 | } 91 | if !src.Type().ConvertibleTo(dest.Type()) { 92 | return fmt.Errorf( 93 | "dbus.Store: type mismatch: cannot convert %s to %s", 94 | src.Type(), dest.Type()) 95 | } 96 | dest.Set(src.Convert(dest.Type())) 97 | return nil 98 | } 99 | 100 | func kindsAreCompatible(dest, src reflect.Type) bool { 101 | switch { 102 | case isVariant(dest): 103 | return true 104 | case dest.Kind() == reflect.Interface: 105 | return true 106 | default: 107 | return dest.Kind() == src.Kind() 108 | } 109 | } 110 | 111 | func isConvertibleTo(dest, src reflect.Type) bool { 112 | switch { 113 | case isVariant(dest): 114 | return true 115 | case dest.Kind() == reflect.Interface: 116 | return true 117 | case dest.Kind() == reflect.Slice: 118 | return src.Kind() == reflect.Slice && 119 | isConvertibleTo(dest.Elem(), src.Elem()) 120 | case dest.Kind() == reflect.Struct: 121 | return src == interfacesType 122 | default: 123 | return src.ConvertibleTo(dest) 124 | } 125 | } 126 | 127 | func storeMap(dest, src reflect.Value) error { 128 | switch { 129 | case !kindsAreCompatible(dest.Type(), src.Type()): 130 | return fmt.Errorf( 131 | "dbus.Store: type mismatch: "+ 132 | "map: cannot store a value of %s into %s", 133 | src.Type(), dest.Type()) 134 | case isVariant(dest.Type()): 135 | return storeMapIntoVariant(dest, src) 136 | case dest.Kind() == reflect.Interface: 137 | return storeMapIntoInterface(dest, src) 138 | case isConvertibleTo(dest.Type().Key(), src.Type().Key()) && 139 | isConvertibleTo(dest.Type().Elem(), src.Type().Elem()): 140 | return storeMapIntoMap(dest, src) 141 | default: 142 | return fmt.Errorf( 143 | "dbus.Store: type mismatch: "+ 144 | "map: cannot convert a value of %s into %s", 145 | src.Type(), dest.Type()) 146 | } 147 | } 148 | 149 | func storeMapIntoVariant(dest, src reflect.Value) error { 150 | dv := reflect.MakeMap(src.Type()) 151 | err := store(dv, src) 152 | if err != nil { 153 | return err 154 | } 155 | return storeBase(dest, dv) 156 | } 157 | 158 | func storeMapIntoInterface(dest, src reflect.Value) error { 159 | var dv reflect.Value 160 | if isVariant(src.Type().Elem()) { 161 | //Convert variants to interface{} recursively when converting 162 | //to interface{} 163 | dv = reflect.MakeMap( 164 | reflect.MapOf(src.Type().Key(), interfaceType)) 165 | } else { 166 | dv = reflect.MakeMap(src.Type()) 167 | } 168 | err := store(dv, src) 169 | if err != nil { 170 | return err 171 | } 172 | return storeBase(dest, dv) 173 | } 174 | 175 | func storeMapIntoMap(dest, src reflect.Value) error { 176 | if dest.IsNil() { 177 | dest.Set(reflect.MakeMap(dest.Type())) 178 | } 179 | keys := src.MapKeys() 180 | for _, key := range keys { 181 | dkey := key.Convert(dest.Type().Key()) 182 | dval := reflect.New(dest.Type().Elem()).Elem() 183 | err := store(dval, getVariantValue(src.MapIndex(key))) 184 | if err != nil { 185 | return err 186 | } 187 | dest.SetMapIndex(dkey, dval) 188 | } 189 | return nil 190 | } 191 | 192 | func storeSlice(dest, src reflect.Value) error { 193 | switch { 194 | case src.Type() == interfacesType && dest.Kind() == reflect.Struct: 195 | //The decoder always decodes structs as slices of interface{} 196 | return storeStruct(dest, src) 197 | case !kindsAreCompatible(dest.Type(), src.Type()): 198 | return fmt.Errorf( 199 | "dbus.Store: type mismatch: "+ 200 | "slice: cannot store a value of %s into %s", 201 | src.Type(), dest.Type()) 202 | case isVariant(dest.Type()): 203 | return storeSliceIntoVariant(dest, src) 204 | case dest.Kind() == reflect.Interface: 205 | return storeSliceIntoInterface(dest, src) 206 | case isConvertibleTo(dest.Type().Elem(), src.Type().Elem()): 207 | return storeSliceIntoSlice(dest, src) 208 | default: 209 | return fmt.Errorf( 210 | "dbus.Store: type mismatch: "+ 211 | "slice: cannot convert a value of %s into %s", 212 | src.Type(), dest.Type()) 213 | } 214 | } 215 | 216 | func storeStruct(dest, src reflect.Value) error { 217 | if isVariant(dest.Type()) { 218 | return storeBase(dest, src) 219 | } 220 | dval := make([]interface{}, 0, dest.NumField()) 221 | dtype := dest.Type() 222 | for i := 0; i < dest.NumField(); i++ { 223 | field := dest.Field(i) 224 | ftype := dtype.Field(i) 225 | if ftype.PkgPath != "" { 226 | continue 227 | } 228 | if ftype.Tag.Get("dbus") == "-" { 229 | continue 230 | } 231 | dval = append(dval, field.Addr().Interface()) 232 | } 233 | if src.Len() != len(dval) { 234 | return fmt.Errorf( 235 | "dbus.Store: type mismatch: "+ 236 | "destination struct does not have "+ 237 | "enough fields need: %d have: %d", 238 | src.Len(), len(dval)) 239 | } 240 | return Store(src.Interface().([]interface{}), dval...) 241 | } 242 | 243 | func storeSliceIntoVariant(dest, src reflect.Value) error { 244 | dv := reflect.MakeSlice(src.Type(), src.Len(), src.Cap()) 245 | err := store(dv, src) 246 | if err != nil { 247 | return err 248 | } 249 | return storeBase(dest, dv) 250 | } 251 | 252 | func storeSliceIntoInterface(dest, src reflect.Value) error { 253 | var dv reflect.Value 254 | if isVariant(src.Type().Elem()) { 255 | //Convert variants to interface{} recursively when converting 256 | //to interface{} 257 | dv = reflect.MakeSlice(reflect.SliceOf(interfaceType), 258 | src.Len(), src.Cap()) 259 | } else { 260 | dv = reflect.MakeSlice(src.Type(), src.Len(), src.Cap()) 261 | } 262 | err := store(dv, src) 263 | if err != nil { 264 | return err 265 | } 266 | return storeBase(dest, dv) 267 | } 268 | 269 | func storeSliceIntoSlice(dest, src reflect.Value) error { 270 | if dest.IsNil() || dest.Len() < src.Len() { 271 | dest.Set(reflect.MakeSlice(dest.Type(), src.Len(), src.Cap())) 272 | } 273 | if dest.Len() != src.Len() { 274 | return fmt.Errorf( 275 | "dbus.Store: type mismatch: "+ 276 | "slices are different lengths "+ 277 | "need: %d have: %d", 278 | src.Len(), dest.Len()) 279 | } 280 | for i := 0; i < src.Len(); i++ { 281 | err := store(dest.Index(i), getVariantValue(src.Index(i))) 282 | if err != nil { 283 | return err 284 | } 285 | } 286 | return nil 287 | } 288 | 289 | func getVariantValue(in reflect.Value) reflect.Value { 290 | if isVariant(in.Type()) { 291 | return reflect.ValueOf(in.Interface().(Variant).Value()) 292 | } 293 | return in 294 | } 295 | 296 | func isVariant(t reflect.Type) bool { 297 | return t == variantType 298 | } 299 | 300 | // An ObjectPath is an object path as defined by the D-Bus spec. 301 | type ObjectPath string 302 | 303 | // IsValid returns whether the object path is valid. 304 | func (o ObjectPath) IsValid() bool { 305 | s := string(o) 306 | if len(s) == 0 { 307 | return false 308 | } 309 | if s[0] != '/' { 310 | return false 311 | } 312 | if s[len(s)-1] == '/' && len(s) != 1 { 313 | return false 314 | } 315 | // probably not used, but technically possible 316 | if s == "/" { 317 | return true 318 | } 319 | split := strings.Split(s[1:], "/") 320 | for _, v := range split { 321 | if len(v) == 0 { 322 | return false 323 | } 324 | for _, c := range v { 325 | if !isMemberChar(c) { 326 | return false 327 | } 328 | } 329 | } 330 | return true 331 | } 332 | 333 | // A UnixFD is a Unix file descriptor sent over the wire. See the package-level 334 | // documentation for more information about Unix file descriptor passsing. 335 | type UnixFD int32 336 | 337 | // A UnixFDIndex is the representation of a Unix file descriptor in a message. 338 | type UnixFDIndex uint32 339 | 340 | // alignment returns the alignment of values of type t. 341 | func alignment(t reflect.Type) int { 342 | switch t { 343 | case variantType: 344 | return 1 345 | case objectPathType: 346 | return 4 347 | case signatureType: 348 | return 1 349 | case interfacesType: 350 | return 4 351 | } 352 | switch t.Kind() { 353 | case reflect.Uint8: 354 | return 1 355 | case reflect.Uint16, reflect.Int16: 356 | return 2 357 | case reflect.Uint, reflect.Int, reflect.Uint32, reflect.Int32, reflect.String, reflect.Array, reflect.Slice, reflect.Map: 358 | return 4 359 | case reflect.Uint64, reflect.Int64, reflect.Float64, reflect.Struct: 360 | return 8 361 | case reflect.Ptr: 362 | return alignment(t.Elem()) 363 | } 364 | return 1 365 | } 366 | 367 | // isKeyType returns whether t is a valid type for a D-Bus dict. 368 | func isKeyType(t reflect.Type) bool { 369 | switch t.Kind() { 370 | case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, 371 | reflect.Int16, reflect.Int32, reflect.Int64, reflect.Float64, 372 | reflect.String, reflect.Uint, reflect.Int: 373 | 374 | return true 375 | } 376 | return false 377 | } 378 | 379 | // isValidInterface returns whether s is a valid name for an interface. 380 | func isValidInterface(s string) bool { 381 | if len(s) == 0 || len(s) > 255 || s[0] == '.' { 382 | return false 383 | } 384 | elem := strings.Split(s, ".") 385 | if len(elem) < 2 { 386 | return false 387 | } 388 | for _, v := range elem { 389 | if len(v) == 0 { 390 | return false 391 | } 392 | if v[0] >= '0' && v[0] <= '9' { 393 | return false 394 | } 395 | for _, c := range v { 396 | if !isMemberChar(c) { 397 | return false 398 | } 399 | } 400 | } 401 | return true 402 | } 403 | 404 | // isValidMember returns whether s is a valid name for a member. 405 | func isValidMember(s string) bool { 406 | if len(s) == 0 || len(s) > 255 { 407 | return false 408 | } 409 | i := strings.Index(s, ".") 410 | if i != -1 { 411 | return false 412 | } 413 | if s[0] >= '0' && s[0] <= '9' { 414 | return false 415 | } 416 | for _, c := range s { 417 | if !isMemberChar(c) { 418 | return false 419 | } 420 | } 421 | return true 422 | } 423 | 424 | func isMemberChar(c rune) bool { 425 | return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || 426 | (c >= 'a' && c <= 'z') || c == '_' 427 | } 428 | -------------------------------------------------------------------------------- /vendor/github.com/godbus/dbus/export.go: -------------------------------------------------------------------------------- 1 | package dbus 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "reflect" 7 | "strings" 8 | ) 9 | 10 | var ( 11 | ErrMsgInvalidArg = Error{ 12 | "org.freedesktop.DBus.Error.InvalidArgs", 13 | []interface{}{"Invalid type / number of args"}, 14 | } 15 | ErrMsgNoObject = Error{ 16 | "org.freedesktop.DBus.Error.NoSuchObject", 17 | []interface{}{"No such object"}, 18 | } 19 | ErrMsgUnknownMethod = Error{ 20 | "org.freedesktop.DBus.Error.UnknownMethod", 21 | []interface{}{"Unknown / invalid method"}, 22 | } 23 | ErrMsgUnknownInterface = Error{ 24 | "org.freedesktop.DBus.Error.UnknownInterface", 25 | []interface{}{"Object does not implement the interface"}, 26 | } 27 | ) 28 | 29 | func MakeFailedError(err error) *Error { 30 | return &Error{ 31 | "org.freedesktop.DBus.Error.Failed", 32 | []interface{}{err.Error()}, 33 | } 34 | } 35 | 36 | // Sender is a type which can be used in exported methods to receive the message 37 | // sender. 38 | type Sender string 39 | 40 | func computeMethodName(name string, mapping map[string]string) string { 41 | newname, ok := mapping[name] 42 | if ok { 43 | name = newname 44 | } 45 | return name 46 | } 47 | 48 | func getMethods(in interface{}, mapping map[string]string) map[string]reflect.Value { 49 | if in == nil { 50 | return nil 51 | } 52 | methods := make(map[string]reflect.Value) 53 | val := reflect.ValueOf(in) 54 | typ := val.Type() 55 | for i := 0; i < typ.NumMethod(); i++ { 56 | methtype := typ.Method(i) 57 | method := val.Method(i) 58 | t := method.Type() 59 | // only track valid methods must return *Error as last arg 60 | // and must be exported 61 | if t.NumOut() == 0 || 62 | t.Out(t.NumOut()-1) != reflect.TypeOf(&ErrMsgInvalidArg) || 63 | methtype.PkgPath != "" { 64 | continue 65 | } 66 | // map names while building table 67 | methods[computeMethodName(methtype.Name, mapping)] = method 68 | } 69 | return methods 70 | } 71 | 72 | func standardMethodArgumentDecode(m Method, sender string, msg *Message, body []interface{}) ([]interface{}, error) { 73 | pointers := make([]interface{}, m.NumArguments()) 74 | decode := make([]interface{}, 0, len(body)) 75 | 76 | for i := 0; i < m.NumArguments(); i++ { 77 | tp := reflect.TypeOf(m.ArgumentValue(i)) 78 | val := reflect.New(tp) 79 | pointers[i] = val.Interface() 80 | if tp == reflect.TypeOf((*Sender)(nil)).Elem() { 81 | val.Elem().SetString(sender) 82 | } else if tp == reflect.TypeOf((*Message)(nil)).Elem() { 83 | val.Elem().Set(reflect.ValueOf(*msg)) 84 | } else { 85 | decode = append(decode, pointers[i]) 86 | } 87 | } 88 | 89 | if len(decode) != len(body) { 90 | return nil, ErrMsgInvalidArg 91 | } 92 | 93 | if err := Store(body, decode...); err != nil { 94 | return nil, ErrMsgInvalidArg 95 | } 96 | 97 | return pointers, nil 98 | } 99 | 100 | func (conn *Conn) decodeArguments(m Method, sender string, msg *Message) ([]interface{}, error) { 101 | if decoder, ok := m.(ArgumentDecoder); ok { 102 | return decoder.DecodeArguments(conn, sender, msg, msg.Body) 103 | } 104 | return standardMethodArgumentDecode(m, sender, msg, msg.Body) 105 | } 106 | 107 | // handleCall handles the given method call (i.e. looks if it's one of the 108 | // pre-implemented ones and searches for a corresponding handler if not). 109 | func (conn *Conn) handleCall(msg *Message) { 110 | name := msg.Headers[FieldMember].value.(string) 111 | path := msg.Headers[FieldPath].value.(ObjectPath) 112 | ifaceName, _ := msg.Headers[FieldInterface].value.(string) 113 | sender, hasSender := msg.Headers[FieldSender].value.(string) 114 | serial := msg.serial 115 | if ifaceName == "org.freedesktop.DBus.Peer" { 116 | switch name { 117 | case "Ping": 118 | conn.sendReply(sender, serial) 119 | case "GetMachineId": 120 | conn.sendReply(sender, serial, conn.uuid) 121 | default: 122 | conn.sendError(ErrMsgUnknownMethod, sender, serial) 123 | } 124 | return 125 | } 126 | if len(name) == 0 { 127 | conn.sendError(ErrMsgUnknownMethod, sender, serial) 128 | } 129 | 130 | object, ok := conn.handler.LookupObject(path) 131 | if !ok { 132 | conn.sendError(ErrMsgNoObject, sender, serial) 133 | return 134 | } 135 | 136 | iface, exists := object.LookupInterface(ifaceName) 137 | if !exists { 138 | conn.sendError(ErrMsgUnknownInterface, sender, serial) 139 | return 140 | } 141 | 142 | m, exists := iface.LookupMethod(name) 143 | if !exists { 144 | conn.sendError(ErrMsgUnknownMethod, sender, serial) 145 | return 146 | } 147 | args, err := conn.decodeArguments(m, sender, msg) 148 | if err != nil { 149 | conn.sendError(err, sender, serial) 150 | return 151 | } 152 | 153 | ret, err := m.Call(args...) 154 | if err != nil { 155 | conn.sendError(err, sender, serial) 156 | return 157 | } 158 | 159 | if msg.Flags&FlagNoReplyExpected == 0 { 160 | reply := new(Message) 161 | reply.Type = TypeMethodReply 162 | reply.serial = conn.getSerial() 163 | reply.Headers = make(map[HeaderField]Variant) 164 | if hasSender { 165 | reply.Headers[FieldDestination] = msg.Headers[FieldSender] 166 | } 167 | reply.Headers[FieldReplySerial] = MakeVariant(msg.serial) 168 | reply.Body = make([]interface{}, len(ret)) 169 | for i := 0; i < len(ret); i++ { 170 | reply.Body[i] = ret[i] 171 | } 172 | reply.Headers[FieldSignature] = MakeVariant(SignatureOf(reply.Body...)) 173 | conn.outLck.RLock() 174 | if !conn.closed { 175 | conn.out <- reply 176 | } 177 | conn.outLck.RUnlock() 178 | } 179 | } 180 | 181 | // Emit emits the given signal on the message bus. The name parameter must be 182 | // formatted as "interface.member", e.g., "org.freedesktop.DBus.NameLost". 183 | func (conn *Conn) Emit(path ObjectPath, name string, values ...interface{}) error { 184 | if !path.IsValid() { 185 | return errors.New("dbus: invalid object path") 186 | } 187 | i := strings.LastIndex(name, ".") 188 | if i == -1 { 189 | return errors.New("dbus: invalid method name") 190 | } 191 | iface := name[:i] 192 | member := name[i+1:] 193 | if !isValidMember(member) { 194 | return errors.New("dbus: invalid method name") 195 | } 196 | if !isValidInterface(iface) { 197 | return errors.New("dbus: invalid interface name") 198 | } 199 | msg := new(Message) 200 | msg.Type = TypeSignal 201 | msg.serial = conn.getSerial() 202 | msg.Headers = make(map[HeaderField]Variant) 203 | msg.Headers[FieldInterface] = MakeVariant(iface) 204 | msg.Headers[FieldMember] = MakeVariant(member) 205 | msg.Headers[FieldPath] = MakeVariant(path) 206 | msg.Body = values 207 | if len(values) > 0 { 208 | msg.Headers[FieldSignature] = MakeVariant(SignatureOf(values...)) 209 | } 210 | conn.outLck.RLock() 211 | defer conn.outLck.RUnlock() 212 | if conn.closed { 213 | return ErrClosed 214 | } 215 | conn.out <- msg 216 | return nil 217 | } 218 | 219 | // Export registers the given value to be exported as an object on the 220 | // message bus. 221 | // 222 | // If a method call on the given path and interface is received, an exported 223 | // method with the same name is called with v as the receiver if the 224 | // parameters match and the last return value is of type *Error. If this 225 | // *Error is not nil, it is sent back to the caller as an error. 226 | // Otherwise, a method reply is sent with the other return values as its body. 227 | // 228 | // Any parameters with the special type Sender are set to the sender of the 229 | // dbus message when the method is called. Parameters of this type do not 230 | // contribute to the dbus signature of the method (i.e. the method is exposed 231 | // as if the parameters of type Sender were not there). 232 | // 233 | // Similarly, any parameters with the type Message are set to the raw message 234 | // received on the bus. Again, parameters of this type do not contribute to the 235 | // dbus signature of the method. 236 | // 237 | // Every method call is executed in a new goroutine, so the method may be called 238 | // in multiple goroutines at once. 239 | // 240 | // Method calls on the interface org.freedesktop.DBus.Peer will be automatically 241 | // handled for every object. 242 | // 243 | // Passing nil as the first parameter will cause conn to cease handling calls on 244 | // the given combination of path and interface. 245 | // 246 | // Export returns an error if path is not a valid path name. 247 | func (conn *Conn) Export(v interface{}, path ObjectPath, iface string) error { 248 | return conn.ExportWithMap(v, nil, path, iface) 249 | } 250 | 251 | // ExportWithMap works exactly like Export but provides the ability to remap 252 | // method names (e.g. export a lower-case method). 253 | // 254 | // The keys in the map are the real method names (exported on the struct), and 255 | // the values are the method names to be exported on DBus. 256 | func (conn *Conn) ExportWithMap(v interface{}, mapping map[string]string, path ObjectPath, iface string) error { 257 | return conn.export(getMethods(v, mapping), path, iface, false) 258 | } 259 | 260 | // ExportSubtree works exactly like Export but registers the given value for 261 | // an entire subtree rather under the root path provided. 262 | // 263 | // In order to make this useful, one parameter in each of the value's exported 264 | // methods should be a Message, in which case it will contain the raw message 265 | // (allowing one to get access to the path that caused the method to be called). 266 | // 267 | // Note that more specific export paths take precedence over less specific. For 268 | // example, a method call using the ObjectPath /foo/bar/baz will call a method 269 | // exported on /foo/bar before a method exported on /foo. 270 | func (conn *Conn) ExportSubtree(v interface{}, path ObjectPath, iface string) error { 271 | return conn.ExportSubtreeWithMap(v, nil, path, iface) 272 | } 273 | 274 | // ExportSubtreeWithMap works exactly like ExportSubtree but provides the 275 | // ability to remap method names (e.g. export a lower-case method). 276 | // 277 | // The keys in the map are the real method names (exported on the struct), and 278 | // the values are the method names to be exported on DBus. 279 | func (conn *Conn) ExportSubtreeWithMap(v interface{}, mapping map[string]string, path ObjectPath, iface string) error { 280 | return conn.export(getMethods(v, mapping), path, iface, true) 281 | } 282 | 283 | // ExportMethodTable like Export registers the given methods as an object 284 | // on the message bus. Unlike Export the it uses a method table to define 285 | // the object instead of a native go object. 286 | // 287 | // The method table is a map from method name to function closure 288 | // representing the method. This allows an object exported on the bus to not 289 | // necessarily be a native go object. It can be useful for generating exposed 290 | // methods on the fly. 291 | // 292 | // Any non-function objects in the method table are ignored. 293 | func (conn *Conn) ExportMethodTable(methods map[string]interface{}, path ObjectPath, iface string) error { 294 | return conn.exportMethodTable(methods, path, iface, false) 295 | } 296 | 297 | // Like ExportSubtree, but with the same caveats as ExportMethodTable. 298 | func (conn *Conn) ExportSubtreeMethodTable(methods map[string]interface{}, path ObjectPath, iface string) error { 299 | return conn.exportMethodTable(methods, path, iface, true) 300 | } 301 | 302 | func (conn *Conn) exportMethodTable(methods map[string]interface{}, path ObjectPath, iface string, includeSubtree bool) error { 303 | out := make(map[string]reflect.Value) 304 | for name, method := range methods { 305 | rval := reflect.ValueOf(method) 306 | if rval.Kind() != reflect.Func { 307 | continue 308 | } 309 | t := rval.Type() 310 | // only track valid methods must return *Error as last arg 311 | if t.NumOut() == 0 || 312 | t.Out(t.NumOut()-1) != reflect.TypeOf(&ErrMsgInvalidArg) { 313 | continue 314 | } 315 | out[name] = rval 316 | } 317 | return conn.export(out, path, iface, includeSubtree) 318 | } 319 | 320 | func (conn *Conn) unexport(h *defaultHandler, path ObjectPath, iface string) error { 321 | if h.PathExists(path) { 322 | obj := h.objects[path] 323 | obj.DeleteInterface(iface) 324 | if len(obj.interfaces) == 0 { 325 | h.DeleteObject(path) 326 | } 327 | } 328 | return nil 329 | } 330 | 331 | // exportWithMap is the worker function for all exports/registrations. 332 | func (conn *Conn) export(methods map[string]reflect.Value, path ObjectPath, iface string, includeSubtree bool) error { 333 | h, ok := conn.handler.(*defaultHandler) 334 | if !ok { 335 | return fmt.Errorf( 336 | `dbus: export only allowed on the default hander handler have %T"`, 337 | conn.handler) 338 | } 339 | 340 | if !path.IsValid() { 341 | return fmt.Errorf(`dbus: Invalid path name: "%s"`, path) 342 | } 343 | 344 | // Remove a previous export if the interface is nil 345 | if methods == nil { 346 | return conn.unexport(h, path, iface) 347 | } 348 | 349 | // If this is the first handler for this path, make a new map to hold all 350 | // handlers for this path. 351 | if !h.PathExists(path) { 352 | h.AddObject(path, newExportedObject()) 353 | } 354 | 355 | exportedMethods := make(map[string]Method) 356 | for name, method := range methods { 357 | exportedMethods[name] = exportedMethod{method} 358 | } 359 | 360 | // Finally, save this handler 361 | obj := h.objects[path] 362 | obj.AddInterface(iface, newExportedIntf(exportedMethods, includeSubtree)) 363 | 364 | return nil 365 | } 366 | 367 | // ReleaseName calls org.freedesktop.DBus.ReleaseName and awaits a response. 368 | func (conn *Conn) ReleaseName(name string) (ReleaseNameReply, error) { 369 | var r uint32 370 | err := conn.busObj.Call("org.freedesktop.DBus.ReleaseName", 0, name).Store(&r) 371 | if err != nil { 372 | return 0, err 373 | } 374 | return ReleaseNameReply(r), nil 375 | } 376 | 377 | // RequestName calls org.freedesktop.DBus.RequestName and awaits a response. 378 | func (conn *Conn) RequestName(name string, flags RequestNameFlags) (RequestNameReply, error) { 379 | var r uint32 380 | err := conn.busObj.Call("org.freedesktop.DBus.RequestName", 0, name, flags).Store(&r) 381 | if err != nil { 382 | return 0, err 383 | } 384 | return RequestNameReply(r), nil 385 | } 386 | 387 | // ReleaseNameReply is the reply to a ReleaseName call. 388 | type ReleaseNameReply uint32 389 | 390 | const ( 391 | ReleaseNameReplyReleased ReleaseNameReply = 1 + iota 392 | ReleaseNameReplyNonExistent 393 | ReleaseNameReplyNotOwner 394 | ) 395 | 396 | // RequestNameFlags represents the possible flags for a RequestName call. 397 | type RequestNameFlags uint32 398 | 399 | const ( 400 | NameFlagAllowReplacement RequestNameFlags = 1 << iota 401 | NameFlagReplaceExisting 402 | NameFlagDoNotQueue 403 | ) 404 | 405 | // RequestNameReply is the reply to a RequestName call. 406 | type RequestNameReply uint32 407 | 408 | const ( 409 | RequestNameReplyPrimaryOwner RequestNameReply = 1 + iota 410 | RequestNameReplyInQueue 411 | RequestNameReplyExists 412 | RequestNameReplyAlreadyOwner 413 | ) 414 | -------------------------------------------------------------------------------- /vendor/github.com/BurntSushi/toml/decode.go: -------------------------------------------------------------------------------- 1 | package toml 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "io/ioutil" 7 | "math" 8 | "reflect" 9 | "strings" 10 | "time" 11 | ) 12 | 13 | func e(format string, args ...interface{}) error { 14 | return fmt.Errorf("toml: "+format, args...) 15 | } 16 | 17 | // Unmarshaler is the interface implemented by objects that can unmarshal a 18 | // TOML description of themselves. 19 | type Unmarshaler interface { 20 | UnmarshalTOML(interface{}) error 21 | } 22 | 23 | // Unmarshal decodes the contents of `p` in TOML format into a pointer `v`. 24 | func Unmarshal(p []byte, v interface{}) error { 25 | _, err := Decode(string(p), v) 26 | return err 27 | } 28 | 29 | // Primitive is a TOML value that hasn't been decoded into a Go value. 30 | // When using the various `Decode*` functions, the type `Primitive` may 31 | // be given to any value, and its decoding will be delayed. 32 | // 33 | // A `Primitive` value can be decoded using the `PrimitiveDecode` function. 34 | // 35 | // The underlying representation of a `Primitive` value is subject to change. 36 | // Do not rely on it. 37 | // 38 | // N.B. Primitive values are still parsed, so using them will only avoid 39 | // the overhead of reflection. They can be useful when you don't know the 40 | // exact type of TOML data until run time. 41 | type Primitive struct { 42 | undecoded interface{} 43 | context Key 44 | } 45 | 46 | // DEPRECATED! 47 | // 48 | // Use MetaData.PrimitiveDecode instead. 49 | func PrimitiveDecode(primValue Primitive, v interface{}) error { 50 | md := MetaData{decoded: make(map[string]bool)} 51 | return md.unify(primValue.undecoded, rvalue(v)) 52 | } 53 | 54 | // PrimitiveDecode is just like the other `Decode*` functions, except it 55 | // decodes a TOML value that has already been parsed. Valid primitive values 56 | // can *only* be obtained from values filled by the decoder functions, 57 | // including this method. (i.e., `v` may contain more `Primitive` 58 | // values.) 59 | // 60 | // Meta data for primitive values is included in the meta data returned by 61 | // the `Decode*` functions with one exception: keys returned by the Undecoded 62 | // method will only reflect keys that were decoded. Namely, any keys hidden 63 | // behind a Primitive will be considered undecoded. Executing this method will 64 | // update the undecoded keys in the meta data. (See the example.) 65 | func (md *MetaData) PrimitiveDecode(primValue Primitive, v interface{}) error { 66 | md.context = primValue.context 67 | defer func() { md.context = nil }() 68 | return md.unify(primValue.undecoded, rvalue(v)) 69 | } 70 | 71 | // Decode will decode the contents of `data` in TOML format into a pointer 72 | // `v`. 73 | // 74 | // TOML hashes correspond to Go structs or maps. (Dealer's choice. They can be 75 | // used interchangeably.) 76 | // 77 | // TOML arrays of tables correspond to either a slice of structs or a slice 78 | // of maps. 79 | // 80 | // TOML datetimes correspond to Go `time.Time` values. 81 | // 82 | // All other TOML types (float, string, int, bool and array) correspond 83 | // to the obvious Go types. 84 | // 85 | // An exception to the above rules is if a type implements the 86 | // encoding.TextUnmarshaler interface. In this case, any primitive TOML value 87 | // (floats, strings, integers, booleans and datetimes) will be converted to 88 | // a byte string and given to the value's UnmarshalText method. See the 89 | // Unmarshaler example for a demonstration with time duration strings. 90 | // 91 | // Key mapping 92 | // 93 | // TOML keys can map to either keys in a Go map or field names in a Go 94 | // struct. The special `toml` struct tag may be used to map TOML keys to 95 | // struct fields that don't match the key name exactly. (See the example.) 96 | // A case insensitive match to struct names will be tried if an exact match 97 | // can't be found. 98 | // 99 | // The mapping between TOML values and Go values is loose. That is, there 100 | // may exist TOML values that cannot be placed into your representation, and 101 | // there may be parts of your representation that do not correspond to 102 | // TOML values. This loose mapping can be made stricter by using the IsDefined 103 | // and/or Undecoded methods on the MetaData returned. 104 | // 105 | // This decoder will not handle cyclic types. If a cyclic type is passed, 106 | // `Decode` will not terminate. 107 | func Decode(data string, v interface{}) (MetaData, error) { 108 | rv := reflect.ValueOf(v) 109 | if rv.Kind() != reflect.Ptr { 110 | return MetaData{}, e("Decode of non-pointer %s", reflect.TypeOf(v)) 111 | } 112 | if rv.IsNil() { 113 | return MetaData{}, e("Decode of nil %s", reflect.TypeOf(v)) 114 | } 115 | p, err := parse(data) 116 | if err != nil { 117 | return MetaData{}, err 118 | } 119 | md := MetaData{ 120 | p.mapping, p.types, p.ordered, 121 | make(map[string]bool, len(p.ordered)), nil, 122 | } 123 | return md, md.unify(p.mapping, indirect(rv)) 124 | } 125 | 126 | // DecodeFile is just like Decode, except it will automatically read the 127 | // contents of the file at `fpath` and decode it for you. 128 | func DecodeFile(fpath string, v interface{}) (MetaData, error) { 129 | bs, err := ioutil.ReadFile(fpath) 130 | if err != nil { 131 | return MetaData{}, err 132 | } 133 | return Decode(string(bs), v) 134 | } 135 | 136 | // DecodeReader is just like Decode, except it will consume all bytes 137 | // from the reader and decode it for you. 138 | func DecodeReader(r io.Reader, v interface{}) (MetaData, error) { 139 | bs, err := ioutil.ReadAll(r) 140 | if err != nil { 141 | return MetaData{}, err 142 | } 143 | return Decode(string(bs), v) 144 | } 145 | 146 | // unify performs a sort of type unification based on the structure of `rv`, 147 | // which is the client representation. 148 | // 149 | // Any type mismatch produces an error. Finding a type that we don't know 150 | // how to handle produces an unsupported type error. 151 | func (md *MetaData) unify(data interface{}, rv reflect.Value) error { 152 | 153 | // Special case. Look for a `Primitive` value. 154 | if rv.Type() == reflect.TypeOf((*Primitive)(nil)).Elem() { 155 | // Save the undecoded data and the key context into the primitive 156 | // value. 157 | context := make(Key, len(md.context)) 158 | copy(context, md.context) 159 | rv.Set(reflect.ValueOf(Primitive{ 160 | undecoded: data, 161 | context: context, 162 | })) 163 | return nil 164 | } 165 | 166 | // Special case. Unmarshaler Interface support. 167 | if rv.CanAddr() { 168 | if v, ok := rv.Addr().Interface().(Unmarshaler); ok { 169 | return v.UnmarshalTOML(data) 170 | } 171 | } 172 | 173 | // Special case. Handle time.Time values specifically. 174 | // TODO: Remove this code when we decide to drop support for Go 1.1. 175 | // This isn't necessary in Go 1.2 because time.Time satisfies the encoding 176 | // interfaces. 177 | if rv.Type().AssignableTo(rvalue(time.Time{}).Type()) { 178 | return md.unifyDatetime(data, rv) 179 | } 180 | 181 | // Special case. Look for a value satisfying the TextUnmarshaler interface. 182 | if v, ok := rv.Interface().(TextUnmarshaler); ok { 183 | return md.unifyText(data, v) 184 | } 185 | // BUG(burntsushi) 186 | // The behavior here is incorrect whenever a Go type satisfies the 187 | // encoding.TextUnmarshaler interface but also corresponds to a TOML 188 | // hash or array. In particular, the unmarshaler should only be applied 189 | // to primitive TOML values. But at this point, it will be applied to 190 | // all kinds of values and produce an incorrect error whenever those values 191 | // are hashes or arrays (including arrays of tables). 192 | 193 | k := rv.Kind() 194 | 195 | // laziness 196 | if k >= reflect.Int && k <= reflect.Uint64 { 197 | return md.unifyInt(data, rv) 198 | } 199 | switch k { 200 | case reflect.Ptr: 201 | elem := reflect.New(rv.Type().Elem()) 202 | err := md.unify(data, reflect.Indirect(elem)) 203 | if err != nil { 204 | return err 205 | } 206 | rv.Set(elem) 207 | return nil 208 | case reflect.Struct: 209 | return md.unifyStruct(data, rv) 210 | case reflect.Map: 211 | return md.unifyMap(data, rv) 212 | case reflect.Array: 213 | return md.unifyArray(data, rv) 214 | case reflect.Slice: 215 | return md.unifySlice(data, rv) 216 | case reflect.String: 217 | return md.unifyString(data, rv) 218 | case reflect.Bool: 219 | return md.unifyBool(data, rv) 220 | case reflect.Interface: 221 | // we only support empty interfaces. 222 | if rv.NumMethod() > 0 { 223 | return e("unsupported type %s", rv.Type()) 224 | } 225 | return md.unifyAnything(data, rv) 226 | case reflect.Float32: 227 | fallthrough 228 | case reflect.Float64: 229 | return md.unifyFloat64(data, rv) 230 | } 231 | return e("unsupported type %s", rv.Kind()) 232 | } 233 | 234 | func (md *MetaData) unifyStruct(mapping interface{}, rv reflect.Value) error { 235 | tmap, ok := mapping.(map[string]interface{}) 236 | if !ok { 237 | if mapping == nil { 238 | return nil 239 | } 240 | return e("type mismatch for %s: expected table but found %T", 241 | rv.Type().String(), mapping) 242 | } 243 | 244 | for key, datum := range tmap { 245 | var f *field 246 | fields := cachedTypeFields(rv.Type()) 247 | for i := range fields { 248 | ff := &fields[i] 249 | if ff.name == key { 250 | f = ff 251 | break 252 | } 253 | if f == nil && strings.EqualFold(ff.name, key) { 254 | f = ff 255 | } 256 | } 257 | if f != nil { 258 | subv := rv 259 | for _, i := range f.index { 260 | subv = indirect(subv.Field(i)) 261 | } 262 | if isUnifiable(subv) { 263 | md.decoded[md.context.add(key).String()] = true 264 | md.context = append(md.context, key) 265 | if err := md.unify(datum, subv); err != nil { 266 | return err 267 | } 268 | md.context = md.context[0 : len(md.context)-1] 269 | } else if f.name != "" { 270 | // Bad user! No soup for you! 271 | return e("cannot write unexported field %s.%s", 272 | rv.Type().String(), f.name) 273 | } 274 | } 275 | } 276 | return nil 277 | } 278 | 279 | func (md *MetaData) unifyMap(mapping interface{}, rv reflect.Value) error { 280 | tmap, ok := mapping.(map[string]interface{}) 281 | if !ok { 282 | if tmap == nil { 283 | return nil 284 | } 285 | return badtype("map", mapping) 286 | } 287 | if rv.IsNil() { 288 | rv.Set(reflect.MakeMap(rv.Type())) 289 | } 290 | for k, v := range tmap { 291 | md.decoded[md.context.add(k).String()] = true 292 | md.context = append(md.context, k) 293 | 294 | rvkey := indirect(reflect.New(rv.Type().Key())) 295 | rvval := reflect.Indirect(reflect.New(rv.Type().Elem())) 296 | if err := md.unify(v, rvval); err != nil { 297 | return err 298 | } 299 | md.context = md.context[0 : len(md.context)-1] 300 | 301 | rvkey.SetString(k) 302 | rv.SetMapIndex(rvkey, rvval) 303 | } 304 | return nil 305 | } 306 | 307 | func (md *MetaData) unifyArray(data interface{}, rv reflect.Value) error { 308 | datav := reflect.ValueOf(data) 309 | if datav.Kind() != reflect.Slice { 310 | if !datav.IsValid() { 311 | return nil 312 | } 313 | return badtype("slice", data) 314 | } 315 | sliceLen := datav.Len() 316 | if sliceLen != rv.Len() { 317 | return e("expected array length %d; got TOML array of length %d", 318 | rv.Len(), sliceLen) 319 | } 320 | return md.unifySliceArray(datav, rv) 321 | } 322 | 323 | func (md *MetaData) unifySlice(data interface{}, rv reflect.Value) error { 324 | datav := reflect.ValueOf(data) 325 | if datav.Kind() != reflect.Slice { 326 | if !datav.IsValid() { 327 | return nil 328 | } 329 | return badtype("slice", data) 330 | } 331 | n := datav.Len() 332 | if rv.IsNil() || rv.Cap() < n { 333 | rv.Set(reflect.MakeSlice(rv.Type(), n, n)) 334 | } 335 | rv.SetLen(n) 336 | return md.unifySliceArray(datav, rv) 337 | } 338 | 339 | func (md *MetaData) unifySliceArray(data, rv reflect.Value) error { 340 | sliceLen := data.Len() 341 | for i := 0; i < sliceLen; i++ { 342 | v := data.Index(i).Interface() 343 | sliceval := indirect(rv.Index(i)) 344 | if err := md.unify(v, sliceval); err != nil { 345 | return err 346 | } 347 | } 348 | return nil 349 | } 350 | 351 | func (md *MetaData) unifyDatetime(data interface{}, rv reflect.Value) error { 352 | if _, ok := data.(time.Time); ok { 353 | rv.Set(reflect.ValueOf(data)) 354 | return nil 355 | } 356 | return badtype("time.Time", data) 357 | } 358 | 359 | func (md *MetaData) unifyString(data interface{}, rv reflect.Value) error { 360 | if s, ok := data.(string); ok { 361 | rv.SetString(s) 362 | return nil 363 | } 364 | return badtype("string", data) 365 | } 366 | 367 | func (md *MetaData) unifyFloat64(data interface{}, rv reflect.Value) error { 368 | if num, ok := data.(float64); ok { 369 | switch rv.Kind() { 370 | case reflect.Float32: 371 | fallthrough 372 | case reflect.Float64: 373 | rv.SetFloat(num) 374 | default: 375 | panic("bug") 376 | } 377 | return nil 378 | } 379 | return badtype("float", data) 380 | } 381 | 382 | func (md *MetaData) unifyInt(data interface{}, rv reflect.Value) error { 383 | if num, ok := data.(int64); ok { 384 | if rv.Kind() >= reflect.Int && rv.Kind() <= reflect.Int64 { 385 | switch rv.Kind() { 386 | case reflect.Int, reflect.Int64: 387 | // No bounds checking necessary. 388 | case reflect.Int8: 389 | if num < math.MinInt8 || num > math.MaxInt8 { 390 | return e("value %d is out of range for int8", num) 391 | } 392 | case reflect.Int16: 393 | if num < math.MinInt16 || num > math.MaxInt16 { 394 | return e("value %d is out of range for int16", num) 395 | } 396 | case reflect.Int32: 397 | if num < math.MinInt32 || num > math.MaxInt32 { 398 | return e("value %d is out of range for int32", num) 399 | } 400 | } 401 | rv.SetInt(num) 402 | } else if rv.Kind() >= reflect.Uint && rv.Kind() <= reflect.Uint64 { 403 | unum := uint64(num) 404 | switch rv.Kind() { 405 | case reflect.Uint, reflect.Uint64: 406 | // No bounds checking necessary. 407 | case reflect.Uint8: 408 | if num < 0 || unum > math.MaxUint8 { 409 | return e("value %d is out of range for uint8", num) 410 | } 411 | case reflect.Uint16: 412 | if num < 0 || unum > math.MaxUint16 { 413 | return e("value %d is out of range for uint16", num) 414 | } 415 | case reflect.Uint32: 416 | if num < 0 || unum > math.MaxUint32 { 417 | return e("value %d is out of range for uint32", num) 418 | } 419 | } 420 | rv.SetUint(unum) 421 | } else { 422 | panic("unreachable") 423 | } 424 | return nil 425 | } 426 | return badtype("integer", data) 427 | } 428 | 429 | func (md *MetaData) unifyBool(data interface{}, rv reflect.Value) error { 430 | if b, ok := data.(bool); ok { 431 | rv.SetBool(b) 432 | return nil 433 | } 434 | return badtype("boolean", data) 435 | } 436 | 437 | func (md *MetaData) unifyAnything(data interface{}, rv reflect.Value) error { 438 | rv.Set(reflect.ValueOf(data)) 439 | return nil 440 | } 441 | 442 | func (md *MetaData) unifyText(data interface{}, v TextUnmarshaler) error { 443 | var s string 444 | switch sdata := data.(type) { 445 | case TextMarshaler: 446 | text, err := sdata.MarshalText() 447 | if err != nil { 448 | return err 449 | } 450 | s = string(text) 451 | case fmt.Stringer: 452 | s = sdata.String() 453 | case string: 454 | s = sdata 455 | case bool: 456 | s = fmt.Sprintf("%v", sdata) 457 | case int64: 458 | s = fmt.Sprintf("%d", sdata) 459 | case float64: 460 | s = fmt.Sprintf("%f", sdata) 461 | default: 462 | return badtype("primitive (string-like)", data) 463 | } 464 | if err := v.UnmarshalText([]byte(s)); err != nil { 465 | return err 466 | } 467 | return nil 468 | } 469 | 470 | // rvalue returns a reflect.Value of `v`. All pointers are resolved. 471 | func rvalue(v interface{}) reflect.Value { 472 | return indirect(reflect.ValueOf(v)) 473 | } 474 | 475 | // indirect returns the value pointed to by a pointer. 476 | // Pointers are followed until the value is not a pointer. 477 | // New values are allocated for each nil pointer. 478 | // 479 | // An exception to this rule is if the value satisfies an interface of 480 | // interest to us (like encoding.TextUnmarshaler). 481 | func indirect(v reflect.Value) reflect.Value { 482 | if v.Kind() != reflect.Ptr { 483 | if v.CanSet() { 484 | pv := v.Addr() 485 | if _, ok := pv.Interface().(TextUnmarshaler); ok { 486 | return pv 487 | } 488 | } 489 | return v 490 | } 491 | if v.IsNil() { 492 | v.Set(reflect.New(v.Type().Elem())) 493 | } 494 | return indirect(reflect.Indirect(v)) 495 | } 496 | 497 | func isUnifiable(rv reflect.Value) bool { 498 | if rv.CanSet() { 499 | return true 500 | } 501 | if _, ok := rv.Interface().(TextUnmarshaler); ok { 502 | return true 503 | } 504 | return false 505 | } 506 | 507 | func badtype(expected string, data interface{}) error { 508 | return e("cannot load TOML value of type %T into a Go %s", data, expected) 509 | } 510 | --------------------------------------------------------------------------------