From d66ed27dd9e870640cb4db89c59ceef36edfcbc8 Mon Sep 17 00:00:00 2001 From: Leo Balduf Date: Fri, 2 Sep 2016 16:42:01 -0400 Subject: [PATCH] udp: add support for opentracker-style IPv6 announces --- frontend/udp/frontend.go | 6 +++--- frontend/udp/parser.go | 22 ++++++++++++++++------ frontend/udp/writer.go | 18 +++++++++++++++--- 3 files changed, 34 insertions(+), 12 deletions(-) diff --git a/frontend/udp/frontend.go b/frontend/udp/frontend.go index 1cf3d03..c135787 100644 --- a/frontend/udp/frontend.go +++ b/frontend/udp/frontend.go @@ -192,11 +192,11 @@ func (t *Frontend) handleRequest(r Request, w ResponseWriter) (actionName string WriteConnectionID(w, txID, NewConnectionID(r.IP, time.Now(), t.PrivateKey)) return - case announceActionID: + case announceActionID, announceV6ActionID: actionName = "announce" var req *bittorrent.AnnounceRequest - req, err = ParseAnnounce(r, t.AllowIPSpoofing) + req, err = ParseAnnounce(r, t.AllowIPSpoofing, actionID == announceV6ActionID) if err != nil { WriteError(w, txID, err) return @@ -209,7 +209,7 @@ func (t *Frontend) handleRequest(r Request, w ResponseWriter) (actionName string return } - WriteAnnounce(w, txID, resp) + WriteAnnounce(w, txID, resp, actionID == announceV6ActionID) go t.logic.AfterAnnounce(context.TODO(), req, resp) diff --git a/frontend/udp/parser.go b/frontend/udp/parser.go index 3c0fed5..ccddfff 100644 --- a/frontend/udp/parser.go +++ b/frontend/udp/parser.go @@ -15,6 +15,7 @@ const ( announceActionID scrapeActionID errorActionID + announceV6ActionID ) // Option-Types as described in BEP 41 and BEP 45. @@ -51,8 +52,17 @@ var ( // ParseAnnounce parses an AnnounceRequest from a UDP request. // // If allowIPSpoofing is true, IPs provided via params will be used. -func ParseAnnounce(r Request, allowIPSpoofing bool) (*bittorrent.AnnounceRequest, error) { - if len(r.Packet) < 98 { +// +// If v6 is true the announce will be parsed as an IPv6 announce "the +// opentracker way", see +// http://opentracker.blog.h3q.com/2007/12/28/the-ipv6-situation/ +func ParseAnnounce(r Request, allowIPSpoofing, v6 bool) (*bittorrent.AnnounceRequest, error) { + ipEnd := 84 + net.IPv4len + if v6 { + ipEnd = 84 + net.IPv6len + } + + if len(r.Packet) < ipEnd+10 { return nil, errMalformedPacket } @@ -68,7 +78,7 @@ func ParseAnnounce(r Request, allowIPSpoofing bool) (*bittorrent.AnnounceRequest } ip := r.IP - ipbytes := r.Packet[84:88] + ipbytes := r.Packet[84:ipEnd] if allowIPSpoofing { ip = net.IP(ipbytes) } @@ -77,10 +87,10 @@ func ParseAnnounce(r Request, allowIPSpoofing bool) (*bittorrent.AnnounceRequest return nil, errMalformedIP } - numWant := binary.BigEndian.Uint32(r.Packet[92:96]) - port := binary.BigEndian.Uint16(r.Packet[96:98]) + numWant := binary.BigEndian.Uint32(r.Packet[ipEnd+4 : ipEnd+8]) + port := binary.BigEndian.Uint16(r.Packet[ipEnd+8 : ipEnd+10]) - params, err := handleOptionalParameters(r.Packet[98:]) + params, err := handleOptionalParameters(r.Packet[ipEnd+10:]) if err != nil { return nil, err } diff --git a/frontend/udp/writer.go b/frontend/udp/writer.go index e3a495f..86eef08 100644 --- a/frontend/udp/writer.go +++ b/frontend/udp/writer.go @@ -25,15 +25,27 @@ func WriteError(w io.Writer, txID []byte, err error) { } // WriteAnnounce encodes an announce response according to BEP 15. -func WriteAnnounce(w io.Writer, txID []byte, resp *bittorrent.AnnounceResponse) { +// The peers returned will be resp.IPv6Peers or resp.IPv4Peers, depending on +// whether v6 is set. The action ID will be 4, according to +// http://opentracker.blog.h3q.com/2007/12/28/the-ipv6-situation/. +func WriteAnnounce(w io.Writer, txID []byte, resp *bittorrent.AnnounceResponse, v6 bool) { var buf bytes.Buffer - writeHeader(&buf, txID, announceActionID) + if v6 { + writeHeader(&buf, txID, announceV6ActionID) + } else { + writeHeader(&buf, txID, announceActionID) + } binary.Write(&buf, binary.BigEndian, uint32(resp.Interval/time.Second)) binary.Write(&buf, binary.BigEndian, uint32(resp.Incomplete)) binary.Write(&buf, binary.BigEndian, uint32(resp.Complete)) - for _, peer := range resp.IPv4Peers { + peers := resp.IPv4Peers + if v6 { + peers = resp.IPv6Peers + } + + for _, peer := range peers { buf.Write(peer.IP) binary.Write(&buf, binary.BigEndian, peer.Port) }