diff --git a/README_ZH.md b/README_ZH.md index b0b46b4..dea5c5e 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -599,7 +599,7 @@ server连接到bridge的时候,如果同时有多个client连接到同一个brid ![5.2](/docs/images/5.2.png) 使用本地端口8090,假设上级SOCKS5代理是`22.22.22.22:8080` `./proxy socks -t tcp -p "0.0.0.0:8090" -T tcp -P "22.22.22.22:8080" ` -我们还可以指定网站域名的黑白名单文件,一行一个域名,匹配规则是最右匹配,比如:baidu.com,匹配的是*.*.baidu.com,黑名单的域名域名直接走上级代理,白名单的域名不走上级代理. +我们还可以指定网站域名的黑白名单文件,一行一个域名,匹配规则是最右匹配,比如:baidu.com,匹配的是*.*.baidu.com,黑名单的域名域名直接走上级代理,白名单的域名不走上级代理;如果域名即在黑名单又在白名单中,那么黑名单起作用. `./proxy socks -p "0.0.0.0:8090" -T tcp -P "22.22.22.22:8080" -b blocked.txt -d direct.txt` #### **5.3.SOCKS二级代理(加密)** diff --git a/utils/socks/client.go b/utils/socks/client.go new file mode 100644 index 0000000..7253d21 --- /dev/null +++ b/utils/socks/client.go @@ -0,0 +1,253 @@ +package socks + +import ( + "encoding/binary" + "errors" + "fmt" + "io" + "net" + "strconv" + "time" +) + +var socks5Errors = []string{ + "", + "general failure", + "connection forbidden", + "network unreachable", + "host unreachable", + "connection refused", + "TTL expired", + "command not supported", + "address type not supported", +} + +type Auth struct { + User, Password string +} +type ClientConn struct { + user string + password string + conn *net.Conn + header []byte + timeout time.Duration + addr string + network string + udpAddr string +} + +// SOCKS5 returns a Dialer that makes SOCKSv5 connections to the given address +// with an optional username and password. See RFC 1928 and RFC 1929. +// target must be a canonical address with a host and port. +// network : tcp udp +func NewClientConn(conn *net.Conn, network, target string, timeout time.Duration, auth *Auth, header []byte) *ClientConn { + s := &ClientConn{ + conn: conn, + network: network, + timeout: timeout, + } + if auth != nil { + s.user = auth.User + s.password = auth.Password + } + if header != nil && len(header) > 0 { + s.header = header + } + if network == "udp" && target == "" { + target = "0.0.0.0:1" + } + s.addr = target + return s +} + +// connect takes an existing connection to a socks5 proxy server, +// and commands the server to extend that connection to target, +// which must be a canonical address with a host and port. +func (s *ClientConn) Connect() error { + host, portStr, err := net.SplitHostPort(s.addr) + if err != nil { + return err + } + port, err := strconv.Atoi(portStr) + if err != nil { + return errors.New("proxy: failed to parse port number: " + portStr) + } + if port < 1 || port > 0xffff { + return errors.New("proxy: port number out of range: " + portStr) + } + + if err := s.handshake(host); err != nil { + return err + } + buf := []byte{} + if s.network == "tcp" { + buf = append(buf, VERSION_V5, CMD_CONNECT, 0 /* reserved */) + + } else { + buf = append(buf, VERSION_V5, CMD_ASSOCIATE, 0 /* reserved */) + } + if ip := net.ParseIP(host); ip != nil { + if ip4 := ip.To4(); ip4 != nil { + buf = append(buf, ATYP_IPV4) + ip = ip4 + } else { + buf = append(buf, ATYP_IPV6) + } + buf = append(buf, ip...) + } else { + if len(host) > 255 { + return errors.New("proxy: destination host name too long: " + host) + } + buf = append(buf, ATYP_DOMAIN) + buf = append(buf, byte(len(host))) + buf = append(buf, host...) + } + buf = append(buf, byte(port>>8), byte(port)) + (*s.conn).SetDeadline(time.Now().Add(s.timeout)) + if _, err := (*s.conn).Write(buf); err != nil { + return errors.New("proxy: failed to write connect request to SOCKS5 proxy at " + s.addr + ": " + err.Error()) + } + (*s.conn).SetDeadline(time.Time{}) + (*s.conn).SetDeadline(time.Now().Add(s.timeout)) + if _, err := io.ReadFull((*s.conn), buf[:4]); err != nil { + return errors.New("proxy: failed to read connect reply from SOCKS5 proxy at " + s.addr + ": " + err.Error()) + } + (*s.conn).SetDeadline(time.Time{}) + failure := "unknown error" + if int(buf[1]) < len(socks5Errors) { + failure = socks5Errors[buf[1]] + } + + if len(failure) > 0 { + return errors.New("proxy: SOCKS5 proxy at " + s.addr + " failed to connect: " + failure) + } + + bytesToDiscard := 0 + switch buf[3] { + case ATYP_IPV4: + bytesToDiscard = net.IPv4len + case ATYP_IPV6: + bytesToDiscard = net.IPv6len + case ATYP_DOMAIN: + (*s.conn).SetDeadline(time.Now().Add(s.timeout)) + _, err := io.ReadFull((*s.conn), buf[:1]) + (*s.conn).SetDeadline(time.Time{}) + if err != nil { + return errors.New("proxy: failed to read domain length from SOCKS5 proxy at " + s.addr + ": " + err.Error()) + } + bytesToDiscard = int(buf[0]) + default: + return errors.New("proxy: got unknown address type " + strconv.Itoa(int(buf[3])) + " from SOCKS5 proxy at " + s.addr) + } + + if cap(buf) < bytesToDiscard { + buf = make([]byte, bytesToDiscard) + } else { + buf = buf[:bytesToDiscard] + } + (*s.conn).SetDeadline(time.Now().Add(s.timeout)) + if _, err := io.ReadFull((*s.conn), buf); err != nil { + return errors.New("proxy: failed to read address from SOCKS5 proxy at " + s.addr + ": " + err.Error()) + } + (*s.conn).SetDeadline(time.Time{}) + var ip net.IP + ip = buf + ipStr := "" + if bytesToDiscard == net.IPv4len || bytesToDiscard == net.IPv6len { + if ipv4 := ip.To4(); ipv4 != nil { + ipStr = ipv4.String() + } else { + ipStr = ip.To16().String() + } + } + //log.Printf("%v", ipStr) + // Also need to discard the port number + (*s.conn).SetDeadline(time.Now().Add(s.timeout)) + if _, err := io.ReadFull((*s.conn), buf[:2]); err != nil { + return errors.New("proxy: failed to read port from SOCKS5 proxy at " + s.addr + ": " + err.Error()) + } + p := binary.BigEndian.Uint16([]byte{buf[0], buf[1]}) + //log.Printf("%v", p) + s.udpAddr = net.JoinHostPort(ipStr, fmt.Sprintf("%d", p)) + //log.Printf("%v", s.udpAddr) + (*s.conn).SetDeadline(time.Time{}) + return nil +} +func (s *ClientConn) SendUDP(data []byte, addr string) (respData []byte, err error) { + + c, err := net.DialTimeout("udp", s.udpAddr, s.timeout) + if err != nil { + return + } + conn := c.(*net.UDPConn) + + p := NewPacketUDP() + p.Build(addr, data) + conn.SetDeadline(time.Now().Add(s.timeout)) + conn.Write(p.Bytes()) + conn.SetDeadline(time.Time{}) + + buf := make([]byte, 1024) + conn.SetDeadline(time.Now().Add(s.timeout)) + n, _, err := conn.ReadFrom(buf) + conn.SetDeadline(time.Time{}) + if err != nil { + return + } + respData = buf[:n] + return +} +func (s *ClientConn) handshake(host string) error { + + // the size here is just an estimate + buf := make([]byte, 0, 6+len(host)) + + buf = append(buf, VERSION_V5) + if len(s.user) > 0 && len(s.user) < 256 && len(s.password) < 256 { + buf = append(buf, 2 /* num auth methods */, Method_NO_AUTH, Method_USER_PASS) + } else { + buf = append(buf, 1 /* num auth methods */, Method_NO_AUTH) + } + (*s.conn).SetDeadline(time.Now().Add(s.timeout)) + if _, err := (*s.conn).Write(buf); err != nil { + return errors.New("proxy: failed to write greeting to SOCKS5 proxy at " + s.addr + ": " + err.Error()) + } + (*s.conn).SetDeadline(time.Time{}) + + (*s.conn).SetDeadline(time.Now().Add(s.timeout)) + if _, err := io.ReadFull((*s.conn), buf[:2]); err != nil { + return errors.New("proxy: failed to read greeting from SOCKS5 proxy at " + s.addr + ": " + err.Error()) + } + (*s.conn).SetDeadline(time.Time{}) + + if buf[0] != 5 { + return errors.New("proxy: SOCKS5 proxy at " + s.addr + " has unexpected version " + strconv.Itoa(int(buf[0]))) + } + if buf[1] == 0xff { + return errors.New("proxy: SOCKS5 proxy at " + s.addr + " requires authentication") + } + + // See RFC 1929 + if buf[1] == Method_USER_PASS { + buf = buf[:0] + buf = append(buf, 1 /* password protocol version */) + buf = append(buf, uint8(len(s.user))) + buf = append(buf, s.user...) + buf = append(buf, uint8(len(s.password))) + buf = append(buf, s.password...) + (*s.conn).SetDeadline(time.Now().Add(s.timeout)) + if _, err := (*s.conn).Write(buf); err != nil { + return errors.New("proxy: failed to write authentication request to SOCKS5 proxy at " + s.addr + ": " + err.Error()) + } + (*s.conn).SetDeadline(time.Time{}) + (*s.conn).SetDeadline(time.Now().Add(s.timeout)) + if _, err := io.ReadFull((*s.conn), buf[:2]); err != nil { + return errors.New("proxy: failed to read authentication reply from SOCKS5 proxy at " + s.addr + ": " + err.Error()) + } + (*s.conn).SetDeadline(time.Time{}) + if buf[1] != 0 { + return errors.New("proxy: SOCKS5 proxy at " + s.addr + " rejected username/password") + } + } + return nil +} diff --git a/utils/socks/server.go b/utils/socks/server.go new file mode 100644 index 0000000..121798a --- /dev/null +++ b/utils/socks/server.go @@ -0,0 +1,225 @@ +package socks + +import ( + "fmt" + "net" + "snail007/proxy/utils" + "strings" + "time" +) + +const ( + Method_NO_AUTH = uint8(0x00) + Method_GSSAPI = uint8(0x01) + Method_USER_PASS = uint8(0x02) + Method_IANA = uint8(0x7F) + Method_RESVERVE = uint8(0x80) + Method_NONE_ACCEPTABLE = uint8(0xFF) + VERSION_V5 = uint8(0x05) + CMD_CONNECT = uint8(0x01) + CMD_BIND = uint8(0x02) + CMD_ASSOCIATE = uint8(0x03) + ATYP_IPV4 = uint8(0x01) + ATYP_DOMAIN = uint8(0x03) + ATYP_IPV6 = uint8(0x04) + REP_SUCCESS = uint8(0x00) + REP_REQ_FAIL = uint8(0x01) + REP_RULE_FORBIDDEN = uint8(0x02) + REP_NETWOR_UNREACHABLE = uint8(0x03) + REP_HOST_UNREACHABLE = uint8(0x04) + REP_CONNECTION_REFUSED = uint8(0x05) + REP_TTL_TIMEOUT = uint8(0x06) + REP_CMD_UNSUPPORTED = uint8(0x07) + REP_ATYP_UNSUPPORTED = uint8(0x08) + REP_UNKNOWN = uint8(0x09) + RSV = uint8(0x00) +) + +var ( + ZERO_IP = []byte{0x00, 0x00, 0x00, 0x00} + ZERO_PORT = []byte{0x00, 0x00} +) + +type ServerConn struct { + target string + user string + password string + conn *net.Conn + timeout time.Duration + auth *utils.BasicAuth + header []byte + ver uint8 + //method + methodsCount uint8 + methods []uint8 + method uint8 + //request + cmd uint8 + reserve uint8 + addressType uint8 + dstAddr string + dstPort string + dstHost string + udpAddress string +} + +func NewServerConn(conn *net.Conn, timeout time.Duration, auth *utils.BasicAuth, udpAddress string, header []byte) *ServerConn { + if udpAddress == "" { + udpAddress = "0.0.0.0:16666" + } + s := &ServerConn{ + conn: conn, + timeout: timeout, + auth: auth, + header: header, + ver: VERSION_V5, + udpAddress: udpAddress, + } + return s + +} +func (s *ServerConn) Close() { + utils.CloseConn(s.conn) +} +func (s *ServerConn) AuthData() Auth { + return Auth{s.user, s.password} +} +func (s *ServerConn) Method() uint8 { + return s.method +} +func (s *ServerConn) Target() string { + return s.target +} +func (s *ServerConn) Handshake() (err error) { + remoteAddr := (*s.conn).RemoteAddr() + //协商开始 + //method select request + var methodReq MethodsRequest + (*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout)) + + methodReq, e := NewMethodsRequest((*s.conn), s.header) + (*s.conn).SetReadDeadline(time.Time{}) + if e != nil { + (*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout)) + methodReq.Reply(Method_NONE_ACCEPTABLE) + (*s.conn).SetReadDeadline(time.Time{}) + err = fmt.Errorf("new methods request fail,ERR: %s", e) + return + } + if s.auth == nil { + if !methodReq.Select(Method_NO_AUTH) { + (*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout)) + methodReq.Reply(Method_NONE_ACCEPTABLE) + (*s.conn).SetReadDeadline(time.Time{}) + err = fmt.Errorf("none method found : Method_NO_AUTH") + return + } + s.method = Method_NO_AUTH + //method select reply + (*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout)) + err = methodReq.Reply(Method_NO_AUTH) + (*s.conn).SetReadDeadline(time.Time{}) + if err != nil { + err = fmt.Errorf("reply answer data fail,ERR: %s", err) + return + } + // err = fmt.Errorf("% x", methodReq.Bytes()) + } else { + //auth + if !methodReq.Select(Method_USER_PASS) { + (*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout)) + methodReq.Reply(Method_NONE_ACCEPTABLE) + (*s.conn).SetReadDeadline(time.Time{}) + err = fmt.Errorf("none method found : Method_USER_PASS") + return + } + s.method = Method_USER_PASS + //method reply need auth + (*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout)) + err = methodReq.Reply(Method_USER_PASS) + (*s.conn).SetReadDeadline(time.Time{}) + if err != nil { + err = fmt.Errorf("reply answer data fail,ERR: %s", err) + return + } + //read auth + buf := make([]byte, 500) + var n int + (*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout)) + n, err = (*s.conn).Read(buf) + (*s.conn).SetReadDeadline(time.Time{}) + if err != nil { + err = fmt.Errorf("read auth info fail,ERR: %s", err) + return + } + r := buf[:n] + s.user = string(r[2 : r[1]+2]) + s.password = string(r[2+r[1]+1:]) + //err = fmt.Errorf("user:%s,pass:%s", user, pass) + //auth + _addr := strings.Split(remoteAddr.String(), ":") + if s.auth.CheckUserPass(s.user, s.password, _addr[0], "") { + (*s.conn).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(s.timeout))) + _, err = (*s.conn).Write([]byte{0x01, 0x00}) + (*s.conn).SetDeadline(time.Time{}) + if err != nil { + err = fmt.Errorf("answer auth success to %s fail,ERR: %s", remoteAddr, err) + return + } + } else { + (*s.conn).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(s.timeout))) + _, err = (*s.conn).Write([]byte{0x01, 0x01}) + (*s.conn).SetDeadline(time.Time{}) + if err != nil { + err = fmt.Errorf("answer auth fail to %s fail,ERR: %s", remoteAddr, err) + return + } + err = fmt.Errorf("auth fail from %s", remoteAddr) + return + } + } + //request detail + (*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout)) + request, e := NewRequest(*s.conn) + (*s.conn).SetReadDeadline(time.Time{}) + if e != nil { + err = fmt.Errorf("read request data fail,ERR: %s", e) + return + } + //协商结束 + + switch request.CMD() { + case CMD_BIND: + err = request.TCPReply(REP_UNKNOWN) + if err != nil { + err = fmt.Errorf("TCPReply REP_UNKNOWN to %s fail,ERR: %s", remoteAddr, err) + return + } + err = fmt.Errorf("cmd bind not supported, form: %s", remoteAddr) + return + case CMD_CONNECT: + err = request.TCPReply(REP_SUCCESS) + if err != nil { + err = fmt.Errorf("TCPReply REP_SUCCESS to %s fail,ERR: %s", remoteAddr, err) + return + } + case CMD_ASSOCIATE: + err = request.UDPReply(REP_SUCCESS, s.udpAddress) + if err != nil { + err = fmt.Errorf("UDPReply REP_SUCCESS to %s fail,ERR: %s", remoteAddr, err) + return + } + } + + //fill socks info + s.target = request.Addr() + s.methodsCount = methodReq.MethodsCount() + s.methods = methodReq.Methods() + s.cmd = request.CMD() + s.reserve = request.reserve + s.addressType = request.addressType + s.dstAddr = request.dstAddr + s.dstHost = request.dstHost + s.dstPort = request.dstPort + return +} diff --git a/utils/socks/structs.go b/utils/socks/structs.go index ef5b51b..a5ec922 100644 --- a/utils/socks/structs.go +++ b/utils/socks/structs.go @@ -3,44 +3,13 @@ package socks import ( "bytes" "encoding/binary" + "errors" "fmt" "io" "net" "strconv" ) -const ( - Method_NO_AUTH = uint8(0x00) - Method_GSSAPI = uint8(0x01) - Method_USER_PASS = uint8(0x02) - Method_IANA = uint8(0x7F) - Method_RESVERVE = uint8(0x80) - Method_NONE_ACCEPTABLE = uint8(0xFF) - VERSION_V5 = uint8(0x05) - CMD_CONNECT = uint8(0x01) - CMD_BIND = uint8(0x02) - CMD_ASSOCIATE = uint8(0x03) - ATYP_IPV4 = uint8(0x01) - ATYP_DOMAIN = uint8(0x03) - ATYP_IPV6 = uint8(0x04) - REP_SUCCESS = uint8(0x00) - REP_REQ_FAIL = uint8(0x01) - REP_RULE_FORBIDDEN = uint8(0x02) - REP_NETWOR_UNREACHABLE = uint8(0x03) - REP_HOST_UNREACHABLE = uint8(0x04) - REP_CONNECTION_REFUSED = uint8(0x05) - REP_TTL_TIMEOUT = uint8(0x06) - REP_CMD_UNSUPPORTED = uint8(0x07) - REP_ATYP_UNSUPPORTED = uint8(0x08) - REP_UNKNOWN = uint8(0x09) - RSV = uint8(0x00) -) - -var ( - ZERO_IP = []byte{0x00, 0x00, 0x00, 0x00} - ZERO_PORT = []byte{0x00, 0x00} -) - type Request struct { ver uint8 cmd uint8 @@ -57,7 +26,7 @@ func NewRequest(rw io.ReadWriter, header ...[]byte) (req Request, err interface{ var b = make([]byte, 1024) var n int req = Request{rw: rw} - if len(header) == 1 { + if header != nil && len(header) == 1 && len(header[0]) > 1 { b = header[0] n = len(header[0]) } else { @@ -71,7 +40,6 @@ func NewRequest(rw io.ReadWriter, header ...[]byte) (req Request, err interface{ req.cmd = uint8(b[1]) req.reserve = uint8(b[2]) req.addressType = uint8(b[3]) - if b[0] != 0x5 { err = fmt.Errorf("sosck version supported") req.TCPReply(REP_REQ_FAIL) @@ -129,7 +97,7 @@ func (s *Request) NewReply(rep uint8, addr string) []byte { ipv6[4], ipv6[5], ipv6[6], ipv6[7], ipv6[8], ipv6[9], ipv6[10], ipv6[11], ) - if ipv6 != nil && "0000000000255255" != zeroiIPv6 { + if ipb == nil && ipv6 != nil && "0000000000255255" != zeroiIPv6 { atyp = ATYP_IPV6 ipb = ip.To16() } @@ -165,7 +133,7 @@ func NewMethodsRequest(r io.ReadWriter, header ...[]byte) (s MethodsRequest, err s.rw = &r var buf = make([]byte, 300) var n int - if len(header) == 1 { + if header != nil && len(header) == 1 && len(header[0]) > 1 { buf = header[0] n = len(header[0]) } else { @@ -182,7 +150,6 @@ func NewMethodsRequest(r io.ReadWriter, header ...[]byte) (s MethodsRequest, err err = fmt.Errorf("socks methods data length error") return } - s.ver = buf[0] s.methodsCount = buf[1] s.methods = buf[2:n] @@ -195,6 +162,9 @@ func (s *MethodsRequest) Version() uint8 { func (s *MethodsRequest) MethodsCount() uint8 { return s.methodsCount } +func (s *MethodsRequest) Methods() []uint8 { + return s.methods +} func (s *MethodsRequest) Select(method uint8) bool { for _, m := range s.methods { if m == method { @@ -211,17 +181,6 @@ func (s *MethodsRequest) Bytes() []byte { return s.bytes } -type UDPPacket struct { - rsv uint16 - frag uint8 - atype uint8 - dstHost string - dstPort string - data []byte - header []byte - bytes []byte -} - func ParseUDPPacket(b []byte) (p UDPPacket, err error) { p = UDPPacket{} p.frag = uint8(b[2]) @@ -249,6 +208,18 @@ func ParseUDPPacket(b []byte) (p UDPPacket, err error) { p.header = b[:portIndex+2] return } + +type UDPPacket struct { + rsv uint16 + frag uint8 + atype uint8 + dstHost string + dstPort string + data []byte + header []byte + bytes []byte +} + func (s *UDPPacket) Header() []byte { return s.header } @@ -268,3 +239,104 @@ func (s *UDPPacket) Port() string { func (s *UDPPacket) Data() []byte { return s.data } + +type PacketUDP struct { + rsv uint16 + frag uint8 + atype uint8 + dstHost string + dstPort string + data []byte +} + +func NewPacketUDP() (p PacketUDP) { + return PacketUDP{} +} +func (p *PacketUDP) Build(destAddr string, data []byte) (err error) { + host, port, err := net.SplitHostPort(destAddr) + if err != nil { + return + } + p.rsv = 0 + p.frag = 0 + p.dstHost = host + p.dstPort = port + p.atype = ATYP_IPV4 + if ip := net.ParseIP(host); ip != nil { + if ip4 := ip.To4(); ip4 != nil { + p.atype = ATYP_IPV4 + ip = ip4 + } else { + p.atype = ATYP_IPV6 + } + } else { + if len(host) > 255 { + err = errors.New("proxy: destination host name too long: " + host) + return + } + p.atype = ATYP_DOMAIN + } + p.data = data + + return +} +func (p *PacketUDP) Parse(b []byte) (err error) { + p.frag = uint8(b[2]) + if p.frag != 0 { + err = fmt.Errorf("FRAG only support for 0 , %v ,%v", p.frag, b[:4]) + return + } + portIndex := 0 + p.atype = b[3] + switch p.atype { + case ATYP_IPV4: //IP V4 + p.dstHost = net.IPv4(b[4], b[5], b[6], b[7]).String() + portIndex = 8 + case ATYP_DOMAIN: //域名 + domainLen := uint8(b[4]) + p.dstHost = string(b[5 : 5+domainLen]) //b[4]表示域名的长度 + portIndex = int(5 + domainLen) + case ATYP_IPV6: //IP V6 + p.dstHost = net.IP{b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15], b[16], b[17], b[18], b[19]}.String() + portIndex = 20 + } + p.dstPort = strconv.Itoa(int(b[portIndex])<<8 | int(b[portIndex+1])) + p.data = b[portIndex+2:] + return +} +func (p *PacketUDP) Header() []byte { + header := new(bytes.Buffer) + header.Write([]byte{0x00, 0x00, p.frag, p.atype}) + if p.atype == ATYP_IPV4 { + ip := net.ParseIP(p.dstHost) + header.Write(ip.To4()) + } else if p.atype == ATYP_IPV6 { + ip := net.ParseIP(p.dstHost) + header.Write(ip.To16()) + } else if p.atype == ATYP_DOMAIN { + hBytes := []byte(p.dstHost) + header.WriteByte(byte(len(hBytes))) + header.Write(hBytes) + } + port, _ := strconv.ParseUint(p.dstPort, 10, 64) + portBytes := new(bytes.Buffer) + binary.Write(portBytes, binary.BigEndian, port) + header.Write(portBytes.Bytes()[portBytes.Len()-2:]) + return header.Bytes() +} +func (p *PacketUDP) Bytes() []byte { + packBytes := new(bytes.Buffer) + packBytes.Write(p.Header()) + packBytes.Write(p.data) + return packBytes.Bytes() +} +func (p *PacketUDP) Host() string { + return p.dstHost +} + +func (p *PacketUDP) Port() string { + return p.dstPort +} +func (p *PacketUDP) Data() []byte { + return p.data +}