diff options
author | Tom Gundersen <teg@jklm.no> | 2015-08-18 15:37:43 +0200 |
---|---|---|
committer | Tom Gundersen <teg@jklm.no> | 2015-09-18 15:14:42 +0200 |
commit | 996d16975b4d802335188a3be2bbc3635c1287f3 (patch) | |
tree | 56a357205a2504f7e2995949909b960445565f1d /src/libsystemd-network/sd-ipv4ll.c | |
parent | 2b2eac39e889bdbcc6cbf44443f7682b3ac502f7 (diff) |
sd-ipv4ll: filter out unwanted ARP packets in the kernel
We currently process every ARP packet, but we should only care about the ones
relating to our IP address.
Also rename ipv4ll helpers to apr-utils.[ch], and rework the helpers a bit.
Diffstat (limited to 'src/libsystemd-network/sd-ipv4ll.c')
-rw-r--r-- | src/libsystemd-network/sd-ipv4ll.c | 80 |
1 files changed, 45 insertions, 35 deletions
diff --git a/src/libsystemd-network/sd-ipv4ll.c b/src/libsystemd-network/sd-ipv4ll.c index 14b9444dab..f292a9dba9 100644 --- a/src/libsystemd-network/sd-ipv4ll.c +++ b/src/libsystemd-network/sd-ipv4ll.c @@ -28,7 +28,7 @@ #include "list.h" #include "random-util.h" -#include "ipv4ll-internal.h" +#include "arp-util.h" #include "sd-ipv4ll.h" /* Constants from the RFC */ @@ -46,6 +46,8 @@ #define IPV4LL_NETWORK 0xA9FE0000L #define IPV4LL_NETMASK 0xFFFF0000L +#define log_ipv4ll(ll, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "IPv4LL: " fmt, ##__VA_ARGS__) + typedef enum IPv4LLTrigger{ IPV4LL_TRIGGER_NULL, IPV4LL_TRIGGER_PACKET, @@ -72,7 +74,6 @@ struct sd_ipv4ll { IPv4LLState state; int index; int fd; - union sockaddr_union link; int iteration; int conflict; sd_event_source *receive_message; @@ -196,8 +197,7 @@ static bool ipv4ll_arp_conflict (sd_ipv4ll *ll, struct ether_arp *arp) { assert(ll); assert(arp); - if (memcmp(arp->arp_spa, &ll->address, sizeof(ll->address)) == 0 && - memcmp(arp->arp_sha, &ll->mac_addr, ETH_ALEN) != 0) + if (memcmp(arp->arp_spa, &ll->address, sizeof(ll->address)) == 0) return true; return false; @@ -210,16 +210,13 @@ static bool ipv4ll_arp_probe_conflict (sd_ipv4ll *ll, struct ether_arp *arp) { if (ipv4ll_arp_conflict(ll, arp)) return true; - if (memcmp(arp->arp_tpa, &ll->address, sizeof(ll->address)) == 0 && - memcmp(arp->arp_sha, &ll->mac_addr, ETH_ALEN)) + if (memcmp(arp->arp_tpa, &ll->address, sizeof(ll->address)) == 0) return true; return false; } static void ipv4ll_run_state_machine(sd_ipv4ll *ll, IPv4LLTrigger trigger, void *trigger_data) { - struct ether_arp out_packet; - int out_packet_ready = 0; int r = 0; assert(ll); @@ -235,8 +232,12 @@ static void ipv4ll_run_state_machine(sd_ipv4ll *ll, IPv4LLTrigger trigger, void (ll->state == IPV4LL_STATE_PROBING && trigger == IPV4LL_TRIGGER_TIMEOUT && ll->iteration < PROBE_NUM-2)) { /* Send a probe */ - arp_packet_probe(&out_packet, ll->address, &ll->mac_addr); - out_packet_ready = 1; + r = arp_send_probe(ll->fd, ll->index, ll->address, &ll->mac_addr); + if (r < 0) { + log_ipv4ll(ll, "Failed to send ARP probe."); + goto out; + } + ipv4ll_set_state(ll, IPV4LL_STATE_PROBING, 0); ipv4ll_set_next_wakeup(ll, PROBE_MIN, (PROBE_MAX-PROBE_MIN)); @@ -244,8 +245,12 @@ static void ipv4ll_run_state_machine(sd_ipv4ll *ll, IPv4LLTrigger trigger, void } else if (ll->state == IPV4LL_STATE_PROBING && trigger == IPV4LL_TRIGGER_TIMEOUT && ll->iteration >= PROBE_NUM-2) { /* Send the last probe */ - arp_packet_probe(&out_packet, ll->address, &ll->mac_addr); - out_packet_ready = 1; + r = arp_send_probe(ll->fd, ll->index, ll->address, &ll->mac_addr); + if (r < 0) { + log_ipv4ll(ll, "Failed to send ARP probe."); + goto out; + } + ipv4ll_set_state(ll, IPV4LL_STATE_WAITING_ANNOUNCE, 1); ipv4ll_set_next_wakeup(ll, ANNOUNCE_WAIT, 0); @@ -254,8 +259,12 @@ static void ipv4ll_run_state_machine(sd_ipv4ll *ll, IPv4LLTrigger trigger, void (ll->state == IPV4LL_STATE_ANNOUNCING && trigger == IPV4LL_TRIGGER_TIMEOUT && ll->iteration < ANNOUNCE_NUM-1)) { /* Send announcement packet */ - arp_packet_announcement(&out_packet, ll->address, &ll->mac_addr); - out_packet_ready = 1; + r = arp_send_announcement(ll->fd, ll->index, ll->address, &ll->mac_addr); + if (r < 0) { + log_ipv4ll(ll, "Failed to send ARP announcement."); + goto out; + } + ipv4ll_set_state(ll, IPV4LL_STATE_ANNOUNCING, 0); ipv4ll_set_next_wakeup(ll, ANNOUNCE_INTERVAL, 0); @@ -295,8 +304,12 @@ static void ipv4ll_run_state_machine(sd_ipv4ll *ll, IPv4LLTrigger trigger, void /* Defend address */ if (time_now > ll->defend_window) { ll->defend_window = time_now + DEFEND_INTERVAL * USEC_PER_SEC; - arp_packet_announcement(&out_packet, ll->address, &ll->mac_addr); - out_packet_ready = 1; + r = arp_send_announcement(ll->fd, ll->index, ll->address, &ll->mac_addr); + if (r < 0) { + log_ipv4ll(ll, "Failed to send ARP announcement."); + goto out; + } + } else conflicted = 1; } @@ -320,6 +333,15 @@ static void ipv4ll_run_state_machine(sd_ipv4ll *ll, IPv4LLTrigger trigger, void r = ipv4ll_pick_address(ll, &ll->address); if (r < 0) goto out; + + ll->fd = safe_close(ll->fd); + + r = arp_network_bind_raw_socket(ll->index, ll->address, &ll->mac_addr); + if (r < 0) + goto out; + + ll->fd = r; + ll->conflict++; ll->defend_window = 0; ipv4ll_set_state(ll, IPV4LL_STATE_WAITING_PROBE, 1); @@ -329,15 +351,6 @@ static void ipv4ll_run_state_machine(sd_ipv4ll *ll, IPv4LLTrigger trigger, void ipv4ll_set_next_wakeup(ll, RATE_LIMIT_INTERVAL, PROBE_WAIT); } else ipv4ll_set_next_wakeup(ll, 0, PROBE_WAIT); - - } - } - - if (out_packet_ready) { - r = arp_network_send_raw_socket(ll->fd, &ll->link, &out_packet); - if (r < 0) { - log_ipv4ll(ll, "failed to send arp packet out"); - goto out; } } @@ -374,10 +387,6 @@ static int ipv4ll_receive_message(sd_event_source *s, int fd, if (r < (int) sizeof(struct ether_arp)) return 0; - r = arp_packet_verify_headers(&arp); - if (r < 0) - return 0; - ipv4ll_run_state_machine(ll, IPV4LL_TRIGGER_PACKET, &arp); return 0; @@ -523,12 +532,6 @@ int sd_ipv4ll_start (sd_ipv4ll *ll) { ll->state = IPV4LL_STATE_INIT; - r = arp_network_bind_raw_socket(ll->index, &ll->link); - - if (r < 0) - goto out; - - ll->fd = r; ll->conflict = 0; ll->defend_window = 0; ll->claimed_address = 0; @@ -551,6 +554,13 @@ int sd_ipv4ll_start (sd_ipv4ll *ll) { goto out; } + r = arp_network_bind_raw_socket(ll->index, ll->address, &ll->mac_addr); + if (r < 0) + goto out; + + safe_close(ll->fd); + ll->fd = r; + ipv4ll_set_state (ll, IPV4LL_STATE_INIT, 1); r = sd_event_add_io(ll->event, &ll->receive_message, ll->fd, |