version 1.1.1.4, 2021/03/17 00:56:46
|
version 1.1.1.5, 2023/09/27 11:02:07
|
Line 1
|
Line 1
|
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley | /* dnsmasq is Copyright (c) 2000-2022 Simon Kelley |
|
|
This program is free software; you can redistribute it and/or modify |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
it under the terms of the GNU General Public License as published by |
Line 33 struct state {
|
Line 33 struct state {
|
unsigned int mac_len, mac_type; |
unsigned int mac_len, mac_type; |
}; |
}; |
|
|
static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz, | static int dhcp6_maybe_relay(struct state *state, unsigned char *inbuff, size_t sz, |
struct in6_addr *client_addr, int is_unicast, time_t now); |
struct in6_addr *client_addr, int is_unicast, time_t now); |
static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_t sz, int is_unicast, time_t now); | static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbuff, size_t sz, int is_unicast, time_t now); |
static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_opts); |
static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_opts); |
static void log6_packet(struct state *state, char *type, struct in6_addr *addr, char *string); |
static void log6_packet(struct state *state, char *type, struct in6_addr *addr, char *string); |
static void log6_quiet(struct state *state, char *type, struct in6_addr *addr, char *string); |
static void log6_quiet(struct state *state, char *type, struct in6_addr *addr, char *string); |
Line 104 unsigned short dhcp6_reply(struct dhcp_context *contex
|
Line 104 unsigned short dhcp6_reply(struct dhcp_context *contex
|
} |
} |
|
|
/* This cost me blood to write, it will probably cost you blood to understand - srk. */ |
/* This cost me blood to write, it will probably cost you blood to understand - srk. */ |
static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz, | static int dhcp6_maybe_relay(struct state *state, unsigned char *inbuff, size_t sz, |
struct in6_addr *client_addr, int is_unicast, time_t now) |
struct in6_addr *client_addr, int is_unicast, time_t now) |
{ |
{ |
void *end = inbuff + sz; |
void *end = inbuff + sz; |
void *opts = inbuff + 34; |
void *opts = inbuff + 34; |
int msg_type = *((unsigned char *)inbuff); | int msg_type = *inbuff; |
unsigned char *outmsgtypep; |
unsigned char *outmsgtypep; |
void *opt; |
void *opt; |
struct dhcp_vendor *vendor; |
struct dhcp_vendor *vendor; |
Line 259 static int dhcp6_maybe_relay(struct state *state, void
|
Line 259 static int dhcp6_maybe_relay(struct state *state, void
|
return 1; |
return 1; |
} |
} |
|
|
static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_t sz, int is_unicast, time_t now) | static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbuff, size_t sz, int is_unicast, time_t now) |
{ |
{ |
void *opt; |
void *opt; |
int i, o, o1, start_opts; | int i, o, o1, start_opts, start_msg; |
struct dhcp_opt *opt_cfg; |
struct dhcp_opt *opt_cfg; |
struct dhcp_netid *tagif; |
struct dhcp_netid *tagif; |
struct dhcp_config *config = NULL; |
struct dhcp_config *config = NULL; |
struct dhcp_netid known_id, iface_id, v6_id; |
struct dhcp_netid known_id, iface_id, v6_id; |
unsigned char *outmsgtypep; | unsigned char outmsgtype; |
struct dhcp_vendor *vendor; |
struct dhcp_vendor *vendor; |
struct dhcp_context *context_tmp; |
struct dhcp_context *context_tmp; |
struct dhcp_mac *mac_opt; |
struct dhcp_mac *mac_opt; |
Line 296 static int dhcp6_no_relay(struct state *state, int msg
|
Line 296 static int dhcp6_no_relay(struct state *state, int msg
|
v6_id.next = state->tags; |
v6_id.next = state->tags; |
state->tags = &v6_id; |
state->tags = &v6_id; |
|
|
/* copy over transaction-id, and save pointer to message type */ | start_msg = save_counter(-1); |
if (!(outmsgtypep = put_opt6(inbuff, 4))) | /* copy over transaction-id */ |
| if (!put_opt6(inbuff, 4)) |
return 0; |
return 0; |
start_opts = save_counter(-1); |
start_opts = save_counter(-1); |
state->xid = outmsgtypep[3] | outmsgtypep[2] << 8 | outmsgtypep[1] << 16; | state->xid = inbuff[3] | inbuff[2] << 8 | inbuff[1] << 16; |
| |
/* We're going to be linking tags from all context we use. |
/* We're going to be linking tags from all context we use. |
mark them as unused so we don't link one twice and break the list */ |
mark them as unused so we don't link one twice and break the list */ |
for (context_tmp = state->context; context_tmp; context_tmp = context_tmp->current) |
for (context_tmp = state->context; context_tmp; context_tmp = context_tmp->current) |
Line 347 static int dhcp6_no_relay(struct state *state, int msg
|
Line 348 static int dhcp6_no_relay(struct state *state, int msg
|
(msg_type == DHCP6REQUEST || msg_type == DHCP6RENEW || msg_type == DHCP6RELEASE || msg_type == DHCP6DECLINE)) |
(msg_type == DHCP6REQUEST || msg_type == DHCP6RENEW || msg_type == DHCP6RELEASE || msg_type == DHCP6DECLINE)) |
|
|
{ |
{ |
*outmsgtypep = DHCP6REPLY; | outmsgtype = DHCP6REPLY; |
o1 = new_opt6(OPTION6_STATUS_CODE); |
o1 = new_opt6(OPTION6_STATUS_CODE); |
put_opt6_short(DHCP6USEMULTI); |
put_opt6_short(DHCP6USEMULTI); |
put_opt6_string("Use multicast"); |
put_opt6_string("Use multicast"); |
end_opt6(o1); |
end_opt6(o1); |
return 1; | goto done; |
} |
} |
|
|
/* match vendor and user class options */ |
/* match vendor and user class options */ |
Line 619 static int dhcp6_no_relay(struct state *state, int msg
|
Line 620 static int dhcp6_no_relay(struct state *state, int msg
|
struct dhcp_netid *solicit_tags; |
struct dhcp_netid *solicit_tags; |
struct dhcp_context *c; |
struct dhcp_context *c; |
|
|
*outmsgtypep = DHCP6ADVERTISE; | outmsgtype = DHCP6ADVERTISE; |
|
|
if (opt6_find(state->packet_options, state->end, OPTION6_RAPID_COMMIT, 0)) |
if (opt6_find(state->packet_options, state->end, OPTION6_RAPID_COMMIT, 0)) |
{ |
{ |
*outmsgtypep = DHCP6REPLY; | outmsgtype = DHCP6REPLY; |
state->lease_allocate = 1; |
state->lease_allocate = 1; |
o = new_opt6(OPTION6_RAPID_COMMIT); |
o = new_opt6(OPTION6_RAPID_COMMIT); |
end_opt6(o); |
end_opt6(o); |
Line 809 static int dhcp6_no_relay(struct state *state, int msg
|
Line 810 static int dhcp6_no_relay(struct state *state, int msg
|
int start = save_counter(-1); |
int start = save_counter(-1); |
|
|
/* set reply message type */ |
/* set reply message type */ |
*outmsgtypep = DHCP6REPLY; | outmsgtype = DHCP6REPLY; |
state->lease_allocate = 1; |
state->lease_allocate = 1; |
|
|
log6_quiet(state, "DHCPREQUEST", NULL, ignore ? _("ignored") : NULL); |
log6_quiet(state, "DHCPREQUEST", NULL, ignore ? _("ignored") : NULL); |
Line 919 static int dhcp6_no_relay(struct state *state, int msg
|
Line 920 static int dhcp6_no_relay(struct state *state, int msg
|
|
|
|
|
case DHCP6RENEW: |
case DHCP6RENEW: |
|
case DHCP6REBIND: |
{ |
{ |
|
int address_assigned = 0; |
|
|
/* set reply message type */ |
/* set reply message type */ |
*outmsgtypep = DHCP6REPLY; | outmsgtype = DHCP6REPLY; |
|
|
log6_quiet(state, "DHCPRENEW", NULL, NULL); | log6_quiet(state, msg_type == DHCP6RENEW ? "DHCPRENEW" : "DHCPREBIND", NULL, NULL); |
|
|
for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end)) |
for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end)) |
{ |
{ |
Line 952 static int dhcp6_no_relay(struct state *state, int msg
|
Line 956 static int dhcp6_no_relay(struct state *state, int msg
|
state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, |
state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, |
state->iaid, &req_addr))) |
state->iaid, &req_addr))) |
{ |
{ |
/* If the server cannot find a client entry for the IA the server | if (msg_type == DHCP6REBIND) |
returns the IA containing no addresses with a Status Code option set | { |
to NoBinding in the Reply message. */ | /* When rebinding, we can create a lease if it doesn't exist. */ |
save_counter(iacntr); | lease = lease6_allocate(&req_addr, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA); |
t1cntr = 0; | if (lease) |
| lease_set_iaid(lease, state->iaid); |
log6_packet(state, "DHCPREPLY", &req_addr, _("lease not found")); | else |
| break; |
o1 = new_opt6(OPTION6_STATUS_CODE); | } |
put_opt6_short(DHCP6NOBINDING); | else |
put_opt6_string(_("no binding found")); | { |
end_opt6(o1); | /* If the server cannot find a client entry for the IA the server |
| returns the IA containing no addresses with a Status Code option set |
preferred_time = valid_time = 0; | to NoBinding in the Reply message. */ |
break; | save_counter(iacntr); |
| t1cntr = 0; |
| |
| log6_packet(state, "DHCPREPLY", &req_addr, _("lease not found")); |
| |
| o1 = new_opt6(OPTION6_STATUS_CODE); |
| put_opt6_short(DHCP6NOBINDING); |
| put_opt6_string(_("no binding found")); |
| end_opt6(o1); |
| |
| preferred_time = valid_time = 0; |
| break; |
| } |
} |
} |
|
|
|
|
if ((this_context = address6_available(state->context, &req_addr, tagif, 1)) || |
if ((this_context = address6_available(state->context, &req_addr, tagif, 1)) || |
(this_context = address6_valid(state->context, &req_addr, tagif, 1))) |
(this_context = address6_valid(state->context, &req_addr, tagif, 1))) |
{ |
{ |
Line 1000 static int dhcp6_no_relay(struct state *state, int msg
|
Line 1015 static int dhcp6_no_relay(struct state *state, int msg
|
|
|
if (preferred_time == 0) |
if (preferred_time == 0) |
message = _("deprecated"); |
message = _("deprecated"); |
|
|
|
address_assigned = 1; |
} |
} |
else |
else |
{ |
{ |
Line 1022 static int dhcp6_no_relay(struct state *state, int msg
|
Line 1039 static int dhcp6_no_relay(struct state *state, int msg
|
end_ia(t1cntr, min_time, 1); |
end_ia(t1cntr, min_time, 1); |
end_opt6(o); |
end_opt6(o); |
} |
} |
|
|
|
if (!address_assigned && msg_type == DHCP6REBIND) |
|
{ |
|
/* can't create lease for any address, return error */ |
|
o1 = new_opt6(OPTION6_STATUS_CODE); |
|
put_opt6_short(DHCP6NOADDRS); |
|
put_opt6_string(_("no addresses available")); |
|
end_opt6(o1); |
|
} |
|
|
tagif = add_options(state, 0); |
tagif = add_options(state, 0); |
break; |
break; |
|
|
} |
} |
|
|
case DHCP6CONFIRM: |
case DHCP6CONFIRM: |
Line 1033 static int dhcp6_no_relay(struct state *state, int msg
|
Line 1058 static int dhcp6_no_relay(struct state *state, int msg
|
int good_addr = 0; |
int good_addr = 0; |
|
|
/* set reply message type */ |
/* set reply message type */ |
*outmsgtypep = DHCP6REPLY; | outmsgtype = DHCP6REPLY; |
|
|
log6_quiet(state, "DHCPCONFIRM", NULL, NULL); |
log6_quiet(state, "DHCPCONFIRM", NULL, NULL); |
|
|
Line 1097 static int dhcp6_no_relay(struct state *state, int msg
|
Line 1122 static int dhcp6_no_relay(struct state *state, int msg
|
log6_quiet(state, "DHCPINFORMATION-REQUEST", NULL, ignore ? _("ignored") : state->hostname); |
log6_quiet(state, "DHCPINFORMATION-REQUEST", NULL, ignore ? _("ignored") : state->hostname); |
if (ignore) |
if (ignore) |
return 0; |
return 0; |
*outmsgtypep = DHCP6REPLY; | outmsgtype = DHCP6REPLY; |
tagif = add_options(state, 1); |
tagif = add_options(state, 1); |
break; |
break; |
} |
} |
Line 1106 static int dhcp6_no_relay(struct state *state, int msg
|
Line 1131 static int dhcp6_no_relay(struct state *state, int msg
|
case DHCP6RELEASE: |
case DHCP6RELEASE: |
{ |
{ |
/* set reply message type */ |
/* set reply message type */ |
*outmsgtypep = DHCP6REPLY; | outmsgtype = DHCP6REPLY; |
|
|
log6_quiet(state, "DHCPRELEASE", NULL, NULL); |
log6_quiet(state, "DHCPRELEASE", NULL, NULL); |
|
|
Line 1171 static int dhcp6_no_relay(struct state *state, int msg
|
Line 1196 static int dhcp6_no_relay(struct state *state, int msg
|
case DHCP6DECLINE: |
case DHCP6DECLINE: |
{ |
{ |
/* set reply message type */ |
/* set reply message type */ |
*outmsgtypep = DHCP6REPLY; | outmsgtype = DHCP6REPLY; |
|
|
log6_quiet(state, "DHCPDECLINE", NULL, NULL); |
log6_quiet(state, "DHCPDECLINE", NULL, NULL); |
|
|
Line 1251 static int dhcp6_no_relay(struct state *state, int msg
|
Line 1276 static int dhcp6_no_relay(struct state *state, int msg
|
} |
} |
|
|
} |
} |
| |
log_tags(tagif, state->xid); |
log_tags(tagif, state->xid); |
|
|
|
done: |
|
/* Fill in the message type. Note that we store the offset, |
|
not a direct pointer, since the packet memory may have been |
|
reallocated. */ |
|
((unsigned char *)(daemon->outpacket.iov_base))[start_msg] = outmsgtype; |
|
|
log6_opts(0, state->xid, daemon->outpacket.iov_base + start_opts, daemon->outpacket.iov_base + save_counter(-1)); |
log6_opts(0, state->xid, daemon->outpacket.iov_base + start_opts, daemon->outpacket.iov_base + save_counter(-1)); |
|
|
return 1; |
return 1; |
Line 1849 static void update_leases(struct state *state, struct
|
Line 1881 static void update_leases(struct state *state, struct
|
#ifdef HAVE_SCRIPT |
#ifdef HAVE_SCRIPT |
if (daemon->lease_change_command) |
if (daemon->lease_change_command) |
{ |
{ |
void *class_opt; | void *opt; |
| |
lease->flags |= LEASE_CHANGED; |
lease->flags |= LEASE_CHANGED; |
free(lease->extradata); |
free(lease->extradata); |
lease->extradata = NULL; |
lease->extradata = NULL; |
lease->extradata_size = lease->extradata_len = 0; |
lease->extradata_size = lease->extradata_len = 0; |
lease->vendorclass_count = 0; |
lease->vendorclass_count = 0; |
|
|
if ((class_opt = opt6_find(state->packet_options, state->end, OPTION6_VENDOR_CLASS, 4))) | if ((opt = opt6_find(state->packet_options, state->end, OPTION6_VENDOR_CLASS, 4))) |
{ |
{ |
void *enc_opt, *enc_end = opt6_ptr(class_opt, opt6_len(class_opt)); | void *enc_opt, *enc_end = opt6_ptr(opt, opt6_len(opt)); |
lease->vendorclass_count++; |
lease->vendorclass_count++; |
/* send enterprise number first */ |
/* send enterprise number first */ |
sprintf(daemon->dhcp_buff2, "%u", opt6_uint(class_opt, 0, 4)); | sprintf(daemon->dhcp_buff2, "%u", opt6_uint(opt, 0, 4)); |
lease_add_extradata(lease, (unsigned char *)daemon->dhcp_buff2, strlen(daemon->dhcp_buff2), 0); |
lease_add_extradata(lease, (unsigned char *)daemon->dhcp_buff2, strlen(daemon->dhcp_buff2), 0); |
|
|
if (opt6_len(class_opt) >= 6) | if (opt6_len(opt) >= 6) |
for (enc_opt = opt6_ptr(class_opt, 4); enc_opt; enc_opt = opt6_next(enc_opt, enc_end)) | for (enc_opt = opt6_ptr(opt, 4); enc_opt; enc_opt = opt6_next(enc_opt, enc_end)) |
{ |
{ |
lease->vendorclass_count++; |
lease->vendorclass_count++; |
lease_add_extradata(lease, opt6_ptr(enc_opt, 0), opt6_len(enc_opt), 0); |
lease_add_extradata(lease, opt6_ptr(enc_opt, 0), opt6_len(enc_opt), 0); |
Line 1875 static void update_leases(struct state *state, struct
|
Line 1908 static void update_leases(struct state *state, struct
|
lease_add_extradata(lease, (unsigned char *)state->client_hostname, |
lease_add_extradata(lease, (unsigned char *)state->client_hostname, |
state->client_hostname ? strlen(state->client_hostname) : 0, 0); |
state->client_hostname ? strlen(state->client_hostname) : 0, 0); |
|
|
|
/* DNSMASQ_REQUESTED_OPTIONS */ |
|
if ((opt = opt6_find(state->packet_options, state->end, OPTION6_ORO, 2))) |
|
{ |
|
int i, len = opt6_len(opt)/2; |
|
u16 *rop = opt6_ptr(opt, 0); |
|
|
|
for (i = 0; i < len; i++) |
|
lease_add_extradata(lease, (unsigned char *)daemon->namebuff, |
|
sprintf(daemon->namebuff, "%u", ntohs(rop[i])), (i + 1) == len ? 0 : ','); |
|
} |
|
else |
|
lease_add_extradata(lease, NULL, 0, 0); |
|
|
|
if ((opt = opt6_find(state->packet_options, state->end, OPTION6_MUD_URL, 1))) |
|
lease_add_extradata(lease, opt6_ptr(opt, 0), opt6_len(opt), 0); |
|
else |
|
lease_add_extradata(lease, NULL, 0, 0); |
|
|
/* space-concat tag set */ |
/* space-concat tag set */ |
if (!tagif && !context->netid.net) |
if (!tagif && !context->netid.net) |
lease_add_extradata(lease, NULL, 0, 0); |
lease_add_extradata(lease, NULL, 0, 0); |
Line 1904 static void update_leases(struct state *state, struct
|
Line 1955 static void update_leases(struct state *state, struct
|
|
|
lease_add_extradata(lease, (unsigned char *)daemon->addrbuff, state->link_address ? strlen(daemon->addrbuff) : 0, 0); |
lease_add_extradata(lease, (unsigned char *)daemon->addrbuff, state->link_address ? strlen(daemon->addrbuff) : 0, 0); |
|
|
if ((class_opt = opt6_find(state->packet_options, state->end, OPTION6_USER_CLASS, 2))) | if ((opt = opt6_find(state->packet_options, state->end, OPTION6_USER_CLASS, 2))) |
{ |
{ |
void *enc_opt, *enc_end = opt6_ptr(class_opt, opt6_len(class_opt)); | void *enc_opt, *enc_end = opt6_ptr(opt, opt6_len(opt)); |
for (enc_opt = opt6_ptr(class_opt, 0); enc_opt; enc_opt = opt6_next(enc_opt, enc_end)) | for (enc_opt = opt6_ptr(opt, 0); enc_opt; enc_opt = opt6_next(enc_opt, enc_end)) |
lease_add_extradata(lease, opt6_ptr(enc_opt, 0), opt6_len(enc_opt), 0); |
lease_add_extradata(lease, opt6_ptr(enc_opt, 0), opt6_len(enc_opt), 0); |
} |
} |
} |
} |
Line 2076 static unsigned int opt6_uint(unsigned char *opt, int
|
Line 2127 static unsigned int opt6_uint(unsigned char *opt, int
|
return ret; |
return ret; |
} |
} |
|
|
void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, | int relay_upstream6(int iface_index, ssize_t sz, |
struct in6_addr *peer_address, u32 scope_id, time_t now) | struct in6_addr *peer_address, u32 scope_id, time_t now) |
{ |
{ |
/* ->local is same value for all relays on ->current chain */ |
|
|
|
union all_addr from; |
|
unsigned char *header; |
unsigned char *header; |
unsigned char *inbuff = daemon->dhcp_packet.iov_base; |
unsigned char *inbuff = daemon->dhcp_packet.iov_base; |
int msg_type = *inbuff; |
int msg_type = *inbuff; |
int hopcount; | int hopcount, o; |
struct in6_addr multicast; |
struct in6_addr multicast; |
unsigned int maclen, mactype; |
unsigned int maclen, mactype; |
unsigned char mac[DHCP_CHADDR_MAX]; |
unsigned char mac[DHCP_CHADDR_MAX]; |
|
struct dhcp_relay *relay; |
|
|
|
for (relay = daemon->relay6; relay; relay = relay->next) |
|
if (relay->iface_index != 0 && relay->iface_index == iface_index) |
|
break; |
|
|
|
/* No relay config. */ |
|
if (!relay) |
|
return 0; |
|
|
inet_pton(AF_INET6, ALL_SERVERS, &multicast); |
inet_pton(AF_INET6, ALL_SERVERS, &multicast); |
get_client_mac(peer_address, scope_id, mac, &maclen, &mactype, now); |
get_client_mac(peer_address, scope_id, mac, &maclen, &mactype, now); |
| |
/* source address == relay address */ | |
from.addr6 = relay->local.addr6; | |
| |
/* Get hop count from nested relayed message */ |
/* Get hop count from nested relayed message */ |
if (msg_type == DHCP6RELAYFORW) |
if (msg_type == DHCP6RELAYFORW) |
hopcount = *((unsigned char *)inbuff+1) + 1; |
hopcount = *((unsigned char *)inbuff+1) + 1; |
else |
else |
hopcount = 0; |
hopcount = 0; |
|
|
/* RFC 3315 HOP_COUNT_LIMIT */ |
|
if (hopcount > 32) |
|
return; |
|
|
|
reset_counter(); |
reset_counter(); |
|
|
if ((header = put_opt6(NULL, 34))) | /* RFC 3315 HOP_COUNT_LIMIT */ |
| if (hopcount > 32 || !(header = put_opt6(NULL, 34))) |
| return 1; |
| |
| header[0] = DHCP6RELAYFORW; |
| header[1] = hopcount; |
| memcpy(&header[18], peer_address, IN6ADDRSZ); |
| |
| /* RFC-6939 */ |
| if (maclen != 0) |
{ |
{ |
int o; | o = new_opt6(OPTION6_CLIENT_MAC); |
| put_opt6_short(mactype); |
header[0] = DHCP6RELAYFORW; | put_opt6(mac, maclen); |
header[1] = hopcount; | |
memcpy(&header[2], &relay->local.addr6, IN6ADDRSZ); | |
memcpy(&header[18], peer_address, IN6ADDRSZ); | |
| |
/* RFC-6939 */ | |
if (maclen != 0) | |
{ | |
o = new_opt6(OPTION6_CLIENT_MAC); | |
put_opt6_short(mactype); | |
put_opt6(mac, maclen); | |
end_opt6(o); | |
} | |
| |
o = new_opt6(OPTION6_RELAY_MSG); | |
put_opt6(inbuff, sz); | |
end_opt6(o); |
end_opt6(o); |
| } |
for (; relay; relay = relay->current) | |
{ | o = new_opt6(OPTION6_RELAY_MSG); |
union mysockaddr to; | put_opt6(inbuff, sz); |
| end_opt6(o); |
to.sa.sa_family = AF_INET6; | |
to.in6.sin6_addr = relay->server.addr6; | for (; relay; relay = relay->next) |
to.in6.sin6_port = htons(DHCPV6_SERVER_PORT); | if (relay->iface_index != 0 && relay->iface_index == iface_index) |
to.in6.sin6_flowinfo = 0; | { |
to.in6.sin6_scope_id = 0; | union mysockaddr to; |
|
|
if (IN6_ARE_ADDR_EQUAL(&relay->server.addr6, &multicast)) | memcpy(&header[2], &relay->local.addr6, IN6ADDRSZ); |
{ | |
int multicast_iface; | to.sa.sa_family = AF_INET6; |
if (!relay->interface || strchr(relay->interface, '*') || | to.in6.sin6_addr = relay->server.addr6; |
(multicast_iface = if_nametoindex(relay->interface)) == 0 || | to.in6.sin6_port = htons(relay->port); |
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &multicast_iface, sizeof(multicast_iface)) == -1) | to.in6.sin6_flowinfo = 0; |
my_syslog(MS_DHCP | LOG_ERR, _("Cannot multicast to DHCPv6 server without correct interface")); | to.in6.sin6_scope_id = 0; |
} | |
| if (IN6_ARE_ADDR_EQUAL(&relay->server.addr6, &multicast)) |
send_from(daemon->dhcp6fd, 0, daemon->outpacket.iov_base, save_counter(-1), &to, &from, 0); | { |
| int multicast_iface; |
if (option_bool(OPT_LOG_OPTS)) | if (!relay->interface || strchr(relay->interface, '*') || |
{ | (multicast_iface = if_nametoindex(relay->interface)) == 0 || |
inet_ntop(AF_INET6, &relay->local, daemon->addrbuff, ADDRSTRLEN); | setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &multicast_iface, sizeof(multicast_iface)) == -1) |
inet_ntop(AF_INET6, &relay->server, daemon->namebuff, ADDRSTRLEN); | { |
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay %s -> %s"), daemon->addrbuff, daemon->namebuff); | my_syslog(MS_DHCP | LOG_ERR, _("Cannot multicast DHCP relay via interface %s"), relay->interface); |
} | continue; |
| } |
| } |
| |
| #ifdef HAVE_DUMPFILE |
| dump_packet_udp(DUMP_DHCPV6, (void *)daemon->outpacket.iov_base, save_counter(-1), NULL, &to, daemon->dhcp6fd); |
| #endif |
|
|
/* Save this for replies */ | while (retry_send(sendto(daemon->dhcp6fd, (void *)daemon->outpacket.iov_base, save_counter(-1), |
relay->iface_index = scope_id; | 0, (struct sockaddr *)&to, sa_len(&to)))); |
} | |
} | if (option_bool(OPT_LOG_OPTS)) |
| { |
| inet_ntop(AF_INET6, &relay->local, daemon->addrbuff, ADDRSTRLEN); |
| if (IN6_ARE_ADDR_EQUAL(&relay->server.addr6, &multicast)) |
| snprintf(daemon->namebuff, MAXDNAME, _("multicast via %s"), relay->interface); |
| else |
| inet_ntop(AF_INET6, &relay->server, daemon->namebuff, ADDRSTRLEN); |
| my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay at %s -> %s"), daemon->addrbuff, daemon->namebuff); |
| } |
| |
| } |
| |
| return 1; |
} |
} |
|
|
unsigned short relay_reply6(struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface) | int relay_reply6(struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface) |
{ |
{ |
struct dhcp_relay *relay; |
struct dhcp_relay *relay; |
struct in6_addr link; |
struct in6_addr link; |
Line 2196 unsigned short relay_reply6(struct sockaddr_in6 *peer,
|
Line 2258 unsigned short relay_reply6(struct sockaddr_in6 *peer,
|
put_opt6(opt6_ptr(opt, 0), opt6_len(opt)); |
put_opt6(opt6_ptr(opt, 0), opt6_len(opt)); |
memcpy(&peer->sin6_addr, &inbuff[18], IN6ADDRSZ); |
memcpy(&peer->sin6_addr, &inbuff[18], IN6ADDRSZ); |
peer->sin6_scope_id = relay->iface_index; |
peer->sin6_scope_id = relay->iface_index; |
return encap_type == DHCP6RELAYREPL ? DHCPV6_SERVER_PORT : DHCPV6_CLIENT_PORT; | |
| if (encap_type == DHCP6RELAYREPL) |
| { |
| peer->sin6_port = ntohs(DHCPV6_SERVER_PORT); |
| return 1; |
| } |
| |
| peer->sin6_port = ntohs(DHCPV6_CLIENT_PORT); |
| |
| #ifdef HAVE_SCRIPT |
| if (daemon->lease_change_command && encap_type == DHCP6REPLY) |
| { |
| /* decapsulate relayed message */ |
| opts = opt6_ptr(opt, 4); |
| end = opt6_ptr(opt, opt6_len(opt)); |
| |
| for (opt = opts; opt; opt = opt6_next(opt, end)) |
| if (opt6_type(opt) == OPTION6_IA_PD && opt6_len(opt) > 12) |
| { |
| void *ia_opts = opt6_ptr(opt, 12); |
| void *ia_end = opt6_ptr(opt, opt6_len(opt)); |
| void *ia_opt; |
| |
| for (ia_opt = ia_opts; ia_opt; ia_opt = opt6_next(ia_opt, ia_end)) |
| /* valid lifetime must not be zero. */ |
| if (opt6_type(ia_opt) == OPTION6_IAPREFIX && opt6_len(ia_opt) >= 25 && opt6_uint(ia_opt, 4, 4) != 0) |
| { |
| if (daemon->free_snoops || |
| (daemon->free_snoops = whine_malloc(sizeof(struct snoop_record)))) |
| { |
| struct snoop_record *snoop = daemon->free_snoops; |
| |
| daemon->free_snoops = snoop->next; |
| snoop->client = peer->sin6_addr; |
| snoop->prefix_len = opt6_uint(ia_opt, 8, 1); |
| memcpy(&snoop->prefix, opt6_ptr(ia_opt, 9), IN6ADDRSZ); |
| snoop->next = relay->snoop_records; |
| relay->snoop_records = snoop; |
| } |
| } |
| } |
| } |
| #endif |
| return 1; |
} |
} |
|
|
} |
} |
|
|
|
return 0; |
|
} |
|
|
|
#ifdef HAVE_SCRIPT |
|
int do_snoop_script_run(void) |
|
{ |
|
struct dhcp_relay *relay; |
|
struct snoop_record *snoop; |
|
|
|
for (relay = daemon->relay6; relay; relay = relay->next) |
|
if ((snoop = relay->snoop_records)) |
|
{ |
|
relay->snoop_records = snoop->next; |
|
snoop->next = daemon->free_snoops; |
|
daemon->free_snoops = snoop; |
|
|
|
queue_relay_snoop(&snoop->client, relay->iface_index, &snoop->prefix, snoop->prefix_len); |
|
return 1; |
|
} |
|
|
return 0; |
return 0; |
} |
} |
|
#endif |
|
|
#endif |
#endif |