Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RDNSS: support more ipv6 addresses #193

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions defaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -205,9 +205,7 @@ struct nd_opt_rdnss_info_local {
uint8_t nd_opt_rdnssi_len;
uint16_t nd_opt_rdnssi_pref_flag_reserved;
uint32_t nd_opt_rdnssi_lifetime;
struct in6_addr nd_opt_rdnssi_addr1;
struct in6_addr nd_opt_rdnssi_addr2;
struct in6_addr nd_opt_rdnssi_addr3;
struct in6_addr nd_opt_rdnssi_addr[];
};
/* pref/flag/reserved field : yyyyx00000000000 (big endian) - 00000000yyyyx000 (little indian); where yyyy = pref, x = flag */
#if BYTE_ORDER == BIG_ENDIAN
Expand Down
26 changes: 9 additions & 17 deletions gram.y
Original file line number Diff line number Diff line change
Expand Up @@ -790,24 +790,15 @@ rdnssaddr : IPV6ADDR
rdnss_init_defaults(rdnss, iface);
}

switch (rdnss->AdvRDNSSNumber) {
case 0:
memcpy(&rdnss->AdvRDNSSAddr1, $1, sizeof(struct in6_addr));
rdnss->AdvRDNSSNumber++;
break;
case 1:
memcpy(&rdnss->AdvRDNSSAddr2, $1, sizeof(struct in6_addr));
rdnss->AdvRDNSSNumber++;
break;
case 2:
memcpy(&rdnss->AdvRDNSSAddr3, $1, sizeof(struct in6_addr));
rdnss->AdvRDNSSNumber++;
break;
default:
flog(LOG_CRIT, "too many addresses in RDNSS section");
ABORT;
rdnss->AdvRDNSSNumber++;
rdnss->AdvRDNSSAddr =
realloc(rdnss->AdvRDNSSAddr,
rdnss->AdvRDNSSNumber * sizeof(struct in6_addr));
if (rdnss->AdvRDNSSAddr == NULL) {
flog(LOG_CRIT, "realloc failed: %s", strerror(errno));
ABORT;
}

memcpy(&rdnss->AdvRDNSSAddr[rdnss->AdvRDNSSNumber - 1], $1, sizeof(struct in6_addr));
}
;

Expand Down Expand Up @@ -1070,6 +1061,7 @@ static void cleanup(void)
}

if (rdnss) {
free(rdnss->AdvRDNSSAddr);
free(rdnss);
rdnss = 0;
}
Expand Down
1 change: 1 addition & 0 deletions interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,7 @@ static void free_iface_list(struct Interface *iface)
while (rdnss) {
struct AdvRDNSS *next_rdnss = rdnss->next;

free(rdnss->AdvRDNSSAddr);
free(rdnss);
rdnss = next_rdnss;
}
Expand Down
45 changes: 11 additions & 34 deletions process.c
Original file line number Diff line number Diff line change
Expand Up @@ -322,44 +322,21 @@ static void process_ra(struct Interface *iface, unsigned char *msg, int len, str
break;
case ND_OPT_RDNSS_INFORMATION: {
char rdnss_str[INET6_ADDRSTRLEN];
struct AdvRDNSS *rdnss = 0;
struct nd_opt_rdnss_info_local *rdnssinfo = (struct nd_opt_rdnss_info_local *)opt_str;
if (len < sizeof(*rdnssinfo))
return;
int count = rdnssinfo->nd_opt_rdnssi_len;

/* Check the RNDSS addresses received */
switch (count) {
case 7:
rdnss = iface->AdvRDNSSList;
if (!check_rdnss_presence(rdnss, &rdnssinfo->nd_opt_rdnssi_addr3)) {
/* no match found in iface->AdvRDNSSList */
addrtostr(&rdnssinfo->nd_opt_rdnssi_addr3, rdnss_str, sizeof(rdnss_str));
flog(LOG_WARNING, "RDNSS address %s received on %s from %s is not advertised by us",
rdnss_str, iface->props.name, addr_str);
}
/* FALLTHROUGH */
case 5:
rdnss = iface->AdvRDNSSList;
if (!check_rdnss_presence(rdnss, &rdnssinfo->nd_opt_rdnssi_addr2)) {
/* no match found in iface->AdvRDNSSList */
addrtostr(&rdnssinfo->nd_opt_rdnssi_addr2, rdnss_str, sizeof(rdnss_str));
flog(LOG_WARNING, "RDNSS address %s received on %s from %s is not advertised by us",
rdnss_str, iface->props.name, addr_str);
}
/* FALLTHROUGH */
case 3:
rdnss = iface->AdvRDNSSList;
if (!check_rdnss_presence(rdnss, &rdnssinfo->nd_opt_rdnssi_addr1)) {
/* no match found in iface->AdvRDNSSList */
addrtostr(&rdnssinfo->nd_opt_rdnssi_addr1, rdnss_str, sizeof(rdnss_str));
flog(LOG_WARNING, "RDNSS address %s received on %s from %s is not advertised by us",
rdnss_str, iface->props.name, addr_str);
}

break;
default:
flog(LOG_ERR, "invalid len %i in RDNSS option on %s from %s", count, iface->props.name, addr_str);
if (rdnssinfo->nd_opt_rdnssi_len > 2) {
for (int i = 0; i < (rdnssinfo->nd_opt_rdnssi_len - 1) / 2; i++) {
if (!check_rdnss_presence(iface->AdvRDNSSList, &rdnssinfo->nd_opt_rdnssi_addr[i])) {
addrtostr(&rdnssinfo->nd_opt_rdnssi_addr[i], rdnss_str, sizeof(rdnss_str));
flog(LOG_WARNING, "RDNSS address %s received on %s from %s is not advertised by us",
rdnss_str, iface->props.name, addr_str);
}
}
} else {
flog(LOG_ERR, "invalid len %i in RDNSS option on %s from %s",
rdnssinfo->nd_opt_rdnssi_len, iface->props.name, addr_str);
}

break;
Expand Down
4 changes: 1 addition & 3 deletions radvd.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,9 +198,7 @@ struct AdvRDNSS {
int AdvRDNSSNumber;
uint32_t AdvRDNSSLifetime;
int FlushRDNSSFlag;
struct in6_addr AdvRDNSSAddr1;
struct in6_addr AdvRDNSSAddr2;
struct in6_addr AdvRDNSSAddr3;
struct in6_addr *AdvRDNSSAddr;

struct AdvRDNSS *next;
};
Expand Down
11 changes: 2 additions & 9 deletions radvdump.c
Original file line number Diff line number Diff line change
Expand Up @@ -402,15 +402,8 @@ static void print_ff(unsigned char *msg, int len, struct sockaddr_in6 *addr, int

printf("\n\tRDNSS");

addrtostr(&rdnss_info->nd_opt_rdnssi_addr1, prefix_str, sizeof(prefix_str));
printf(" %s", prefix_str);

if (rdnss_info->nd_opt_rdnssi_len >= 5) {
addrtostr(&rdnss_info->nd_opt_rdnssi_addr2, prefix_str, sizeof(prefix_str));
printf(" %s", prefix_str);
}
if (rdnss_info->nd_opt_rdnssi_len >= 7) {
addrtostr(&rdnss_info->nd_opt_rdnssi_addr3, prefix_str, sizeof(prefix_str));
for (int i = 0; i < (rdnss_info->nd_opt_rdnssi_len - 1) / 2; i++) {
addrtostr(&rdnss_info->nd_opt_rdnssi_addr[i], prefix_str, sizeof(prefix_str));
printf(" %s", prefix_str);
}

Expand Down
21 changes: 15 additions & 6 deletions send.c
Original file line number Diff line number Diff line change
Expand Up @@ -579,8 +579,10 @@ static struct safe_buffer_list *add_ra_options_route(struct safe_buffer_list *sb
static struct safe_buffer_list *add_ra_options_rdnss(struct safe_buffer_list *sbl, struct Interface const *iface,
struct AdvRDNSS const *rdnss, int cease_adv, struct in6_addr const *dest)
{
struct safe_buffer *rdnss_addr = new_safe_buffer();
while (rdnss) {
struct nd_opt_rdnss_info_local rdnssinfo;
rdnss_addr->used = 0;

if (!cease_adv && !schedule_option_rdnss(dest, iface, rdnss)) {
rdnss = rdnss->next;
Expand All @@ -589,6 +591,12 @@ static struct safe_buffer_list *add_ra_options_rdnss(struct safe_buffer_list *sb

memset(&rdnssinfo, 0, sizeof(rdnssinfo));

size_t const bytes = sizeof(rdnssinfo) + sizeof(struct in6_addr) * rdnss->AdvRDNSSNumber;
if (bytes > (256 * 8)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you pick 2048?

  • 1280 bytes is the min IPv6 MTU; what would happen in that case?
  • can radvd safely send multiple RA packets with different RDNSS entries? (other framework code for example splits large options into their own packets)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in my opinion
1、The IPv6 MTU value may change the processing of the kernel protocol stack.
2、RDNSS 2048 is consistent with DNSSL packet maximum in radvd

Do you have any good suggestions for me?

flog(LOG_ERR, "RDNSS too long for RA option, must be < 2048 bytes. Exiting.");
exit(1);
}

rdnssinfo.nd_opt_rdnssi_type = ND_OPT_RDNSS_INFORMATION;
rdnssinfo.nd_opt_rdnssi_len = 1 + 2 * rdnss->AdvRDNSSNumber;
rdnssinfo.nd_opt_rdnssi_pref_flag_reserved = 0;
Expand All @@ -599,16 +607,17 @@ static struct safe_buffer_list *add_ra_options_rdnss(struct safe_buffer_list *sb
rdnssinfo.nd_opt_rdnssi_lifetime = htonl(rdnss->AdvRDNSSLifetime);
}

memcpy(&rdnssinfo.nd_opt_rdnssi_addr1, &rdnss->AdvRDNSSAddr1, sizeof(struct in6_addr));
memcpy(&rdnssinfo.nd_opt_rdnssi_addr2, &rdnss->AdvRDNSSAddr2, sizeof(struct in6_addr));
memcpy(&rdnssinfo.nd_opt_rdnssi_addr3, &rdnss->AdvRDNSSAddr3, sizeof(struct in6_addr));

sbl = safe_buffer_list_append(sbl);
safe_buffer_append(sbl->sb, &rdnssinfo,
sizeof(rdnssinfo) - (3 - rdnss->AdvRDNSSNumber) * sizeof(struct in6_addr));
safe_buffer_append(sbl->sb, &rdnssinfo, sizeof(rdnssinfo));
for (int i = 0; i < rdnss->AdvRDNSSNumber; i++) {
safe_buffer_append(rdnss_addr, &rdnss->AdvRDNSSAddr[i], sizeof(struct in6_addr));
}
safe_buffer_append(sbl->sb, rdnss_addr->buffer, rdnss_addr->used);
safe_buffer_free(rdnss_addr);

rdnss = rdnss->next;
}
safe_buffer_free(rdnss_addr);

return sbl;
}
Expand Down
8 changes: 4 additions & 4 deletions util.c
Original file line number Diff line number Diff line change
Expand Up @@ -191,10 +191,10 @@ void addrtostr(struct in6_addr const *addr, char *str, size_t str_size)
int check_rdnss_presence(struct AdvRDNSS *rdnss, struct in6_addr *addr)
{
while (rdnss) {
if (!memcmp(&rdnss->AdvRDNSSAddr1, addr, sizeof(struct in6_addr)) ||
!memcmp(&rdnss->AdvRDNSSAddr2, addr, sizeof(struct in6_addr)) ||
!memcmp(&rdnss->AdvRDNSSAddr3, addr, sizeof(struct in6_addr)))
return 1; /* rdnss address found in the list */
for (int i = 0; i < rdnss->AdvRDNSSNumber; i++) {
if (!memcmp(&rdnss->AdvRDNSSAddr[i], addr, sizeof(struct in6_addr)))
return 1; /* rdnss address found in the list */
}
rdnss = rdnss->next;
}
return 0;
Expand Down