void ni_dhcp4_fsm_process_arp_packet(ni_arp_socket_t *arph, const ni_arp_packet_t *pkt, void *user_data) { ni_dhcp4_device_t *dev = user_data; ni_netconfig_t *nc = ni_global_state_handle(0); const ni_netdev_t *ifp; ni_bool_t false_alarm = FALSE; ni_bool_t found_addr = FALSE; if (!pkt || pkt->op != ARPOP_REPLY || !dev || !dev->lease) return; /* Is it about the address we're validating at all? */ if (pkt->sip.s_addr != dev->lease->dhcp4.address.s_addr) return; /* Ignore any ARP replies that seem to come from our own * MAC address. Some helpful switches seem to generate * these. */ if (ni_link_address_equal(&dev->system.hwaddr, &pkt->sha)) return; /* As well as ARP replies that seem to come from our own * host: dup if same address, not a dup if there are two * interfaces connected to the same broadcast domain. */ for (ifp = ni_netconfig_devlist(nc); ifp; ifp = ifp->next) { if (ifp->link.ifindex == dev->link.ifindex) continue; if (!ni_netdev_link_is_up(ifp)) continue; if (!ni_link_address_equal(&ifp->link.hwaddr, &pkt->sha)) continue; /* OK, we have an interface matching the hwaddr, * which will answer arp requests when it is on * the same broadcast domain and causes a false * alarm, except it really has the IP assigned. */ false_alarm = TRUE; if (__ni_dhcp4_address_on_device(ifp, pkt->sip)) found_addr = TRUE; } if (false_alarm && !found_addr) return; ni_debug_dhcp("%s: address %s already in use by %s", dev->ifname, inet_ntoa(pkt->sip), ni_link_address_print(&pkt->sha)); ni_dhcp4_device_arp_close(dev); ni_dhcp4_fsm_decline(dev); }
void ni_netdev_discover_client_state(ni_netdev_t *dev) { ni_fsm_state_t state = NI_FSM_STATE_DEVICE_EXISTS; ni_client_state_t *cs; if (!dev) return; if (ni_netdev_device_is_up(dev)) state = NI_FSM_STATE_DEVICE_UP; if (ni_netdev_link_is_up(dev)) state = NI_FSM_STATE_LINK_UP; if (ni_netdev_network_is_up(dev)) state = NI_FSM_STATE_LINK_UP; cs = ni_client_state_new(state); ni_netdev_set_client_state(dev, cs); }
static int __do_arp_validate_init(struct arp_handle *handle, ni_capture_devinfo_t *dev_info) { ni_netconfig_t *nc; ni_netdev_t *dev; if (ni_server_listen_interface_events(NULL) < 0) { ni_error("unable to initialize netlink link listener"); return NI_LSB_RC_ERROR; } if (ni_server_enable_interface_addr_events(NULL) < 0) { ni_error("unable to initialize netlink addr listener"); return NI_LSB_RC_ERROR; } if (!(nc = ni_global_state_handle(1))) { ni_error("Cannot refresh interface list!"); return NI_LSB_RC_ERROR; } if (!(dev = ni_netdev_by_name(nc, handle->ifname))) { ni_error("Cannot find interface with name '%s'", handle->ifname); return NI_LSB_RC_ERROR; } if (!ni_netdev_supports_arp(dev)) { ni_error("%s: arp is not supported/enabled", dev->name); return NI_LSB_RC_ERROR; } if (!ni_netdev_link_is_up(dev)) { ni_error("%s: link is not up", dev->name); return NI_LSB_RC_ERROR; } if (ni_capture_devinfo_init(dev_info, dev->name, &dev->link) < 0) { ni_error("%s: cannot initialize capture", dev->name); return NI_LSB_RC_ERROR; } return 0; }
static void __do_arp_validate_process(ni_arp_socket_t *sock, const ni_arp_packet_t *pkt, void *user_data) { struct arp_handle *handle = user_data; ni_netconfig_t *nc = ni_global_state_handle(0); const ni_netdev_t *ifp; ni_bool_t false_alarm = FALSE; ni_bool_t found_addr = FALSE; const ni_address_t *ap; ni_sockaddr_t addr; if (!pkt || pkt->op != ARPOP_REPLY || !handle->replies) return; /* Is it about the address we're validating at all? */ if (pkt->sip.s_addr != handle->ipaddr.sin.sin_addr.s_addr) { ni_debug_application("%s: report about different address", handle->ifname); return; } /* Ignore any ARP replies that seem to come from our own * MAC address. Some helpful switches seem to generate * these. */ if (ni_link_address_equal(&sock->dev_info.hwaddr, &pkt->sha)) { ni_debug_application("%s: adress in use by ourself", handle->ifname); return; } /* As well as ARP replies that seem to come from our own * host: dup if same address, not a dup if there are two * interfaces connected to the same broadcast domain. */ ni_sockaddr_set_ipv4(&addr, pkt->sip, 0); for (ifp = ni_netconfig_devlist(nc); ifp; ifp = ifp->next) { if (ifp->link.ifindex == sock->dev_info.ifindex) continue; if (!ni_netdev_link_is_up(ifp)) continue; if (!ni_link_address_equal(&ifp->link.hwaddr, &pkt->sha)) continue; /* OK, we have an interface matching the hwaddr, * which will answer arp requests when it is on * the same broadcast domain and causes a false * alarm, except it really has the IP assigned. */ false_alarm = TRUE; for (ap = ifp->addrs; !found_addr && ap; ap = ap->next) { if (ap->family != AF_INET) continue; if (ni_sockaddr_equal(&ap->local_addr, &addr)) found_addr = TRUE; } } if (false_alarm && !found_addr) { ni_debug_application("%s: reply from one of our interfaces", handle->ifname); return; } ni_info("%s: adress %s in use by %s reported", handle->ifname, inet_ntoa(pkt->sip), ni_link_address_print(&pkt->sha)); handle->hwaddr = pkt->sha; }
int ni_dhcp4_tester_run(ni_dhcp4_tester_t *opts) { ni_netconfig_t *nc; ni_netdev_t *ifp = NULL; ni_dhcp4_device_t *dev = NULL; ni_dhcp4_request_t *req = NULL; unsigned int link_timeout = 20; int rv; if (opts->timeout && opts->timeout != -1U) { link_timeout = (opts->timeout * 2) / 3; opts->timeout -= link_timeout; } if (!opts || ni_string_empty(opts->ifname)) ni_fatal("Invalid start parameters!"); dhcp4_tester_opts = *opts; dhcp4_tester_status = NI_WICKED_RC_ERROR; if (!(nc = ni_global_state_handle(1))) ni_fatal("Cannot refresh interface list!"); if (!(ifp = ni_netdev_by_name(nc, opts->ifname))) ni_fatal("Cannot find interface with name '%s'", opts->ifname); if (!ni_dhcp4_supported(ifp)) ni_fatal("DHCPv4 not supported on '%s'", opts->ifname); if (!(dev = ni_dhcp4_device_new(ifp->name, &ifp->link))) ni_fatal("Cannot allocate dhcp4 client for '%s'", opts->ifname); ni_dhcp4_set_event_handler(ni_dhcp4_tester_protocol_event); if (!(req = ni_dhcp4_request_new())) { ni_error("Cannot allocate dhcp4 request"); goto failure; } if (!ni_dhcp4_tester_req_init(req, opts->request)) goto failure; if (!ni_netdev_link_is_up(ifp)) { ni_netdev_req_t *ifreq; ni_debug_dhcp("%s: Link is not up, trying to bring it up", ifp->name); ifreq = ni_netdev_req_new(); ifreq->ifflags = NI_IFF_LINK_UP | NI_IFF_NETWORK_UP; if ((rv = ni_system_interface_link_change(ifp, ifreq)) < 0) { ni_error("%s: Unable to set up link", ifp->name); ni_netdev_req_free(ifreq); goto failure; } ni_netdev_req_free(ifreq); do { sleep(1); if (!(nc = ni_global_state_handle(1))) goto failure; if (!(ifp = ni_netdev_by_index(nc, dev->link.ifindex))) break; if (ni_netdev_link_is_up(ifp)) break; ni_debug_dhcp("%s: Link is not (yet) up", ifp->name); } while (link_timeout-- > 1); if (!ifp || !ni_netdev_link_is_up(ifp) || !link_timeout) { ni_error("%s: Unable to bring link up", ifp && ifp->name ? ifp->name : dev->ifname); goto failure; } /* Do not try to send too early, even link is reported up now */ sleep(1); } if (opts->timeout && opts->timeout != -1U) req->acquire_timeout = opts->timeout; req->broadcast = opts->broadcast; if ((rv = ni_dhcp4_acquire(dev, req)) < 0) { ni_error("%s: DHCP4v6 acquire request %s failed: %s", dev->ifname, ni_uuid_print(&req->uuid), ni_strerror(rv)); goto failure; } dhcp4_tester_status = NI_WICKED_RC_IN_PROGRESS; while (!ni_caught_terminal_signal()) { long timeout; timeout = ni_timer_next_timeout(); if (ni_socket_wait(timeout) != 0) break; } ni_server_deactivate_interface_events(); ni_socket_deactivate_all(); failure: if (dev) ni_dhcp4_device_put(dev); if (req) ni_dhcp4_request_free(req); return dhcp4_tester_status; }