diff options
Diffstat (limited to 'src/rfc3315.c')
-rw-r--r-- | src/rfc3315.c | 69 |
1 files changed, 67 insertions, 2 deletions
diff --git a/src/rfc3315.c b/src/rfc3315.c index f54fb78..fb387a4 100644 --- a/src/rfc3315.c +++ b/src/rfc3315.c @@ -2194,7 +2194,7 @@ void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, } } -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 in6_addr link; @@ -2226,10 +2226,75 @@ unsigned short relay_reply6(struct sockaddr_in6 *peer, ssize_t sz, char *arrival put_opt6(opt6_ptr(opt, 0), opt6_len(opt)); memcpy(&peer->sin6_addr, &inbuff[18], IN6ADDRSZ); 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; +} +int do_snoop_script_run(void) +{ +#ifdef HAVE_SCRIPT + 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; + } +#endif + return 0; } |