// Parse a UDP byte buffer, return response from udpTracker func parseUDP(buf []byte, addr *net.UDPAddr) ([]byte, error) { // Attempt to grab generic UDP connection fields packet := new(udp.Packet) err := packet.UnmarshalBinary(buf) if err != nil { // Because no transaction ID is present on failure, we must return nil return nil, errUDPHandshake } // Create a udpTracker to handle this client udpTracker := tracker.UDPTracker{TransID: packet.TransID} // Check for maintenance mode if common.Static.Maintenance { // Return tracker error with maintenance message return udpTracker.Error("Maintenance: " + common.Static.StatusMessage), nil } // Action switch // Action 0: Connect if packet.Action == 0 { // Validate UDP udpTracker handshake if packet.ConnID != udpInitID { return udpTracker.Error("Invalid UDP udpTracker handshake"), errUDPHandshake } // Generate a connection ID, which will be expected for this client next call expID := uint64(common.RandRange(1, 1000000000)) // Store this client's address and ID in map udpAddrToID[addr.String()] = expID // Generate connect response connect := udp.ConnectResponse{ Action: 0, TransID: packet.TransID, ConnID: expID, } // Grab bytes from connect response connectBuf, err := connect.MarshalBinary() if err != nil { log.Println(err.Error()) return udpTracker.Error("Could not generate UDP connect response"), errUDPWrite } return connectBuf, nil } // For all udpTracker actions other than connect, we must validate the connection ID for this // address, ensuring it matches the previously set value // Ensure connection ID map contains this IP address expID, ok := udpAddrToID[addr.String()] if !ok { return udpTracker.Error("Client must properly handshake before announce"), errUDPHandshake } // Validate expected connection ID using map if packet.ConnID != expID { return udpTracker.Error("Invalid UDP connection ID"), errUDPHandshake } // Clear this IP from the connection map after 2 minutes // note: this is done to conserve memory and prevent session fixation go func(addr *net.UDPAddr) { <-time.After(2 * time.Minute) delete(udpAddrToID, addr.String()) }(addr) // Action 1: Announce if packet.Action == 1 { // Retrieve UDP announce request from byte buffer announce := new(udp.AnnounceRequest) err := announce.UnmarshalBinary(buf) log.Println(announce) if err != nil { return udpTracker.Error("Malformed UDP announce"), errUDPInteger } // Convert UDP announce to query map query := announce.ToValues() // Check if a proper IP was set, and if not, use the UDP connection address if query.Get("ip") == "0" { query.Set("ip", strings.Split(addr.String(), ":")[0]) } // Trigger an anonymous announce return tracker.Announce(udpTracker, data.UserRecord{}, query), nil } // Action 2: Scrape if packet.Action == 2 { // Generate UDP scrape packet from byte buffer scrape := new(udp.ScrapeRequest) err := scrape.UnmarshalBinary(buf) if err != nil { return udpTracker.Error("Malformed UDP scrape"), errUDPHandshake } // Convert UDP scrape to query map query := scrape.ToValues() // Store IP in query map query.Set("ip", strings.Split(addr.String(), ":")[0]) // Trigger a scrape return tracker.Scrape(udpTracker, query), nil } // No action matched return udpTracker.Error("Invalid action"), errUDPAction }