Skip to content

Commit cb15d70

Browse files
committed
Add support for APL RR
1 parent ed2e91b commit cb15d70

File tree

9 files changed

+201
-14
lines changed

9 files changed

+201
-14
lines changed

src/fallback/ip4.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,41 @@
99
#ifndef IP4_H
1010
#define IP4_H
1111

12+
zone_nonnull_all
13+
static zone_really_inline int32_t scan_ip4(
14+
const char *text, uint8_t *wire, size_t *length)
15+
{
16+
const char *start = text;
17+
uint32_t round = 0;
18+
for (;;) {
19+
uint8_t digits[3];
20+
uint32_t octet;
21+
digits[0] = (uint8_t)text[0] - '0';
22+
digits[1] = (uint8_t)text[1] - '0';
23+
digits[2] = (uint8_t)text[2] - '0';
24+
if (digits[0] > 9)
25+
return -1;
26+
else if (digits[1] > 9)
27+
(void)(text += 1), octet = digits[0];
28+
else if (digits[2] > 9)
29+
(void)(text += 2), octet = digits[0] * 10 + digits[1];
30+
else
31+
(void)(text += 3), octet = digits[0] * 100 + digits[1] * 10 + digits[2];
32+
33+
if (octet > 255)
34+
return -1;
35+
wire[round++] = (uint8_t)octet;
36+
if (text[0] != '.' || round == 4)
37+
break;
38+
text += 1;
39+
}
40+
41+
if (round != 4)
42+
return -1;
43+
*length = (uintptr_t)text - (uintptr_t)start;
44+
return 4;
45+
}
46+
1247
zone_nonnull_all
1348
static zone_really_inline int32_t parse_ip4(
1449
zone_parser_t *parser,

src/fallback/parser.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "generic/wks.h"
3131
#include "generic/loc.h"
3232
#include "generic/gpos.h"
33+
#include "generic/apl.h"
3334
#include "types.h"
3435
#include "fallback/type.h"
3536
#include "parser.h"

src/generic/apl.h

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* apl.h -- Address Prefix Lists (RFC3123) parser
3+
*
4+
* Copyright (c) 2023, NLnet Labs. All rights reserved.
5+
*
6+
* SPDX-License-Identifier: BSD-3-Clause
7+
*
8+
*/
9+
#ifndef APL_H
10+
#define APL_H
11+
12+
static zone_really_inline int32_t scan_apl(
13+
const char *text, size_t length, uint8_t *octets, size_t size)
14+
{
15+
uint8_t negate = text[0] == '!';
16+
uint8_t digits[3];
17+
size_t count;
18+
uint32_t prefix;
19+
const uint8_t af_inet[2] = { 0x01, 0x00 }, af_inet6[2] = { 0x02, 0x00 };
20+
21+
// address family is immediately followed by a colon ":"
22+
if (text[negate + 1] != ':')
23+
return -1;
24+
25+
switch (text[negate]) {
26+
case '1':
27+
if (size < 8)
28+
return -1;
29+
memcpy(octets, af_inet, sizeof(af_inet));
30+
if (scan_ip4(&text[negate+2], &octets[4], &count) == -1)
31+
return -1;
32+
count += negate + 2;
33+
digits[0] = (uint8_t)text[count+1] - '0';
34+
digits[1] = (uint8_t)text[count+2] - '0';
35+
if (text[count] != '/' || digits[0] > 9)
36+
return -1;
37+
if (digits[1] > 9)
38+
(void)(count += 2), prefix = digits[0];
39+
else
40+
(void)(count += 3), prefix = digits[0] * 10 + digits[1];
41+
if (prefix > 32 || (size_t)count != length)
42+
return -1;
43+
octets[2] = (uint8_t)prefix;
44+
octets[3] = (uint8_t)((negate << 7) | 4);
45+
return 8;
46+
case '2':
47+
if (size < 20)
48+
return -1;
49+
memcpy(octets, af_inet6, sizeof(af_inet6));
50+
if (scan_ip6(text, &octets[4], &count) == -1)
51+
return -1;
52+
count += negate + 2;
53+
digits[0] = (uint8_t)text[count+1] - '0';
54+
digits[1] = (uint8_t)text[count+2] - '0';
55+
digits[2] = (uint8_t)text[count+3] - '0';
56+
if (text[count] != '/' || digits[0] > 9)
57+
return -1;
58+
if (digits[1] > 9)
59+
(void)(count += 2), prefix = digits[0];
60+
else if (digits[2] > 9)
61+
(void)(count += 3), prefix = digits[0] * 10 + digits[1];
62+
else
63+
(void)(count += 4), prefix = digits[0] * 100 + digits[1] * 10 + digits[0];
64+
if (prefix > 128 || (size_t)count != length)
65+
return -1;
66+
octets[2] = (uint8_t)prefix;
67+
octets[3] = (uint8_t)((negate << 7) | 16);
68+
return 20;
69+
default:
70+
return -1;
71+
}
72+
}
73+
74+
#endif // APL_H

src/generic/ip6.h

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ inet_pton4(const char *src, uint8_t *dst)
3737
static const char digits[] = "0123456789";
3838
int saw_digit, octets, ch;
3939
uint8_t tmp[NS_INADDRSZ], *tp;
40+
const char *start = src;
4041

4142
saw_digit = 0;
4243
octets = 0;
@@ -48,11 +49,11 @@ inet_pton4(const char *src, uint8_t *dst)
4849
uint32_t new = *tp * 10 + (uint32_t)(pch - digits);
4950

5051
if (new > 255)
51-
return (0);
52+
return -1;
5253
*tp = (uint8_t)new;
5354
if (! saw_digit) {
5455
if (++octets > 4)
55-
return (0);
56+
return -1;
5657
saw_digit = 1;
5758
}
5859
} else if (ch == '.' && saw_digit) {
@@ -61,13 +62,13 @@ inet_pton4(const char *src, uint8_t *dst)
6162
*++tp = 0;
6263
saw_digit = 0;
6364
} else
64-
return (0);
65+
break;
6566
}
6667
if (octets < 4)
67-
return (0);
68+
return -1;
6869

6970
memcpy(dst, tmp, NS_INADDRSZ);
70-
return (1);
71+
return (int)(src - start);
7172
}
7273

7374
/* int
@@ -92,14 +93,16 @@ inet_pton6(const char *src, uint8_t *dst)
9293
const char *xdigits, *curtok;
9394
int ch, saw_xdigit;
9495
uint32_t val;
96+
int len;
97+
const char *start = src;
9598

9699
memset((tp = tmp), '\0', NS_IN6ADDRSZ);
97100
endp = tp + NS_IN6ADDRSZ;
98101
colonp = NULL;
99102
/* Leading :: requires some special handling. */
100103
if (*src == ':')
101104
if (*++src != ':')
102-
return (0);
105+
return -1;
103106
curtok = src;
104107
saw_xdigit = 0;
105108
val = 0;
@@ -112,7 +115,7 @@ inet_pton6(const char *src, uint8_t *dst)
112115
val <<= 4;
113116
val |= (pch - xdigits);
114117
if (val > 0xffff)
115-
return (0);
118+
return -1;
116119
saw_xdigit = 1;
117120
continue;
118121
}
@@ -133,16 +136,17 @@ inet_pton6(const char *src, uint8_t *dst)
133136
continue;
134137
}
135138
if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
136-
inet_pton4(curtok, tp) > 0) {
139+
(len = inet_pton4(curtok, tp)) > 0) {
140+
src += len;
137141
tp += NS_INADDRSZ;
138142
saw_xdigit = 0;
139143
break; /* '\0' was seen by inet_pton4(). */
140144
}
141-
return (0);
145+
return -1;
142146
}
143147
if (saw_xdigit) {
144148
if (tp + NS_INT16SZ > endp)
145-
return (0);
149+
return -1;
146150
*tp++ = (uint8_t) (val >> 8) & 0xff;
147151
*tp++ = (uint8_t) val & 0xff;
148152
}
@@ -161,9 +165,20 @@ inet_pton6(const char *src, uint8_t *dst)
161165
tp = endp;
162166
}
163167
if (tp != endp)
164-
return (0);
168+
return -1;
165169
memcpy(dst, tmp, NS_IN6ADDRSZ);
166-
return (1);
170+
return (int)(src - start);
171+
}
172+
173+
zone_nonnull_all
174+
static zone_really_inline int32_t scan_ip6(
175+
const char *text, uint8_t *wire, size_t *length)
176+
{
177+
int len = inet_pton6(text, wire);
178+
if (len == -1)
179+
return -1;
180+
*length = (size_t)len;
181+
return 16;
167182
}
168183

169184
zone_nonnull_all
@@ -178,7 +193,7 @@ static zone_really_inline int32_t parse_ip6(
178193
if ((r = have_contiguous(parser, type, field, token)) < 0)
179194
return r;
180195

181-
if (inet_pton6(token->data, &parser->rdata->octets[parser->rdata->length]) == 1) {
196+
if (inet_pton6(token->data, &parser->rdata->octets[parser->rdata->length]) != -1) {
182197
parser->rdata->length += 16;
183198
return ZONE_IP6;
184199
}

src/haswell/parser.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "generic/wks.h"
3333
#include "generic/loc.h"
3434
#include "generic/gpos.h"
35+
#include "generic/apl.h"
3536
#include "types.h"
3637
#include "westmere/type.h"
3738
#include "parser.h"

src/types.h

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1191,6 +1191,41 @@ static int32_t parse_cert_rdata(
11911191
return accept_rr(parser, type);
11921192
}
11931193

1194+
zone_nonnull_all
1195+
static int32_t check_apl_rr(
1196+
zone_parser_t *parser, const zone_type_info_t *type)
1197+
{
1198+
// FIXME: check correctness of fields and total length
1199+
return accept_rr(parser, type);
1200+
}
1201+
1202+
zone_nonnull_all
1203+
static int32_t parse_apl_rdata(
1204+
zone_parser_t *parser, const zone_type_info_t *type, token_t *token)
1205+
{
1206+
int32_t code;
1207+
uint8_t *octets = parser->rdata->octets;
1208+
size_t size = ZONE_RDATA_SIZE;
1209+
1210+
// RDATA section for APL consists of zero or more items
1211+
while (token->code == CONTIGUOUS) {
1212+
int32_t length;
1213+
if ((length = scan_apl(token->data, token->length, octets, size)) < 0)
1214+
SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(&type->rdata.fields[0]), TNAME(type));
1215+
assert(length == 8 /* ipv4 */ || length == 20 /* ipv6 */);
1216+
size -= (size_t)length;
1217+
octets += (size_t)length;
1218+
lex(parser, token);
1219+
}
1220+
1221+
parser->rdata->length = ZONE_RDATA_SIZE - size;
1222+
1223+
if ((code = have_delimiter(parser, type, token)) < 0)
1224+
return code;
1225+
1226+
return accept_rr(parser, type);
1227+
}
1228+
11941229
zone_nonnull_all
11951230
static int32_t check_ds_rr(
11961231
zone_parser_t *parser, const zone_type_info_t *type)
@@ -2285,6 +2320,10 @@ static const zone_field_info_t dname_rdata_fields[] = {
22852320
FIELD("source", ZONE_NAME, 0)
22862321
};
22872322

2323+
static const zone_field_info_t apl_rdata_fields[] = {
2324+
FIELD("prefix", ZONE_INT16, 0)
2325+
};
2326+
22882327
static const zone_symbol_t ds_digest_type_symbols[] = {
22892328
SYMBOL("GOST", 3),
22902329
SYMBOL("SHA-1", 1),
@@ -2551,8 +2590,9 @@ static const type_descriptor_t types[] = {
25512590

25522591
UNKNOWN_TYPE(40),
25532592
UNKNOWN_TYPE(41),
2554-
UNKNOWN_TYPE(42),
25552593

2594+
TYPE("APL", ZONE_APL, ZONE_IN, FIELDS(apl_rdata_fields),
2595+
check_apl_rr, parse_apl_rdata),
25562596
TYPE("DS", ZONE_DS, ZONE_ANY, FIELDS(ds_rdata_fields),
25572597
check_ds_rr, parse_ds_rdata),
25582598
TYPE("SSHFP", ZONE_SSHFP, ZONE_ANY, FIELDS(sshfp_rdata_fields),

src/westmere/ip4.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,17 @@ static inline int sse_inet_aton(const char* ipv4_string, uint8_t* destination, s
180180
return (int)(length + check_mask - pattern_ptr[6]);
181181
}
182182

183+
zone_nonnull_all
184+
static zone_really_inline int32_t scan_ip4(
185+
const char *text, uint8_t *wire, size_t *length)
186+
{
187+
size_t len;
188+
if (sse_inet_aton(text, wire, &len) != 1)
189+
return -1;
190+
*length = len;
191+
return 4;
192+
}
193+
183194
zone_nonnull_all
184195
static zone_really_inline int32_t parse_ip4(
185196
zone_parser_t *parser,

src/westmere/parser.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "generic/wks.h"
3333
#include "generic/loc.h"
3434
#include "generic/gpos.h"
35+
#include "generic/apl.h"
3536
#include "types.h"
3637
#include "westmere/type.h"
3738
#include "parser.h"

tests/types.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,14 @@ static const char dname_generic_text[] =
334334
PAD(" DNAME \\# 18 04686f7374076578616d706c6503636f6d00");
335335
static const rdata_t dname_rdata = RDATA(HOST_EXAMPLE_COM);
336336

337+
static const char apl_text[] =
338+
PAD("foo.example. IN APL 1:192.168.32.0/21 !1:192.168.38.0/28");
339+
static const rdata_t apl_rdata =
340+
RDATA(/* 1:192.168.32.0/21 */
341+
1, 0, 21, 0x04, 192, 168, 32, 0,
342+
/* !1:192.168.38.0/28 */
343+
1, 0, 28, 0x84, 192, 168, 38, 0);
344+
337345
static const char sshfp_text[] =
338346
PAD(" SSHFP 4 2 123456789abcdef67890123456789abcdef67890123456789abcdef123456789");
339347
static const char sshfp_generic_text[] =
@@ -816,6 +824,7 @@ static const test_t tests[] = {
816824
{ ZONE_CERT, cert_text, &cert_rdata },
817825
{ ZONE_DNAME, dname_text, &dname_rdata },
818826
{ ZONE_DNAME, dname_generic_text, &dname_rdata },
827+
{ ZONE_APL, apl_text, &apl_rdata },
819828
{ ZONE_SSHFP, sshfp_text, &sshfp_rdata },
820829
{ ZONE_SSHFP, sshfp_generic_text, &sshfp_rdata },
821830
{ ZONE_IPSECKEY, ipseckey_text, &ipseckey_rdata },

0 commit comments

Comments
 (0)