From 2330935b90e1e2d98a141b68a969c97eb501d17e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=B2=B3?= Date: Mon, 8 Apr 2019 18:23:12 +0800 Subject: [PATCH] Vender add --- vender/github.com/ccding/go-stun/.gitignore | 25 +++ vender/github.com/ccding/go-stun/LICENSE | 191 ++++++++++++++++++ .../ccding/go-stun/linter_config.json | 27 +++ vender/github.com/ccding/go-stun/main.go | 56 +++++ .../ccding/go-stun/stun/attribute.go | 106 ++++++++++ .../github.com/ccding/go-stun/stun/client.go | 126 ++++++++++++ .../github.com/ccding/go-stun/stun/const.go | 178 ++++++++++++++++ .../ccding/go-stun/stun/discover.go | 168 +++++++++++++++ vender/github.com/ccding/go-stun/stun/doc.go | 25 +++ vender/github.com/ccding/go-stun/stun/host.go | 70 +++++++ vender/github.com/ccding/go-stun/stun/log.go | 87 ++++++++ vender/github.com/ccding/go-stun/stun/net.go | 106 ++++++++++ .../github.com/ccding/go-stun/stun/packet.go | 129 ++++++++++++ .../ccding/go-stun/stun/packet_test.go | 61 ++++++ .../ccding/go-stun/stun/response.go | 78 +++++++ .../github.com/ccding/go-stun/stun/tests.go | 33 +++ .../github.com/ccding/go-stun/stun/utils.go | 63 ++++++ .../ccding/go-stun/stun/utils_test.go | 69 +++++++ 18 files changed, 1598 insertions(+) create mode 100755 vender/github.com/ccding/go-stun/.gitignore create mode 100755 vender/github.com/ccding/go-stun/LICENSE create mode 100755 vender/github.com/ccding/go-stun/linter_config.json create mode 100755 vender/github.com/ccding/go-stun/main.go create mode 100755 vender/github.com/ccding/go-stun/stun/attribute.go create mode 100755 vender/github.com/ccding/go-stun/stun/client.go create mode 100755 vender/github.com/ccding/go-stun/stun/const.go create mode 100755 vender/github.com/ccding/go-stun/stun/discover.go create mode 100755 vender/github.com/ccding/go-stun/stun/doc.go create mode 100755 vender/github.com/ccding/go-stun/stun/host.go create mode 100755 vender/github.com/ccding/go-stun/stun/log.go create mode 100755 vender/github.com/ccding/go-stun/stun/net.go create mode 100755 vender/github.com/ccding/go-stun/stun/packet.go create mode 100755 vender/github.com/ccding/go-stun/stun/packet_test.go create mode 100755 vender/github.com/ccding/go-stun/stun/response.go create mode 100755 vender/github.com/ccding/go-stun/stun/tests.go create mode 100755 vender/github.com/ccding/go-stun/stun/utils.go create mode 100755 vender/github.com/ccding/go-stun/stun/utils_test.go diff --git a/vender/github.com/ccding/go-stun/.gitignore b/vender/github.com/ccding/go-stun/.gitignore new file mode 100755 index 00000000..a1b4a2ec --- /dev/null +++ b/vender/github.com/ccding/go-stun/.gitignore @@ -0,0 +1,25 @@ +# Temporary files for running example +go-stun + +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe diff --git a/vender/github.com/ccding/go-stun/LICENSE b/vender/github.com/ccding/go-stun/LICENSE new file mode 100755 index 00000000..37ec93a1 --- /dev/null +++ b/vender/github.com/ccding/go-stun/LICENSE @@ -0,0 +1,191 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "[]" replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same "printed page" as the copyright notice for easier identification within +third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vender/github.com/ccding/go-stun/linter_config.json b/vender/github.com/ccding/go-stun/linter_config.json new file mode 100755 index 00000000..3f88246b --- /dev/null +++ b/vender/github.com/ccding/go-stun/linter_config.json @@ -0,0 +1,27 @@ +{ + "Vendor": true, + "DisableAll": true, + "Enable": [ + "vet", + "safesql", + "errcheck", + "goconst", + "goimports", + "varcheck", + "gas", + "staticcheck", + "gosimple", + "lll", + "unconvert", + "misspell", + "unconvert" + ], + "Aggregate": true, + "WarnUnmatchedNolint": true, + "LineLength": 240, + "Exclude": [ + "stun/const.go" + ], + "Deadline": "300s", + "Skip": [] +} diff --git a/vender/github.com/ccding/go-stun/main.go b/vender/github.com/ccding/go-stun/main.go new file mode 100755 index 00000000..925f7d20 --- /dev/null +++ b/vender/github.com/ccding/go-stun/main.go @@ -0,0 +1,56 @@ +// Copyright 2013, Cong Ding. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// author: Cong Ding + +package main + +import ( + "flag" + "fmt" + + "github.com/ccding/go-stun/stun" +) + +func main() { + var serverAddr = flag.String("s", stun.DefaultServerAddr, "STUN server address") + var v = flag.Bool("v", false, "verbose mode") + var vv = flag.Bool("vv", false, "double verbose mode (includes -v)") + var vvv = flag.Bool("vvv", false, "triple verbose mode (includes -v and -vv)") + flag.Parse() + + // Creates a STUN client. NewClientWithConnection can also be used if + // you want to handle the UDP listener by yourself. + client := stun.NewClient() + // The default addr (stun.DefaultServerAddr) will be used unless we + // call SetServerAddr. + client.SetServerAddr(*serverAddr) + // Non verbose mode will be used by default unless we call + // SetVerbose(true) or SetVVerbose(true). + client.SetVerbose(*v || *vv || *vvv) + client.SetVVerbose(*vv || *vvv) + // Discover the NAT and return the result. + nat, host, err := client.Discover() + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("NAT Type:", nat) + if host != nil { + fmt.Println("External IP Family:", host.Family()) + fmt.Println("External IP:", host.IP()) + fmt.Println("External Port:", host.Port()) + } +} diff --git a/vender/github.com/ccding/go-stun/stun/attribute.go b/vender/github.com/ccding/go-stun/stun/attribute.go new file mode 100755 index 00000000..61732a91 --- /dev/null +++ b/vender/github.com/ccding/go-stun/stun/attribute.go @@ -0,0 +1,106 @@ +// Copyright 2013, Cong Ding. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Cong Ding + +package stun + +import ( + "encoding/binary" + "hash/crc32" + "net" +) + +type attribute struct { + types uint16 + length uint16 + value []byte +} + +func newAttribute(types uint16, value []byte) *attribute { + att := new(attribute) + att.types = types + att.value = padding(value) + att.length = uint16(len(att.value)) + return att +} + +func newFingerprintAttribute(packet *packet) *attribute { + crc := crc32.ChecksumIEEE(packet.bytes()) ^ fingerprint + buf := make([]byte, 4) + binary.BigEndian.PutUint32(buf, crc) + return newAttribute(attributeFingerprint, buf) +} + +func newSoftwareAttribute(name string) *attribute { + return newAttribute(attributeSoftware, []byte(name)) +} + +func newChangeReqAttribute(changeIP bool, changePort bool) *attribute { + value := make([]byte, 4) + if changeIP { + value[3] |= 0x04 + } + if changePort { + value[3] |= 0x02 + } + return newAttribute(attributeChangeRequest, value) +} + +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |x x x x x x x x| Family | X-Port | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | X-Address (Variable) +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// Figure 6: Format of XOR-MAPPED-ADDRESS Attribute +func (v *attribute) xorAddr(transID []byte) *Host { + xorIP := make([]byte, 16) + for i := 0; i < len(v.value)-4; i++ { + xorIP[i] = v.value[i+4] ^ transID[i] + } + family := uint16(v.value[1]) + port := binary.BigEndian.Uint16(v.value[2:4]) + // Truncate if IPv4, otherwise net.IP sometimes renders it as an IPv6 address. + if family == attributeFamilyIPv4 { + xorIP = xorIP[:4] + } + x := binary.BigEndian.Uint16(transID[:2]) + return &Host{family, net.IP(xorIP).String(), port ^ x} +} + +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |0 0 0 0 0 0 0 0| Family | Port | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | | +// | Address (32 bits or 128 bits) | +// | | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// Figure 5: Format of MAPPED-ADDRESS Attribute +func (v *attribute) rawAddr() *Host { + host := new(Host) + host.family = uint16(v.value[1]) + host.port = binary.BigEndian.Uint16(v.value[2:4]) + // Truncate if IPv4, otherwise net.IP sometimes renders it as an IPv6 address. + if host.family == attributeFamilyIPv4 { + v.value = v.value[:8] + } + host.ip = net.IP(v.value[4:]).String() + return host +} diff --git a/vender/github.com/ccding/go-stun/stun/client.go b/vender/github.com/ccding/go-stun/stun/client.go new file mode 100755 index 00000000..89be7046 --- /dev/null +++ b/vender/github.com/ccding/go-stun/stun/client.go @@ -0,0 +1,126 @@ +// Copyright 2013, Cong Ding. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Cong Ding + +package stun + +import ( + "errors" + "net" + "strconv" +) + +// Client is a STUN client, which can be set STUN server address and is used +// to discover NAT type. +type Client struct { + serverAddr string + softwareName string + conn net.PacketConn + logger *Logger +} + +// NewClient returns a client without network connection. The network +// connection will be build when calling Discover function. +func NewClient() *Client { + c := new(Client) + c.SetSoftwareName(DefaultSoftwareName) + c.logger = NewLogger() + return c +} + +// NewClientWithConnection returns a client which uses the given connection. +// Please note the connection should be acquired via net.Listen* method. +func NewClientWithConnection(conn net.PacketConn) *Client { + c := new(Client) + c.conn = conn + c.SetSoftwareName(DefaultSoftwareName) + c.logger = NewLogger() + return c +} + +// SetVerbose sets the client to be in the verbose mode, which prints +// information in the discover process. +func (c *Client) SetVerbose(v bool) { + c.logger.SetDebug(v) +} + +// SetVVerbose sets the client to be in the double verbose mode, which prints +// information and packet in the discover process. +func (c *Client) SetVVerbose(v bool) { + c.logger.SetInfo(v) +} + +// SetServerHost allows user to set the STUN hostname and port. +func (c *Client) SetServerHost(host string, port int) { + c.serverAddr = net.JoinHostPort(host, strconv.Itoa(port)) +} + +// SetServerAddr allows user to set the transport layer STUN server address. +func (c *Client) SetServerAddr(address string) { + c.serverAddr = address +} + +// SetSoftwareName allows user to set the name of the software, which is used +// for logging purpose (NOT used in the current implementation). +func (c *Client) SetSoftwareName(name string) { + c.softwareName = name +} + +// Discover contacts the STUN server and gets the response of NAT type, host +// for UDP punching. +func (c *Client) Discover() (NATType, *Host, error) { + if c.serverAddr == "" { + c.SetServerAddr(DefaultServerAddr) + } + serverUDPAddr, err := net.ResolveUDPAddr("udp", c.serverAddr) + if err != nil { + return NATError, nil, err + } + // Use the connection passed to the client if it is not nil, otherwise + // create a connection and close it at the end. + conn := c.conn + if conn == nil { + conn, err = net.ListenUDP("udp", nil) + if err != nil { + return NATError, nil, err + } + defer conn.Close() + } + return c.discover(conn, serverUDPAddr) +} + +// Keepalive sends and receives a bind request, which ensures the mapping stays open +// Only applicable when client was created with a connection. +func (c *Client) Keepalive() (*Host, error) { + if c.conn == nil { + return nil, errors.New("no connection available") + } + if c.serverAddr == "" { + c.SetServerAddr(DefaultServerAddr) + } + serverUDPAddr, err := net.ResolveUDPAddr("udp", c.serverAddr) + if err != nil { + return nil, err + } + + resp, err := c.test1(c.conn, serverUDPAddr) + if err != nil { + return nil, err + } + if resp == nil || resp.packet == nil { + return nil, errors.New("failed to contact") + } + return resp.mappedAddr, nil +} diff --git a/vender/github.com/ccding/go-stun/stun/const.go b/vender/github.com/ccding/go-stun/stun/const.go new file mode 100755 index 00000000..3980e8a6 --- /dev/null +++ b/vender/github.com/ccding/go-stun/stun/const.go @@ -0,0 +1,178 @@ +// Copyright 2013, Cong Ding. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Cong Ding + +package stun + +// Default server address and client name. +const ( + DefaultServerAddr = "stun.voiparound.com:3478" + DefaultSoftwareName = "StunClient" +) + +const ( + magicCookie = 0x2112A442 + fingerprint = 0x5354554e +) + +// NATType is the type of NAT described by int. +type NATType int + +// NAT types. +const ( + NATError NATType = iota + NATUnknown + NATNone + NATBlocked + NATFull + NATSymmetric + NATRestricted + NATPortRestricted + NATSymmetricUDPFirewall + + // Deprecated spellings of these constants + NATSymetric = NATSymmetric + NATSymetricUDPFirewall = NATSymmetricUDPFirewall +) + +var natStr map[NATType]string + +func init() { + natStr = map[NATType]string{ + NATError: "Test failed", + NATUnknown: "Unexpected response from the STUN server", + NATBlocked: "UDP is blocked", + NATFull: "Full cone NAT", + NATSymmetric: "Symmetric NAT", + NATRestricted: "Restricted NAT", + NATPortRestricted: "Port restricted NAT", + NATNone: "Not behind a NAT", + NATSymmetricUDPFirewall: "Symmetric UDP firewall", + } +} + +func (nat NATType) String() string { + if s, ok := natStr[nat]; ok { + return s + } + return "Unknown" +} + +const ( + errorTryAlternate = 300 + errorBadRequest = 400 + errorUnauthorized = 401 + errorUnassigned402 = 402 + errorForbidden = 403 + errorUnknownAttribute = 420 + errorAllocationMismatch = 437 + errorStaleNonce = 438 + errorUnassigned439 = 439 + errorAddressFamilyNotSupported = 440 + errorWrongCredentials = 441 + errorUnsupportedTransportProtocol = 442 + errorPeerAddressFamilyMismatch = 443 + errorConnectionAlreadyExists = 446 + errorConnectionTimeoutOrFailure = 447 + errorAllocationQuotaReached = 486 + errorRoleConflict = 487 + errorServerError = 500 + errorInsufficientCapacity = 508 +) +const ( + attributeFamilyIPv4 = 0x01 + attributeFamilyIPV6 = 0x02 +) + +const ( + attributeMappedAddress = 0x0001 + attributeResponseAddress = 0x0002 + attributeChangeRequest = 0x0003 + attributeSourceAddress = 0x0004 + attributeChangedAddress = 0x0005 + attributeUsername = 0x0006 + attributePassword = 0x0007 + attributeMessageIntegrity = 0x0008 + attributeErrorCode = 0x0009 + attributeUnknownAttributes = 0x000a + attributeReflectedFrom = 0x000b + attributeChannelNumber = 0x000c + attributeLifetime = 0x000d + attributeBandwidth = 0x0010 + attributeXorPeerAddress = 0x0012 + attributeData = 0x0013 + attributeRealm = 0x0014 + attributeNonce = 0x0015 + attributeXorRelayedAddress = 0x0016 + attributeRequestedAddressFamily = 0x0017 + attributeEvenPort = 0x0018 + attributeRequestedTransport = 0x0019 + attributeDontFragment = 0x001a + attributeXorMappedAddress = 0x0020 + attributeTimerVal = 0x0021 + attributeReservationToken = 0x0022 + attributePriority = 0x0024 + attributeUseCandidate = 0x0025 + attributePadding = 0x0026 + attributeResponsePort = 0x0027 + attributeConnectionID = 0x002a + attributeXorMappedAddressExp = 0x8020 + attributeSoftware = 0x8022 + attributeAlternateServer = 0x8023 + attributeCacheTimeout = 0x8027 + attributeFingerprint = 0x8028 + attributeIceControlled = 0x8029 + attributeIceControlling = 0x802a + attributeResponseOrigin = 0x802b + attributeOtherAddress = 0x802c + attributeEcnCheckStun = 0x802d + attributeCiscoFlowdata = 0xc000 +) + +const ( + typeBindingRequest = 0x0001 + typeBindingResponse = 0x0101 + typeBindingErrorResponse = 0x0111 + typeSharedSecretRequest = 0x0002 + typeSharedSecretResponse = 0x0102 + typeSharedErrorResponse = 0x0112 + typeAllocate = 0x0003 + typeAllocateResponse = 0x0103 + typeAllocateErrorResponse = 0x0113 + typeRefresh = 0x0004 + typeRefreshResponse = 0x0104 + typeRefreshErrorResponse = 0x0114 + typeSend = 0x0006 + typeSendResponse = 0x0106 + typeSendErrorResponse = 0x0116 + typeData = 0x0007 + typeDataResponse = 0x0107 + typeDataErrorResponse = 0x0117 + typeCreatePermisiion = 0x0008 + typeCreatePermisiionResponse = 0x0108 + typeCreatePermisiionErrorResponse = 0x0118 + typeChannelBinding = 0x0009 + typeChannelBindingResponse = 0x0109 + typeChannelBindingErrorResponse = 0x0119 + typeConnect = 0x000a + typeConnectResponse = 0x010a + typeConnectErrorResponse = 0x011a + typeConnectionBind = 0x000b + typeConnectionBindResponse = 0x010b + typeConnectionBindErrorResponse = 0x011b + typeConnectionAttempt = 0x000c + typeConnectionAttemptResponse = 0x010c + typeConnectionAttemptErrorResponse = 0x011c +) diff --git a/vender/github.com/ccding/go-stun/stun/discover.go b/vender/github.com/ccding/go-stun/stun/discover.go new file mode 100755 index 00000000..f60d2c58 --- /dev/null +++ b/vender/github.com/ccding/go-stun/stun/discover.go @@ -0,0 +1,168 @@ +// Copyright 2013, Cong Ding. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Cong Ding + +package stun + +import ( + "errors" + "net" +) + +// Follow RFC 3489 and RFC 5389. +// Figure 2: Flow for type discovery process (from RFC 3489). +// +--------+ +// | Test | +// | I | +// +--------+ +// | +// | +// V +// /\ /\ +// N / \ Y / \ Y +--------+ +// UDP <-------/Resp\--------->/ IP \------------->| Test | +// Blocked \ ? / \Same/ | II | +// \ / \? / +--------+ +// \/ \/ | +// | N | +// | V +// V /\ +// +--------+ Sym. N / \ +// | Test | UDP <---/Resp\ +// | II | Firewall \ ? / +// +--------+ \ / +// | \/ +// V |Y +// /\ /\ | +// Symmetric N / \ +--------+ N / \ V +// NAT <--- / IP \<-----| Test |<--- /Resp\ Open +// \Same/ | I | \ ? / Internet +// \? / +--------+ \ / +// \/ \/ +// |Y |Y +// | | +// | V +// | Full +// | Cone +// V /\ +// +--------+ / \ Y +// | Test |------>/Resp\---->Restricted +// | III | \ ? / +// +--------+ \ / +// \/ +// |N +// | Port +// +------>Restricted +func (c *Client) discover(conn net.PacketConn, addr *net.UDPAddr) (NATType, *Host, error) { + // Perform test1 to check if it is under NAT. + c.logger.Debugln("Do Test1") + c.logger.Debugln("Send To:", addr) + resp, err := c.test1(conn, addr) + if err != nil { + return NATError, nil, err + } + c.logger.Debugln("Received:", resp) + if resp == nil { + return NATBlocked, nil, nil + } + // identical used to check if it is open Internet or not. + identical := resp.identical + // changedAddr is used to perform second time test1 and test3. + changedAddr := resp.changedAddr + // mappedAddr is used as the return value, its IP is used for tests + mappedAddr := resp.mappedAddr + // Make sure IP and port are not changed. + if resp.serverAddr.IP() != addr.IP.String() || + resp.serverAddr.Port() != uint16(addr.Port) { + return NATError, mappedAddr, errors.New("Server error: response IP/port") + } + // if changedAddr is not available, use otherAddr as changedAddr, + // which is updated in RFC 5780 + if changedAddr == nil { + changedAddr = resp.otherAddr + } + // changedAddr shall not be nil + if changedAddr == nil { + return NATError, mappedAddr, errors.New("Server error: no changed address.") + } + // Perform test2 to see if the client can receive packet sent from + // another IP and port. + c.logger.Debugln("Do Test2") + c.logger.Debugln("Send To:", addr) + resp, err = c.test2(conn, addr) + if err != nil { + return NATError, mappedAddr, err + } + c.logger.Debugln("Received:", resp) + // Make sure IP and port are changed. + if resp != nil && + (resp.serverAddr.IP() == addr.IP.String() || + resp.serverAddr.Port() == uint16(addr.Port)) { + return NATError, mappedAddr, errors.New("Server error: response IP/port") + } + if identical { + if resp == nil { + return NATSymmetricUDPFirewall, mappedAddr, nil + } + return NATNone, mappedAddr, nil + } + if resp != nil { + return NATFull, mappedAddr, nil + } + // Perform test1 to another IP and port to see if the NAT use the same + // external IP. + c.logger.Debugln("Do Test1") + c.logger.Debugln("Send To:", changedAddr) + caddr, err := net.ResolveUDPAddr("udp", changedAddr.String()) + if err != nil { + c.logger.Debugf("ResolveUDPAddr error: %v", err) + } + resp, err = c.test1(conn, caddr) + if err != nil { + return NATError, mappedAddr, err + } + c.logger.Debugln("Received:", resp) + if resp == nil { + // It should be NAT_BLOCKED, but will be detected in the first + // step. So this will never happen. + return NATUnknown, mappedAddr, nil + } + // Make sure IP/port is not changed. + if resp.serverAddr.IP() != caddr.IP.String() || + resp.serverAddr.Port() != uint16(caddr.Port) { + return NATError, mappedAddr, errors.New("Server error: response IP/port") + } + if mappedAddr.IP() == resp.mappedAddr.IP() && mappedAddr.Port() == resp.mappedAddr.Port() { + // Perform test3 to see if the client can receive packet sent + // from another port. + c.logger.Debugln("Do Test3") + c.logger.Debugln("Send To:", caddr) + resp, err = c.test3(conn, caddr) + if err != nil { + return NATError, mappedAddr, err + } + c.logger.Debugln("Received:", resp) + if resp == nil { + return NATPortRestricted, mappedAddr, nil + } + // Make sure IP is not changed, and port is changed. + if resp.serverAddr.IP() != caddr.IP.String() || + resp.serverAddr.Port() == uint16(caddr.Port) { + return NATError, mappedAddr, errors.New("Server error: response IP/port") + } + return NATRestricted, mappedAddr, nil + } + return NATSymmetric, mappedAddr, nil +} diff --git a/vender/github.com/ccding/go-stun/stun/doc.go b/vender/github.com/ccding/go-stun/stun/doc.go new file mode 100755 index 00000000..d1c9aba1 --- /dev/null +++ b/vender/github.com/ccding/go-stun/stun/doc.go @@ -0,0 +1,25 @@ +// Copyright 2013, Cong Ding. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Cong Ding + +// Package stun is a STUN (RFC 3489 and RFC 5389) client implementation in +// golang. +// +// It is extremely easy to use -- just one line of code. +// +// nat, host, err := stun.NewClient().Discover() +// +// More details please go to `main.go`. +package stun diff --git a/vender/github.com/ccding/go-stun/stun/host.go b/vender/github.com/ccding/go-stun/stun/host.go new file mode 100755 index 00000000..cee1e9d1 --- /dev/null +++ b/vender/github.com/ccding/go-stun/stun/host.go @@ -0,0 +1,70 @@ +// Copyright 2013, Cong Ding. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Cong Ding + +package stun + +import ( + "net" + "strconv" +) + +// Host defines the network address including address family, IP address and port. +type Host struct { + family uint16 + ip string + port uint16 +} + +func newHostFromStr(s string) *Host { + udpAddr, err := net.ResolveUDPAddr("udp", s) + if err != nil { + return nil + } + host := new(Host) + if udpAddr.IP.To4() != nil { + host.family = attributeFamilyIPv4 + } else { + host.family = attributeFamilyIPV6 + } + host.ip = udpAddr.IP.String() + host.port = uint16(udpAddr.Port) + return host +} + +// Family returns the family type of a host (IPv4 or IPv6). +func (h *Host) Family() uint16 { + return h.family +} + +// IP returns the internet protocol address of the host. +func (h *Host) IP() string { + return h.ip +} + +// Port returns the port number of the host. +func (h *Host) Port() uint16 { + return h.port +} + +// TransportAddr returns the transport layer address of the host. +func (h *Host) TransportAddr() string { + return net.JoinHostPort(h.ip, strconv.Itoa(int(h.port))) +} + +// String returns the string representation of the host address. +func (h *Host) String() string { + return h.TransportAddr() +} diff --git a/vender/github.com/ccding/go-stun/stun/log.go b/vender/github.com/ccding/go-stun/stun/log.go new file mode 100755 index 00000000..52f9fd2b --- /dev/null +++ b/vender/github.com/ccding/go-stun/stun/log.go @@ -0,0 +1,87 @@ +// Copyright 2016, Cong Ding. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Cong Ding + +package stun + +import ( + "log" + "os" +) + +// Logger is a simple logger specified for this STUN client. +type Logger struct { + log.Logger + debug bool + info bool +} + +// NewLogger creates a default logger. +func NewLogger() *Logger { + logger := &Logger{*log.New(os.Stdout, "", log.LstdFlags), false, false} + return logger +} + +// SetDebug sets the logger running in debug mode or not. +func (l *Logger) SetDebug(v bool) { + l.debug = v +} + +// SetInfo sets the logger running in info mode or not. +func (l *Logger) SetInfo(v bool) { + l.info = v +} + +// Debug outputs the log in the format of log.Print. +func (l *Logger) Debug(v ...interface{}) { + if l.debug { + l.Print(v...) + } +} + +// Debugf outputs the log in the format of log.Printf. +func (l *Logger) Debugf(format string, v ...interface{}) { + if l.debug { + l.Printf(format, v...) + } +} + +// Debugln outputs the log in the format of log.Println. +func (l *Logger) Debugln(v ...interface{}) { + if l.debug { + l.Println(v...) + } +} + +// Info outputs the log in the format of log.Print. +func (l *Logger) Info(v ...interface{}) { + if l.info { + l.Print(v...) + } +} + +// Infof outputs the log in the format of log.Printf. +func (l *Logger) Infof(format string, v ...interface{}) { + if l.info { + l.Printf(format, v...) + } +} + +// Infoln outputs the log in the format of log.Println. +func (l *Logger) Infoln(v ...interface{}) { + if l.info { + l.Println(v...) + } +} diff --git a/vender/github.com/ccding/go-stun/stun/net.go b/vender/github.com/ccding/go-stun/stun/net.go new file mode 100755 index 00000000..f067f3e3 --- /dev/null +++ b/vender/github.com/ccding/go-stun/stun/net.go @@ -0,0 +1,106 @@ +// Copyright 2016, Cong Ding. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Cong Ding + +package stun + +import ( + "bytes" + "encoding/hex" + "errors" + "net" + "time" +) + +const ( + numRetransmit = 9 + defaultTimeout = 100 + maxTimeout = 1600 + maxPacketSize = 1024 +) + +func (c *Client) sendBindingReq(conn net.PacketConn, addr net.Addr, changeIP bool, changePort bool) (*response, error) { + // Construct packet. + pkt, err := newPacket() + if err != nil { + return nil, err + } + pkt.types = typeBindingRequest + attribute := newSoftwareAttribute(c.softwareName) + pkt.addAttribute(*attribute) + if changeIP || changePort { + attribute = newChangeReqAttribute(changeIP, changePort) + pkt.addAttribute(*attribute) + } + // length of fingerprint attribute must be included into crc, + // so we add it before calculating crc, then subtract it after calculating crc. + pkt.length += 8 + attribute = newFingerprintAttribute(pkt) + pkt.length -= 8 + pkt.addAttribute(*attribute) + // Send packet. + return c.send(pkt, conn, addr) +} + +// RFC 3489: Clients SHOULD retransmit the request starting with an interval +// of 100ms, doubling every retransmit until the interval reaches 1.6s. +// Retransmissions continue with intervals of 1.6s until a response is +// received, or a total of 9 requests have been sent. +func (c *Client) send(pkt *packet, conn net.PacketConn, addr net.Addr) (*response, error) { + c.logger.Info("\n" + hex.Dump(pkt.bytes())) + timeout := defaultTimeout + packetBytes := make([]byte, maxPacketSize) + for i := 0; i < numRetransmit; i++ { + // Send packet to the server. + length, err := conn.WriteTo(pkt.bytes(), addr) + if err != nil { + return nil, err + } + if length != len(pkt.bytes()) { + return nil, errors.New("Error in sending data.") + } + err = conn.SetReadDeadline(time.Now().Add(time.Duration(timeout) * time.Millisecond)) + if err != nil { + return nil, err + } + if timeout < maxTimeout { + timeout *= 2 + } + for { + // Read from the port. + length, raddr, err := conn.ReadFrom(packetBytes) + if err != nil { + if nerr, ok := err.(net.Error); ok && nerr.Timeout() { + break + } + return nil, err + } + p, err := newPacketFromBytes(packetBytes[0:length]) + if err != nil { + return nil, err + } + // If transId mismatches, keep reading until get a + // matched packet or timeout. + if !bytes.Equal(pkt.transID, p.transID) { + continue + } + c.logger.Info("\n" + hex.Dump(packetBytes[0:length])) + resp := newResponse(p, conn) + resp.serverAddr = newHostFromStr(raddr.String()) + return resp, err + } + } + return nil, nil +} diff --git a/vender/github.com/ccding/go-stun/stun/packet.go b/vender/github.com/ccding/go-stun/stun/packet.go new file mode 100755 index 00000000..ca569004 --- /dev/null +++ b/vender/github.com/ccding/go-stun/stun/packet.go @@ -0,0 +1,129 @@ +// Copyright 2013, Cong Ding. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Cong Ding + +package stun + +import ( + "crypto/rand" + "encoding/binary" + "errors" +) + +type packet struct { + types uint16 + length uint16 + transID []byte // 4 bytes magic cookie + 12 bytes transaction id + attributes []attribute +} + +func newPacket() (*packet, error) { + v := new(packet) + v.transID = make([]byte, 16) + binary.BigEndian.PutUint32(v.transID[:4], magicCookie) + _, err := rand.Read(v.transID[4:]) + if err != nil { + return nil, err + } + v.attributes = make([]attribute, 0, 10) + v.length = 0 + return v, nil +} + +func newPacketFromBytes(packetBytes []byte) (*packet, error) { + if len(packetBytes) < 24 { + return nil, errors.New("Received data length too short.") + } + pkt := new(packet) + pkt.types = binary.BigEndian.Uint16(packetBytes[0:2]) + pkt.length = binary.BigEndian.Uint16(packetBytes[2:4]) + pkt.transID = packetBytes[4:20] + pkt.attributes = make([]attribute, 0, 10) + for pos := uint16(20); pos < uint16(len(packetBytes)); { + types := binary.BigEndian.Uint16(packetBytes[pos : pos+2]) + length := binary.BigEndian.Uint16(packetBytes[pos+2 : pos+4]) + if pos+4+length > uint16(len(packetBytes)) { + return nil, errors.New("Received data format mismatch.") + } + value := packetBytes[pos+4 : pos+4+length] + attribute := newAttribute(types, value) + pkt.addAttribute(*attribute) + pos += align(length) + 4 + } + return pkt, nil +} + +func (v *packet) addAttribute(a attribute) { + v.attributes = append(v.attributes, a) + v.length += align(a.length) + 4 +} + +func (v *packet) bytes() []byte { + packetBytes := make([]byte, 4) + binary.BigEndian.PutUint16(packetBytes[0:2], v.types) + binary.BigEndian.PutUint16(packetBytes[2:4], v.length) + packetBytes = append(packetBytes, v.transID...) + for _, a := range v.attributes { + buf := make([]byte, 2) + binary.BigEndian.PutUint16(buf, a.types) + packetBytes = append(packetBytes, buf...) + binary.BigEndian.PutUint16(buf, a.length) + packetBytes = append(packetBytes, buf...) + packetBytes = append(packetBytes, a.value...) + } + return packetBytes +} + +func (v *packet) getSourceAddr() *Host { + return v.getRawAddr(attributeSourceAddress) +} + +func (v *packet) getMappedAddr() *Host { + return v.getRawAddr(attributeMappedAddress) +} + +func (v *packet) getChangedAddr() *Host { + return v.getRawAddr(attributeChangedAddress) +} + +func (v *packet) getOtherAddr() *Host { + return v.getRawAddr(attributeOtherAddress) +} + +func (v *packet) getRawAddr(attribute uint16) *Host { + for _, a := range v.attributes { + if a.types == attribute { + return a.rawAddr() + } + } + return nil +} + +func (v *packet) getXorMappedAddr() *Host { + addr := v.getXorAddr(attributeXorMappedAddress) + if addr == nil { + addr = v.getXorAddr(attributeXorMappedAddressExp) + } + return addr +} + +func (v *packet) getXorAddr(attribute uint16) *Host { + for _, a := range v.attributes { + if a.types == attribute { + return a.xorAddr(v.transID) + } + } + return nil +} diff --git a/vender/github.com/ccding/go-stun/stun/packet_test.go b/vender/github.com/ccding/go-stun/stun/packet_test.go new file mode 100755 index 00000000..a061e8ba --- /dev/null +++ b/vender/github.com/ccding/go-stun/stun/packet_test.go @@ -0,0 +1,61 @@ +// Copyright 2016, Cong Ding. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Cong Ding + +package stun + +import ( + "testing" +) + +func TestNewPacketFromBytes(t *testing.T) { + b := make([]byte, 23) + _, err := newPacketFromBytes(b) + if err == nil { + t.Errorf("newPacketFromBytes error") + } + b = make([]byte, 24) + _, err = newPacketFromBytes(b) + if err != nil { + t.Errorf("newPacketFromBytes error") + } +} + +func TestNewPacket(t *testing.T) { + _, err := newPacket() + if err != nil { + t.Errorf("newPacket error") + } +} + +func TestPacketAll(t *testing.T) { + p, err := newPacket() + if err != nil { + t.Errorf("newPacket error") + } + p.addAttribute(*newChangeReqAttribute(true, true)) + p.addAttribute(*newSoftwareAttribute("aaa")) + p.addAttribute(*newFingerprintAttribute(p)) + pkt, err := newPacketFromBytes(p.bytes()) + if err != nil { + t.Errorf("newPacketFromBytes error") + } + if pkt.types != 0 { + t.Errorf("newPacketFromBytes error") + } + if pkt.length < 24 { + t.Errorf("newPacketFromBytes error") + } +} diff --git a/vender/github.com/ccding/go-stun/stun/response.go b/vender/github.com/ccding/go-stun/stun/response.go new file mode 100755 index 00000000..c9a75cb4 --- /dev/null +++ b/vender/github.com/ccding/go-stun/stun/response.go @@ -0,0 +1,78 @@ +// Copyright 2016, Cong Ding. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Cong Ding + +package stun + +import ( + "fmt" + "net" +) + +type response struct { + packet *packet // the original packet from the server + serverAddr *Host // the address received packet + changedAddr *Host // parsed from packet + mappedAddr *Host // parsed from packet, external addr of client NAT + otherAddr *Host // parsed from packet, to replace changedAddr in RFC 5780 + identical bool // if mappedAddr is in local addr list +} + +func newResponse(pkt *packet, conn net.PacketConn) *response { + resp := &response{pkt, nil, nil, nil, nil, false} + if pkt == nil { + return resp + } + // RFC 3489 doesn't require the server return XOR mapped address. + mappedAddr := pkt.getXorMappedAddr() + if mappedAddr == nil { + mappedAddr = pkt.getMappedAddr() + } + resp.mappedAddr = mappedAddr + // compute identical + localAddrStr := conn.LocalAddr().String() + if mappedAddr != nil { + mappedAddrStr := mappedAddr.String() + resp.identical = isLocalAddress(localAddrStr, mappedAddrStr) + } + // compute changedAddr + changedAddr := pkt.getChangedAddr() + if changedAddr != nil { + changedAddrHost := newHostFromStr(changedAddr.String()) + resp.changedAddr = changedAddrHost + } + // compute otherAddr + otherAddr := pkt.getOtherAddr() + if otherAddr != nil { + otherAddrHost := newHostFromStr(otherAddr.String()) + resp.otherAddr = otherAddrHost + } + + return resp +} + +// String is only used for verbose mode output. +func (r *response) String() string { + if r == nil { + return "Nil" + } + return fmt.Sprintf("{packet nil: %v, local: %v, remote: %v, changed: %v, other: %v, identical: %v}", + r.packet == nil, + r.mappedAddr, + r.serverAddr, + r.changedAddr, + r.otherAddr, + r.identical) +} diff --git a/vender/github.com/ccding/go-stun/stun/tests.go b/vender/github.com/ccding/go-stun/stun/tests.go new file mode 100755 index 00000000..013c803e --- /dev/null +++ b/vender/github.com/ccding/go-stun/stun/tests.go @@ -0,0 +1,33 @@ +// Copyright 2016, Cong Ding. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Cong Ding + +package stun + +import ( + "net" +) + +func (c *Client) test1(conn net.PacketConn, addr net.Addr) (*response, error) { + return c.sendBindingReq(conn, addr, false, false) +} + +func (c *Client) test2(conn net.PacketConn, addr net.Addr) (*response, error) { + return c.sendBindingReq(conn, addr, true, true) +} + +func (c *Client) test3(conn net.PacketConn, addr net.Addr) (*response, error) { + return c.sendBindingReq(conn, addr, false, true) +} diff --git a/vender/github.com/ccding/go-stun/stun/utils.go b/vender/github.com/ccding/go-stun/stun/utils.go new file mode 100755 index 00000000..7242316b --- /dev/null +++ b/vender/github.com/ccding/go-stun/stun/utils.go @@ -0,0 +1,63 @@ +// Copyright 2016, Cong Ding. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Cong Ding + +package stun + +import ( + "net" +) + +// Padding the length of the byte slice to multiple of 4. +func padding(bytes []byte) []byte { + length := uint16(len(bytes)) + return append(bytes, make([]byte, align(length)-length)...) +} + +// Align the uint16 number to the smallest multiple of 4, which is larger than +// or equal to the uint16 number. +func align(n uint16) uint16 { + return (n + 3) & 0xfffc +} + +// isLocalAddress check if localRemote is a local address. +func isLocalAddress(local, localRemote string) bool { + // Resolve the IP returned by the STUN server first. + localRemoteAddr, err := net.ResolveUDPAddr("udp", localRemote) + if err != nil { + return false + } + // Try comparing with the local address on the socket first, but only if + // it's actually specified. + addr, err := net.ResolveUDPAddr("udp", local) + if err == nil && addr.IP != nil && !addr.IP.IsUnspecified() { + return addr.IP.Equal(localRemoteAddr.IP) + } + // Fallback to checking IPs of all interfaces + addrs, err := net.InterfaceAddrs() + if err != nil { + return false + } + for _, addr := range addrs { + ip, _, err := net.ParseCIDR(addr.String()) + if err != nil { + continue + } + if ip.Equal(localRemoteAddr.IP) { + return true + } + } + return false +} diff --git a/vender/github.com/ccding/go-stun/stun/utils_test.go b/vender/github.com/ccding/go-stun/stun/utils_test.go new file mode 100755 index 00000000..6f0088dc --- /dev/null +++ b/vender/github.com/ccding/go-stun/stun/utils_test.go @@ -0,0 +1,69 @@ +// Copyright 2015, Cong Ding. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Cong Ding + +package stun + +import ( + "testing" +) + +func TestPadding(t *testing.T) { + b := []byte{1, 2} + expected := []byte{1, 2, 0, 0} + result := padding(b) + if len(result) != len(expected) { + t.Errorf("Padding error: result size wrong.\n") + } + for i := range expected { + if expected[i] != result[i] { + t.Errorf("Padding error: data wrong in bit %d.\n", i) + } + } +} + +func TestAlign(t *testing.T) { + d := make(map[uint16]uint16) + d[1] = 4 + d[4] = 4 + d[5] = 8 + d[6] = 8 + d[7] = 8 + d[8] = 8 + d[65528] = 65528 + d[65529] = 65532 + d[65531] = 65532 + d[65532] = 65532 + for k, v := range d { + if align(k) != v { + t.Errorf("Align error: expected %d, get %d", align(k), v) + } + } +} + +func TestIsLocalAddress(t *testing.T) { + if !isLocalAddress(":1234", "127.0.0.1:8888") { + t.Errorf("isLocal error") + } + if !isLocalAddress("192.168.0.1:1234", "192.168.0.1:8888") { + t.Errorf("isLocal error") + } + if !isLocalAddress("8.8.8.8:1234", "8.8.8.8:8888") { + t.Errorf("isLocal error") + } + if isLocalAddress(":1234", "8.8.8.8:8888") { + t.Errorf("isLocal error") + } +}