Skip to content

Commit

Permalink
Merge pull request #179 from zajdee/add_pref64_support
Browse files Browse the repository at this point in the history
Add pref64 support (RFC8781)
  • Loading branch information
robbat2 authored Jul 8, 2022
2 parents b0cb5a2 + 4f19ef0 commit a646066
Show file tree
Hide file tree
Showing 10 changed files with 309 additions and 0 deletions.
3 changes: 3 additions & 0 deletions defaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@
#define DFLT_DeprecatePrefixFlag 0
#define DFLT_DecrementLifetimesFlag 0

/* RFC8781 section 4.1; this is the non-scaled value (8191 << 3) */
#define DFLT_NAT64MaxValidLifetime 65528 /* seconds */

/* Each route has an associated: */
#define DFLT_AdvRouteLifetime(iface) (3 * (iface)->MaxRtrAdvInterval)

Expand Down
91 changes: 91 additions & 0 deletions gram.y
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
%token T_LOWPANCO
%token T_ABRO
%token T_RASRCADDRESS
%token T_NAT64PREFIX

%token <str> STRING
%token <num> NUMBER
Expand Down Expand Up @@ -138,6 +139,7 @@
%type <abroinfo> abrodef
%type <num> number_or_infinity
%type <rasrcaddressinfo> rasrcaddresslist v6addrlist_rasrcaddress
%type <nat64pinfo> nat64prefixdef

%union {
unsigned int num;
Expand All @@ -153,6 +155,7 @@
struct AdvLowpanCo *lowpancoinfo;
struct AdvAbro *abroinfo;
struct AdvRASrcAddress *rasrcaddressinfo;
struct NAT64Prefix *nat64pinfo;
};

%{
Expand All @@ -166,6 +169,7 @@ static struct AdvRDNSS *rdnss;
static struct AdvDNSSL *dnssl;
static struct AdvLowpanCo *lowpanco;
static struct AdvAbro *abro;
static struct NAT64Prefix *nat64prefix;
static void cleanup(void);
#define ABORT do { cleanup(); YYABORT; } while (0);
static void yyerror(char const * msg);
Expand Down Expand Up @@ -237,6 +241,7 @@ ifaceparam : ifaceval
| lowpancodef { ADD_TO_LL(struct AdvLowpanCo, AdvLowpanCoList, $1); }
| abrodef { ADD_TO_LL(struct AdvAbro, AdvAbroList, $1); }
| rasrcaddresslist { ADD_TO_LL(struct AdvRASrcAddress, AdvRASrcAddressList, $1); }
| nat64prefixdef { ADD_TO_LL(struct NAT64Prefix, NAT64PrefixList, $1); }
;

ifaceval : T_MinRtrAdvInterval NUMBER ';'
Expand Down Expand Up @@ -478,6 +483,92 @@ v6addrlist_rasrcaddress : IPV6ADDR ';'
}
;

nat64prefixdef : nat64prefixhead optional_nat64prefixplist ';'
{
if (nat64prefix) {

if (nat64prefix->AdvValidLifetime > DFLT_NAT64MaxValidLifetime)
{
flog(LOG_ERR, "AdvValidLifeTime must be "
"smaller or equal to %d in %s, line %d",
DFLT_NAT64MaxValidLifetime, filename, num_lines);
ABORT;
}
nat64prefix->curr_validlft = nat64prefix->AdvValidLifetime;
}
$$ = nat64prefix;
nat64prefix = NULL;
}
;

nat64prefixhead : T_NAT64PREFIX IPV6ADDR '/' NUMBER
{
struct in6_addr zeroaddr;
memset(&zeroaddr, 0, sizeof(zeroaddr));

if (!memcmp($2, &zeroaddr, sizeof(struct in6_addr))) {
flog(LOG_ERR, "invalid all-zeros nat64prefix in %s, line %d", filename, num_lines);
ABORT;
}

nat64prefix = malloc(sizeof(struct NAT64Prefix));

if (nat64prefix == NULL) {
flog(LOG_CRIT, "malloc failed: %s", strerror(errno));
ABORT;
}

nat64prefix_init_defaults(nat64prefix, iface);

if ($4 > MAX_PrefixLen)
{
flog(LOG_ERR, "invalid prefix length in %s, line %d", filename, num_lines);
ABORT;
}

/* RFC8781, section 4: only prefix lengths of 96, 64, 56, 48, 40, and 32 bits are valid */
switch ($4) {
case 32:
case 40:
case 48:
case 56:
case 64:
case 96:
break;
default:
flog(LOG_ERR, "only /96, /64, /56, /48, /40 and /32 are allowed for "
"nat64prefix in %s:%d", filename, num_lines);
ABORT;
}
nat64prefix->PrefixLen = $4;

memcpy(&nat64prefix->Prefix, $2, sizeof(struct in6_addr));
}
;

optional_nat64prefixplist: /* empty */
| '{' /* somewhat empty */ '}'
| '{' nat64prefixplist '}'
;

nat64prefixplist : nat64prefixplist nat64prefixparms
| nat64prefixparms
;

nat64prefixparms : T_AdvValidLifetime NUMBER ';'
{
if ($2 > DFLT_NAT64MaxValidLifetime)
{
flog(LOG_ERR, "maximum for NAT64 AdvValidLifetime is %d (in %s, line %d)",
DFLT_NAT64MaxValidLifetime, filename, num_lines);
ABORT;
}
if (nat64prefix) {
nat64prefix->AdvValidLifetime = $2;
}
}
;

prefixdef : prefixhead optional_prefixplist ';'
{
if (prefix) {
Expand Down
9 changes: 9 additions & 0 deletions interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,15 @@ void prefix_init_defaults(struct AdvPrefix *prefix)
prefix->curr_preferredlft = prefix->AdvPreferredLifetime;
}

void nat64prefix_init_defaults(struct NAT64Prefix *prefix, struct Interface *iface)
{
memset(prefix, 0, sizeof(struct NAT64Prefix));

prefix->AdvValidLifetime = min(DFLT_NAT64MaxValidLifetime, 3*(iface->MaxRtrAdvInterval));

prefix->curr_validlft = prefix->AdvValidLifetime;
}

void route_init_defaults(struct AdvRoute *route, struct Interface *iface)
{
memset(route, 0, sizeof(struct AdvRoute));
Expand Down
3 changes: 3 additions & 0 deletions process.c
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,9 @@ static void process_ra(struct Interface *iface, unsigned char *msg, int len, str
}
break;
}
case ND_OPT_PREF64:
/* not checked */
break;
default:
dlog(LOG_DEBUG, 1, "unknown option %d in RA on %s from %s", (int)*opt_str, iface->props.name, addr_str);
break;
Expand Down
1 change: 1 addition & 0 deletions radvd.8.man
Original file line number Diff line number Diff line change
Expand Up @@ -173,4 +173,5 @@ Reuben Hawkins <reubenhwk@gmail.com> - current maintainer
Pierre Ossman <pierre@ossman.eu> - RFC6106 (DNSSL) support
Varka Bhadram <varkabhadram@gmail.com> - 6LoWPAN-ND (RFC6775) support
Robin H. Johnson <robbat2@gentoo.org> - RA splitting per RFC 6980 & RFC4861#6.2.3
Radek Zajic <radek@zajic.v.pytli.cz> - NAT64 pref64 support (RFC8781)
.fi
44 changes: 44 additions & 0 deletions radvd.conf.5.man
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ The file contains one or more interface definitions of the form:
list of RDNSS definitions
list of DNSSL definitions
list of ABRO definitions
list of NAT64 pref64 definitions
list of acceptable RA source addresses
.B };
.fi
Expand Down Expand Up @@ -131,6 +132,18 @@ ABRO (Authoritative Border Router Option) definitions are of the form:
.B };
.fi

NAT64 pref64 (the NAT64 prefix included in the router advertisements):

.nf
.BR "nat64prefix " prefix / "length " {
list of NAT64 prefix specific options
.B };
.fi

The value of
.B length
can only be one of /32, /40, /48, /56, /64, or /96.

.SH INTERFACE SPECIFIC OPTIONS

.TP
Expand Down Expand Up @@ -627,6 +640,18 @@ A value of all zero bits assumes a default value of 10,000(~one week).
.BR "AdvVersionLow, AdvVersionHigh " unsigned integer
Both forms 32-bit unsigned version number corresponding to the set of information contained in RA message.

.SH NAT64 PREF64 SPECIFIC OPTIONS

.TP
.BR "AdvValidLifetime " seconds ""

The length of time in seconds (relative to the time the packet is
sent) that the prefix is valid for the purpose of NAT64 existence
determination. In case the value is not a multiple of 8, the validity
is rounded up to the next multiple of 8. The maximum is 65528 seconds.

Default: the lesser value of 3 * MaxRtrAdvInterval, or 65528

.SH EXAMPLES

.nf
Expand Down Expand Up @@ -746,6 +771,23 @@ interface lowpan0
};
};

The NAT64 pref64 support
.nf
interface eth0
{
prefix 2001:db8:100::/64 {
AdvOnLink on;
AdvAutonomous on;
AdvRouterAddr on;
};
nat64prefix 64:ff9b::/96 {
AdvValidLifeTime 1800;
};
RDNSS 2001:db8:100::64 {
AdvRDNSSLifetime 1800;
};
};

.SH FILES

.nf
Expand Down Expand Up @@ -798,6 +840,8 @@ RFC 7772, February 2016.
.PP
J. Jeong, S. Park, L. Beloeil, and S. Madanapalli, "IPv6 Router Advertisement Options for DNS Configuration",
RFC 8106, March 2017.
L. Colitti, and J. Linkova, "Discovering PREF64 in Router Advertisements",
RFC 8781, April 2020.

.SH "SEE ALSO"

Expand Down
26 changes: 26 additions & 0 deletions radvd.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ extern int disableigmp6check;
#define min(a, b) (((a) < (b)) ? (a) : (b))

struct AdvPrefix;
struct NAT64Prefix;
struct Clients;

#define HWADDR_MAX 16
Expand Down Expand Up @@ -104,6 +105,8 @@ struct Interface {
struct AdvRDNSS *AdvRDNSSList;
struct AdvDNSSL *AdvDNSSLList;

struct NAT64Prefix *NAT64PrefixList;

uint32_t AdvLinkMTU; /* XXX: sllao also has an if_maxmtu value...Why? */
uint32_t AdvRAMTU; /* MTU used for RA */

Expand Down Expand Up @@ -166,6 +169,16 @@ struct AdvPrefix {
struct AdvPrefix *next;
};

struct NAT64Prefix {
struct in6_addr Prefix;
uint8_t PrefixLen;

uint32_t AdvValidLifetime;
uint32_t curr_validlft;

struct NAT64Prefix *next;
};

/* More-Specific Routes extensions */

struct AdvRoute {
Expand Down Expand Up @@ -269,6 +282,18 @@ struct nd_opt_6co {
struct in6_addr nd_opt_6co_con_prefix;
}; /*Added by Bhadram */

/* Pref64 option type (RFC8781, section 4) */
#ifndef ND_OPT_PREF64
#define ND_OPT_PREF64 38
#endif

struct nd_opt_nat64prefix_info {
uint8_t nd_opt_pi_type;
uint8_t nd_opt_pi_len;
uint16_t nd_opt_pi_lifetime_preflen;
unsigned char nd_opt_pi_nat64prefix[12];
};

/* gram.y */
struct Interface *readin_config(char const *fname);

Expand Down Expand Up @@ -308,6 +333,7 @@ struct Interface *find_iface_by_time(struct Interface *iface_list);
void dnssl_init_defaults(struct AdvDNSSL *, struct Interface *);
void for_each_iface(struct Interface *ifaces, void (*foo)(struct Interface *iface, void *), void *data);
void free_ifaces(struct Interface *ifaces);
void nat64prefix_init_defaults(struct NAT64Prefix *, struct Interface *);
void iface_init_defaults(struct Interface *);
void prefix_init_defaults(struct AdvPrefix *);
void rdnss_init_defaults(struct AdvRDNSS *, struct Interface *);
Expand Down
49 changes: 49 additions & 0 deletions radvdump.c
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,8 @@ static void print_ff(unsigned char *msg, int len, struct sockaddr_in6 *addr, int
break;
case ND_OPT_DNSSL_INFORMATION:
break;
case ND_OPT_PREF64:
break;
default:
dlog(LOG_DEBUG, 1, "unknown option %d in RA", (int)*opt_str);
break;
Expand Down Expand Up @@ -466,6 +468,53 @@ static void print_ff(unsigned char *msg, int len, struct sockaddr_in6 *addr, int
printf("\t}; # End of DNSSL definition\n\n");
break;
}
case ND_OPT_PREF64: {
if (optlen != sizeof(struct nd_opt_nat64prefix_info)) {
flog(LOG_ERR, "incorrect pref64 option length in RA from %s, skipping", addr_str);
break;
}

struct nd_opt_nat64prefix_info *pinfo = (struct nd_opt_nat64prefix_info *)opt_str;
uint16_t lifetime_preflen = ntohs(pinfo->nd_opt_pi_lifetime_preflen);
uint8_t prefix_length_code = lifetime_preflen & 7;
uint16_t prefix_lifetime = lifetime_preflen & 0xFFF8;
int prefix_size = -1;
struct in6_addr nat64prefix;

/* The option only contains the first 96 bits of the prefix */
memset(&nat64prefix, 0, sizeof(nat64prefix));
memcpy(&nat64prefix, &pinfo->nd_opt_pi_nat64prefix, 12);
addrtostr(&nat64prefix, prefix_str, sizeof(prefix_str));

switch (prefix_length_code) {
case 0:
prefix_size = 96;
break;
case 1:
prefix_size = 64;
break;
case 2:
prefix_size = 56;
break;
case 3:
prefix_size = 48;
break;
case 4:
prefix_size = 40;
break;
case 5:
prefix_size = 32;
break;
default:
flog(LOG_ERR, "Invalid (reserved) nat64prefix length code %d received", prefix_length_code);
}

printf("\n\tnat64prefix %s/%d\n\t{\n", prefix_str, prefix_size);
printf("\t\tAdvValidLifetime %u;\n", prefix_lifetime);
printf("\t}; # End of nat64prefix definition\n\n");

break;
}
default:
break;
}
Expand Down
2 changes: 2 additions & 0 deletions scanner.l
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ DNSSL { return T_DNSSL; }
clients { return T_CLIENTS; }
lowpanco { return T_LOWPANCO; }
abro { return T_ABRO; }
nat64prefix { return T_NAT64PREFIX; }
AdvRASrcAddress { return T_RASRCADDRESS; }
IgnoreIfMissing { return T_IgnoreIfMissing; }
Expand Down
Loading

0 comments on commit a646066

Please sign in to comment.