summaryrefslogtreecommitdiff
path: root/src/rfc3315.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/rfc3315.c')
-rw-r--r--src/rfc3315.c69
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;
}