/* EUI64 end */
+/* APL start */
+/* https://tools.ietf.org/html/rfc3123 */
+void APLRecordContent::report(void)
+{
+ regist(1, QType::APL, &make, &make, "APL");
+}
+// Parse incoming packets (e.g. nsupdate)
+std::shared_ptr<DNSRecordContent> APLRecordContent::make(const DNSRecord &dr, PacketReader& pr) {
+ uint8_t temp;
+
+ if(dr.d_clen < 5 or dr.d_clen > 20)
+ throw MOADNSException("Wrong size for APL record");
+
+ auto ret=std::make_shared<APLRecordContent>();
+ pr.xfr16BitInt(ret->d_family);
+ pr.xfr8BitInt(ret->d_prefix);
+ pr.xfr8BitInt(temp);
+ ret->d_n = (temp & 128) >> 7;
+ ret->d_afdlength = temp & 127;
+
+ if (ret->d_family == APL_FAMILY_IPV4) { // IPv4
+ if (ret->d_afdlength > 4) {
+ throw MOADNSException("Invalid IP length for IPv4 APL");
+ }
+ bzero(ret->d_ip4, sizeof(ret->d_ip4));
+ for (int i=0; i < 4; i++) {
+ if (i < ret->d_afdlength)
+ pr.xfr8BitInt(ret->d_ip4[i]);
+ }
+ } else if (ret->d_family == APL_FAMILY_IPV6) {
+ if (ret->d_afdlength > 16) {
+ throw MOADNSException("Invalid IP length for IPv6 APL");
+ }
+ bzero(ret->d_ip6, sizeof(ret->d_ip6));
+ for (int i=0; i< 16; i++) {
+ if (i < ret->d_afdlength)
+ pr.xfr8BitInt(ret->d_ip6[i]);
+ }
+ } else
+ throw MOADNSException("Unknown family for APL record");
+
+ return ret;
+}
+
+// Parse backend record
+std::shared_ptr<DNSRecordContent> APLRecordContent::make(const string& zone) {
+ string record;
+
+ auto ret=std::make_shared<APLRecordContent>();
+
+ // Strip the optional leading ! (negate)
+ if (zone[0] == '!') {
+ ret->d_n = 1;
+ record = zone.substr(1, zone.length()-1);
+ } else {
+ ret->d_n = 0;
+ record = zone;
+ }
+
+ if (record.find("1:", 0) == 0) { // IPv4
+ unsigned int prefix;
+ uint32_t v4ip;
+ string ipstr, subnetstr;
+ int subnet_pos;
+ ComboAddress ca;
+ int bytes;
+
+ ret->d_family = APL_FAMILY_IPV4;
+
+ // Find netmask
+ subnet_pos = record.rfind("/");
+
+ if (subnet_pos < 0) {
+ throw MOADNSException("Asked to decode '"+zone+"' as an APL record, but missing subnet mask");
+ }
+
+ // Read IPv4 string into a ComboAddress
+ ipstr = record.substr(2, subnet_pos - 2);
+ subnetstr = record.substr(subnet_pos + 1, record.length() - subnet_pos - 1);
+ ca = makeComboAddress(ipstr);
+ v4ip = ntohl(ca.sin4.sin_addr.s_addr);
+ if (ca.sin4.sin_family != AF_INET) { // ComboAddress will match v6 IPs, which is not valid here
+ throw MOADNSException("Asked to decode '"+zone+"' as an APL record, but found invalid v4 IP address");
+ }
+ // Section 4.1 of RFC 3123 (don't send trailing "0" bytes)
+ // Copy data; using array of bytes since we might end up truncating them in the packet
+ bzero(ret->d_ip4, sizeof(ret->d_ip4));
+ for (int i=0; i<4; i++) {
+ ret->d_ip4[3-i] = (v4ip & 255);
+ v4ip = v4ip >> 8;
+ }
+ // Remove trailing "0" bytes from packet and calculate length
+ bytes = 4; // Start by assuming we'll send 4 bytes
+ v4ip = ntohl(ca.sin4.sin_addr.s_addr);
+ for (int i=0; i<4; i++) {
+ if ((v4ip & 255) == 0) {
+ // trailing 0 byte, reduce length
+ bytes--;
+ } else
+ {
+ // Found non-0 byte, stop trimming
+ break;
+ }
+ v4ip = v4ip >> 8;
+ }
+
+ // Prefix length
+ if (sscanf(subnetstr.c_str(), "%u", &prefix) == 1) {
+ ret->d_prefix=prefix;
+ } else
+ throw MOADNSException("Asked to decode '"+zone+"' as an IPv4 APL record, but found invalid prefix string "+subnetstr);
+ if (prefix > 32)
+ throw MOADNSException("Asked to decode '"+zone+"' as an IPv4 APL record, but found invalid prefix value "+std::to_string(prefix));
+ ret->d_afdlength = bytes;
+
+ } else if (record.find("2:", 0) == 0) { // IPv6
+ unsigned int prefix;
+ int subnet_pos;
+ string ipstr, subnetstr;
+ ComboAddress ca;
+ int bytes;
+
+ ret->d_family = APL_FAMILY_IPV6;
+
+ // Find Netmask
+ subnet_pos = record.rfind("/");
+ if (subnet_pos < 0) {
+ throw MOADNSException("Asked to decode '"+zone+"' as an APL record, but missing subnet mask");
+ }
+
+ // Parse IPv6 string into ComboAddress
+ ipstr = record.substr(2, subnet_pos - 2);
+ subnetstr = record.substr(subnet_pos + 1, record.length() - subnet_pos - 1);
+ ca = makeComboAddress(ipstr);
+
+ // Section 4.2 of RFC 3123 (don't send trailing "0" bytes)
+ // Remove trailing "0" bytes from packet and reduce length
+ bytes = 16; // Start by assuming we'll send 16 bytes
+ for (int i=15; i>=0; i--) {
+ if (ca.sin6.sin6_addr.s6_addr[i] == 0) {
+ // trailing 0 byte, calculate length
+ bytes--;
+ } else {
+ // Found non-0 byte, stop trimming
+ break;
+ }
+ }
+ bzero(ret->d_ip6, sizeof(ret->d_ip6));
+ for (int i=0; i<bytes; i++) {
+ ret->d_ip6[i] = ca.sin6.sin6_addr.s6_addr[i];
+ }
+ ret->d_afdlength = bytes;
+
+ // Prefix length
+ prefix = 0;
+ if (sscanf(subnetstr.c_str(), "%u", &prefix) == 1) {
+ ret->d_prefix=prefix;
+ } else
+ throw MOADNSException("Asked to decode '"+zone+"' as an IPv6 APL record, but found invalid prefix string "+subnetstr);
+ if (prefix > 32)
+ throw MOADNSException("Asked to decode '"+zone+"' as an IPv6 APL record, but found invalid prefix value "+subnetstr);
+ } else {
+ throw MOADNSException("Asked to encode '"+zone+"' as an IPv6 APL record but got unknown Address Family");
+ }
+
+ return ret;
+}
+
+// DNSRecord to Packet conversion
+void APLRecordContent::toPacket(DNSPacketWriter& pw) {
+
+ pw.xfr16BitInt(d_family);
+ pw.xfr8BitInt(d_prefix);
+ pw.xfr8BitInt((d_n << 7) + d_afdlength);
+ if (d_family == APL_FAMILY_IPV4) {
+ for (int i=0; i<d_afdlength; i++) {
+ pw.xfr8BitInt(d_ip4[i]);
+ }
+ } else if (d_family == APL_FAMILY_IPV6) {
+ for (int i=0; i<d_afdlength; i++) {
+ pw.xfr8BitInt(d_ip6[i]);
+ }
+ }
+}
+
+// Decode record into string
+string APLRecordContent::getZoneRepresentation(bool noDot) const {
+ string s_n, s_family, s_ip;
+
+ // Negation flag
+ if (d_n == 1) {
+ s_n = "!";
+ } else {
+ s_n = "";
+ }
+
+ if (d_family == APL_FAMILY_IPV4) { // IPv4
+ sockaddr_in sa;
+
+ s_family = std::to_string(APL_FAMILY_IPV4);
+ s_ip = "";
+ sa.sin_family = AF_INET;
+ sa.sin_port = 0;
+ sa.sin_addr.s_addr = 0;
+ for (int i=0; i < 4; i++) {
+ sa.sin_addr.s_addr |= d_ip4[i] << (i*8);
+ }
+ ComboAddress ca = ComboAddress(&sa);
+ s_ip = ca.toString();
+
+ } else if (d_family == APL_FAMILY_IPV6) { // IPv6
+ sockaddr_in6 sa;
+ s_family = std::to_string(APL_FAMILY_IPV6);
+ s_ip = "";
+ sa.sin6_family = AF_INET6;
+ sa.sin6_port = 0;
+ sa.sin6_flowinfo = 0;
+ sa.sin6_scope_id = 0;
+ for (int i=0; i < 16; i++) {
+ if (i < d_afdlength) {
+ sa.sin6_addr.s6_addr[i] = d_ip6[i];
+ } else {
+ sa.sin6_addr.s6_addr[i] = 0;
+ }
+ }
+ ComboAddress ca = ComboAddress(&sa);
+ s_ip = ca.toString();
+ } else {
+ throw MOADNSException("Asked to decode APL record but got unknown Address Family "+d_family);
+ }
+
+ return s_n + s_family + ":" + s_ip + "/" + std::to_string(d_prefix);
+}
+
+/* APL end */
+
boilerplate_conv(TKEY, QType::TKEY,
conv.xfrName(d_algo);
conv.xfr32BitInt(d_inception);
MINFORecordContent::report();
URIRecordContent::report();
CAARecordContent::report();
+ APLRecordContent::report();
}
void reportAllTypes()
// X.509 as per PKIX
(CASE_S(QType::CERT, "1 0 0 MIIB9DCCAV2gAwIBAgIJAKxUfFVXhw7HMA0GCSqGSIb3DQEBBQUAMBMxETAPBgNVBAMMCHJlYy50ZXN0MB4XDTEzMDUxMjE5NDgwOVoXDTEzMDYxMTE5NDgwOVowEzERMA8GA1UEAwwIcmVjLnRlc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANKCu5aN/ewOXRPfzAo27XMXhYFCThCjfInTAUIEkzs6jBFZ/eyyIa/kFoiD0tAKwfFfykYU+9XgXeLjetD7rYt3SN3bzzCznoBGbGHHM0Fecrn0LV+tC/NfBB61Yx7e0AMUxmxIeLNRQW5ca5CW8qcIiiQ4fl0BScUjc5+E9QLHAgMBAAGjUDBOMB0GA1UdDgQWBBRzcVu/2bwrgkES+FhYbxZqr7mUgjAfBgNVHSMEGDAWgBRzcVu/2bwrgkES+FhYbxZqr7mUgjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAFVQ8dZBOasOhsWzA/xpAV0WdsqVkxBxrkGIRlbHHBFqOBOOz2MFSzUNx4mDy0qDKI28gcWmWaVsxoQ9VFLD6YRJuUoM8MDNcZDJbKpfDumjvvfnUAK+SiM2c4Ur3xpf0wanCA60/q2bOtFiB0tfAH6RVuIgMC3qjHAIaKEld+fE", "\x00\x01\x00\x00\x00\x30\x82\x01\xf4\x30\x82\x01\x5d\xa0\x03\x02\x01\x02\x02\x09\x00\xac\x54\x7c\x55\x57\x87\x0e\xc7\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x30\x13\x31\x11\x30\x0f\x06\x03\x55\x04\x03\x0c\x08\x72\x65\x63\x2e\x74\x65\x73\x74\x30\x1e\x17\x0d\x31\x33\x30\x35\x31\x32\x31\x39\x34\x38\x30\x39\x5a\x17\x0d\x31\x33\x30\x36\x31\x31\x31\x39\x34\x38\x30\x39\x5a\x30\x13\x31\x11\x30\x0f\x06\x03\x55\x04\x03\x0c\x08\x72\x65\x63\x2e\x74\x65\x73\x74\x30\x81\x9f\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x81\x8d\x00\x30\x81\x89\x02\x81\x81\x00\xd2\x82\xbb\x96\x8d\xfd\xec\x0e\x5d\x13\xdf\xcc\x0a\x36\xed\x73\x17\x85\x81\x42\x4e\x10\xa3\x7c\x89\xd3\x01\x42\x04\x93\x3b\x3a\x8c\x11\x59\xfd\xec\xb2\x21\xaf\xe4\x16\x88\x83\xd2\xd0\x0a\xc1\xf1\x5f\xca\x46\x14\xfb\xd5\xe0\x5d\xe2\xe3\x7a\xd0\xfb\xad\x8b\x77\x48\xdd\xdb\xcf\x30\xb3\x9e\x80\x46\x6c\x61\xc7\x33\x41\x5e\x72\xb9\xf4\x2d\x5f\xad\x0b\xf3\x5f\x04\x1e\xb5\x63\x1e\xde\xd0\x03\x14\xc6\x6c\x48\x78\xb3\x51\x41\x6e\x5c\x6b\x90\x96\xf2\xa7\x08\x8a\x24\x38\x7e\x5d\x01\x49\xc5\x23\x73\x9f\x84\xf5\x02\xc7\x02\x03\x01\x00\x01\xa3\x50\x30\x4e\x30\x1d\x06\x03\x55\x1d\x0e\x04\x16\x04\x14\x73\x71\x5b\xbf\xd9\xbc\x2b\x82\x41\x12\xf8\x58\x58\x6f\x16\x6a\xaf\xb9\x94\x82\x30\x1f\x06\x03\x55\x1d\x23\x04\x18\x30\x16\x80\x14\x73\x71\x5b\xbf\xd9\xbc\x2b\x82\x41\x12\xf8\x58\x58\x6f\x16\x6a\xaf\xb9\x94\x82\x30\x0c\x06\x03\x55\x1d\x13\x04\x05\x30\x03\x01\x01\xff\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x03\x81\x81\x00\x55\x50\xf1\xd6\x41\x39\xab\x0e\x86\xc5\xb3\x03\xfc\x69\x01\x5d\x16\x76\xca\x95\x93\x10\x71\xae\x41\x88\x46\x56\xc7\x1c\x11\x6a\x38\x13\x8e\xcf\x63\x05\x4b\x35\x0d\xc7\x89\x83\xcb\x4a\x83\x28\x8d\xbc\x81\xc5\xa6\x59\xa5\x6c\xc6\x84\x3d\x54\x52\xc3\xe9\x84\x49\xb9\x4a\x0c\xf0\xc0\xcd\x71\x90\xc9\x6c\xaa\x5f\x0e\xe9\xa3\xbe\xf7\xe7\x50\x02\xbe\x4a\x23\x36\x73\x85\x2b\xdf\x1a\x5f\xd3\x06\xa7\x08\x0e\xb4\xfe\xad\x9b\x3a\xd1\x62\x07\x4b\x5f\x00\x7e\x91\x56\xe2\x20\x30\x2d\xea\x8c\x70\x08\x68\xa1\x25\x77\xe7\xc4"))
+ (CASE_S(QType::APL,"1:10.1.1.1/32", "\x00\x01\x20\x04\x0a\x01\x01\x01"))
+ (CASE_S(QType::APL,"1:10.1.1.0/24", "\x00\x01\x18\x03\x0a\x01\x01"))
+ (CASE_S(QType::APL,"1:60.0.0.0/8", "\x00\x01\x08\x01\x3c"))
+ (CASE_S(QType::APL,"1:10.1.1.1/32", "\x00\x01\x20\x04\x0a\x01\x01\x01"))
+ (CASE_S(QType::APL,"!1:10.1.1.1/32", "\x00\x01\x20\x84\x0a\x01\x01\x01"))
+ (CASE_S(QType::APL,"1:255.255.255.255/32", "\x00\x01\x20\x04\xff\xff\xff\xff"))
+ (CASE_S(QType::APL,"2:fe80::/8", "\x00\x02\x08\x02\xfe\x80"))
+ (CASE_S(QType::APL,"2:2001::1/32", "\x00\x02\x20\x10\x20\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"))
+ (CASE_S(QType::APL,"!2:2001::1/32", "\x00\x02\x20\x90\x20\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"))
+ (CASE_S(QType::APL,"2:fe80:1234:5678:9910:8bc:3359:b2e8:720e/32", "\x00\x02\x20\x10\xfe\x80\x12\x34\x56\x78\x99\x10\x08\xbc\x33\x59\xb2\xe8\x72\x0e"))
+ (CASE_S(QType::APL,"2:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/32","\x00\x02\x20\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"))
(CASE_L(QType::DS, "20642 8 2 04443ABE7E94C3985196BEAE5D548C727B044DDA5151E60D7CD76A9F D931D00E", "20642 8 2 04443abe7e94c3985196beae5d548c727b044dda5151e60d7cd76a9fd931d00e", "\x50\xa2\x08\x02\x04\x44\x3a\xbe\x7e\x94\xc3\x98\x51\x96\xbe\xae\x5d\x54\x8c\x72\x7b\x04\x4d\xda\x51\x51\xe6\x0d\x7c\xd7\x6a\x9f\xd9\x31\xd0\x0e"))
(CASE_S(QType::SSHFP, "1 1 aa65e3415a50d9b3519c2b17aceb815fc2538d88", "\x01\x01\xaa\x65\xe3\x41\x5a\x50\xd9\xb3\x51\x9c\x2b\x17\xac\xeb\x81\x5f\xc2\x53\x8d\x88"))
(CASE_L(QType::SSHFP, "1 1 aa65e3415a50d9b3519c2b17aceb815fc253 8d88", "1 1 aa65e3415a50d9b3519c2b17aceb815fc2538d88", "\x01\x01\xaa\x65\xe3\x41\x5a\x50\xd9\xb3\x51\x9c\x2b\x17\xac\xeb\x81\x5f\xc2\x53\x8d\x88"))