// Port Control Protocol prototyping. // RFC 6887 class CPCPRequestHeader { U8 version; U8 opcode; // includes R bit. U16 reserved; // must be all 0 on TX U32 req_lifetime; // seconds. 0 interpreted as 'delete'. U8 pcp_client_ip[16]; // source ipv4 addr converted to ipv4-mapped ipv6 as per spec. 128 bits }; class CPCPMapRequest { CPCPRequestHeader header; U8 nonce[12]; // "Mapping Nonce" 96 bits of random vals. U8 protocol; // 6 TCP. 17 UDP. 0 'all protocols'. U8 reserved[3]; // 24 bits, TX must be 0, ignore on RX. U16 internal_port; /* internal_port. 0 'all ports' legal only on lifetime 0 (delete) or client req 'all ports'. must be ignored on RX. */ U16 external_port; /* external_port. 'suggested'. if client doesnt know it or has no preference it must be 0.*/ U8 external_ip[16]; /* external_ip. 'suggested'. if client doesnt know it or no preference, it must use 'address-family-specific all-zero address. */ }; I64 PCPSendMapRequest(U16 internal_port, U16 external_port=NULL, U32 external_ip=NULL) { U8 *frame; CPCPMapRequest *request; I64 de_index; I64 i; de_index = UDPPacketAllocate(&frame, IPV4AddressGet, 5351, ipv4_globals.ipv4_router_address, 5351, sizeof(CPCPMapRequest)); if (de_index < 0) { NetErr("PCP SEND MAP REQ: Failed, UDPPacketAllocate returned error."); return de_index; } request = frame; request->header.version = 2; request->header.opcode = 1; // MAP request->header.req_lifetime = 60; // live for 1 min. // force local IPV4 addr into IPV4-mapped-IPV6 for (i = 0; i < 10; i++) // first 80 bits 0 request->header.pcp_client_ip[i] = 0; for (; i < 10 + 2; i++) // next 16 bits 1 request->header.pcp_client_ip[i] = 0xFF; *(&request->header.pcp_client_ip[i](U32 *)) = EndianU32(IPV4AddressGet); // // set random 'nonce' for (i = 0; i < 12; i++) request->nonce[i] = RandU8; request->protocol = IP_PROTOCOL_UDP; request->internal_port = internal_port; request->external_port = external_port; if (!external_ip) { // if no specified ext ip, use specific ipv4-mapped-ipv6 all-zeroes address. for (i = 0; i < 10; i++) request->external_ip[i] = 0; for (; i < 10 + 2; i++) request->external_ip[i] = 0xFF; *(&request->external_ip[i](U32 *)) = 0; } else { // else, map to param ip for (i = 0; i < 10; i++) request->external_ip[i] = 0; for (; i < 10 + 2; i++) request->external_ip[i] = 0xFF; *(&request->external_ip[i](U32 *)) = EndianU32(external_ip); } UDPPacketFinish(de_index); return 0; } PCPSendMapRequest(0xDEAD, 0xBEEF);