int __ni_dhcp4_build_msg_request_offer(const ni_dhcp4_device_t *dev, const ni_addrconf_lease_t *lease, ni_buffer_t *msgbuf) { const ni_dhcp4_config_t *options = dev->config; unsigned int msg_code = DHCP4_REQUEST; ni_dhcp4_message_t *message; ni_sockaddr_t addr; /* Request an offer provided by a server (id!) while discover */ ni_sockaddr_set_ipv4(&addr, lease->dhcp4.address, 0); if (!ni_sockaddr_is_ipv4_specified(&addr)) { ni_error("%s: not requesting this offer - no ip-address in lease", dev->ifname); return -1; } if (!(message = __ni_dhcp4_build_msg_init_head(dev, msg_code, msgbuf))) return -1; if (__ni_dhcp4_build_msg_put_hwspec(dev, message) < 0) return -1; if (__ni_dhcp4_build_msg_put_client_id(dev, msg_code, message, msgbuf) < 0) return -1; if (__ni_dhcp4_build_msg_put_server_id(dev, lease, msg_code, msgbuf) < 0) return -1; ni_dhcp4_option_put_ipv4(msgbuf, DHCP4_ADDRESS, lease->dhcp4.address); ni_debug_verbose(NI_LOG_DEBUG1, NI_TRACE_DHCP, "%s: using offered ip-address: %s", dev->ifname, ni_sockaddr_print(&addr)); if (__ni_dhcp4_build_msg_put_our_hostname(dev, msgbuf) < 0) return -1; if (__ni_dhcp4_build_msg_put_option_request(dev, msg_code, msgbuf) < 0) return -1; ni_dhcp4_option_put16(msgbuf, DHCP4_MAXMESSAGESIZE, dev->system.mtu); if (lease->dhcp4.lease_time != 0) { ni_dhcp4_option_put32(msgbuf, DHCP4_LEASETIME, lease->dhcp4.lease_time); } if (options->userclass.len > 0) { ni_dhcp4_option_put(msgbuf, DHCP4_USERCLASS, options->userclass.data, options->userclass.len); } if (options->classid && options->classid[0]) { ni_dhcp4_option_puts(msgbuf, DHCP4_CLASSID, options->classid); } return 0; }
/* * Decode a CIDR list option. */ static int ni_dhcp_decode_csr(ni_buffer_t *bp, ni_route_array_t *routes) { while (ni_buffer_count(bp) && !bp->underflow) { ni_sockaddr_t destination, gateway; struct in_addr prefix = { 0 }; unsigned int prefix_len; ni_route_t *rp; prefix_len = ni_buffer_getc(bp); if (prefix_len > 32) { ni_error("invalid prefix len of %u in classless static route", prefix_len); return -1; } if (prefix_len) ni_buffer_get(bp, &prefix, (prefix_len + 7) / 8); ni_sockaddr_set_ipv4(&destination, prefix, 0); if (ni_dhcp_option_get_sockaddr(bp, &gateway) < 0) return -1; rp = ni_route_create(prefix_len, &destination, &gateway, 0, NULL); ni_route_array_append(routes, rp); } if (bp->underflow) return -1; return 0; }
static int __ni_dhcp4_build_msg_release(const ni_dhcp4_device_t *dev, const ni_addrconf_lease_t *lease, ni_buffer_t *msgbuf) { unsigned int msg_code = DHCP4_RELEASE; ni_dhcp4_message_t *message; ni_sockaddr_t addr; /* Release an IP address from a lease we own */ ni_sockaddr_set_ipv4(&addr, lease->dhcp4.address, 0); if (!ni_sockaddr_is_ipv4_specified(&addr)) { ni_error("%s: cannot release - no ip-address in lease", dev->ifname); return -1; } if (!(message = __ni_dhcp4_build_msg_init_head(dev, msg_code, msgbuf))) return -1; message->ciaddr = lease->dhcp4.address.s_addr; ni_debug_verbose(NI_LOG_DEBUG1, NI_TRACE_DHCP, "%s: using release ip-address: %s", dev->ifname, ni_sockaddr_print(&addr)); if (__ni_dhcp4_build_msg_put_hwspec(dev, message) < 0) return -1; if (__ni_dhcp4_build_msg_put_client_id(dev, msg_code, message, msgbuf) < 0) return -1; if (__ni_dhcp4_build_msg_put_server_id(dev, lease, msg_code, msgbuf) < 0) return -1; return 0; }
static int __ni_dhcp4_build_msg_discover(const ni_dhcp4_device_t *dev, const ni_addrconf_lease_t *lease, ni_buffer_t *msgbuf) { const ni_dhcp4_config_t *options = dev->config; unsigned int msg_code = DHCP4_DISCOVER; ni_dhcp4_message_t *message; ni_sockaddr_t addr; /* Discover server able to provide usable offer */ if (!(message = __ni_dhcp4_build_msg_init_head(dev, msg_code, msgbuf))) return -1; if (__ni_dhcp4_build_msg_put_hwspec(dev, message) < 0) return -1; if (__ni_dhcp4_build_msg_put_client_id(dev, msg_code, message, msgbuf) < 0) return -1; /* An optional hint that we've had this address in the past, * so the server __may__ assign it again to us. */ ni_sockaddr_set_ipv4(&addr, lease->dhcp4.address, 0); if (ni_sockaddr_is_ipv4_specified(&addr)) { ni_dhcp4_option_put_ipv4(msgbuf, DHCP4_ADDRESS, lease->dhcp4.address); ni_debug_verbose(NI_LOG_DEBUG1, NI_TRACE_DHCP, "%s: using ip-address hint: %s", dev->ifname, ni_sockaddr_print(&addr)); } if (__ni_dhcp4_build_msg_put_option_request(dev, msg_code, msgbuf) < 0) return -1; ni_dhcp4_option_put16(msgbuf, DHCP4_MAXMESSAGESIZE, dev->system.mtu); if (lease->dhcp4.lease_time != 0) { ni_dhcp4_option_put32(msgbuf, DHCP4_LEASETIME, lease->dhcp4.lease_time); } if (options->userclass.len > 0) { ni_dhcp4_option_put(msgbuf, DHCP4_USERCLASS, options->userclass.data, options->userclass.len); } if (options->classid && options->classid[0]) { ni_dhcp4_option_puts(msgbuf, DHCP4_CLASSID, options->classid); } return 0; }
int __ni_dhcp4_build_msg_inform(const ni_dhcp4_device_t *dev, const ni_addrconf_lease_t *lease, ni_buffer_t *msgbuf) { const ni_dhcp4_config_t *options = dev->config; unsigned int msg_code = DHCP4_INFORM; ni_dhcp4_message_t *message; ni_sockaddr_t addr; /* Inform server about IP address we use and request other config */ ni_sockaddr_set_ipv4(&addr, lease->dhcp4.address, 0); if (!ni_sockaddr_is_ipv4_specified(&addr)) { ni_error("%s: cannot inform - no ip-address set", dev->ifname); return -1; } if (!(message = __ni_dhcp4_build_msg_init_head(dev, msg_code, msgbuf))) return -1; message->ciaddr = lease->dhcp4.address.s_addr; ni_debug_verbose(NI_LOG_DEBUG1, NI_TRACE_DHCP, "%s: using inform ip-address: %s", dev->ifname, ni_sockaddr_print(&addr)); if (__ni_dhcp4_build_msg_put_hwspec(dev, message) < 0) return -1; if (__ni_dhcp4_build_msg_put_client_id(dev, msg_code, message, msgbuf) < 0) return -1; if (__ni_dhcp4_build_msg_put_option_request(dev, msg_code, msgbuf) < 0) return -1; ni_dhcp4_option_put16(msgbuf, DHCP4_MAXMESSAGESIZE, dev->system.mtu); if (options->userclass.len > 0) { ni_dhcp4_option_put(msgbuf, DHCP4_USERCLASS, options->userclass.data, options->userclass.len); } if (options->classid && options->classid[0]) { ni_dhcp4_option_puts(msgbuf, DHCP4_CLASSID, options->classid); } return 0; }
static ni_bool_t __ni_dhcp4_address_on_device(const ni_netdev_t *ifp, struct in_addr ipv4) { const ni_address_t *ap; ni_sockaddr_t addr; ni_sockaddr_set_ipv4(&addr, ipv4, 0); for (ap = ifp->addrs; ap; ap = ap->next) { if (ap->family != AF_INET) continue; if (ni_sockaddr_equal(&ap->local_addr, &addr)) return TRUE; } return FALSE; }
static int __ni_dhcp4_build_msg_put_server_id(const ni_dhcp4_device_t *dev, const ni_addrconf_lease_t *lease, unsigned int msg_code, ni_buffer_t *msgbuf) { ni_sockaddr_t addr; ni_sockaddr_set_ipv4(&addr, lease->dhcp4.server_id, 0); if (!ni_sockaddr_is_ipv4_specified(&addr)) { ni_error("%s: cannot construct %s without server-id", dev->ifname, ni_dhcp4_message_name(msg_code)); return -1; } ni_dhcp4_option_put_ipv4(msgbuf, DHCP4_SERVERIDENTIFIER, lease->dhcp4.server_id); ni_debug_verbose(NI_LOG_DEBUG1, NI_TRACE_DHCP, "%s: using server-id: %s", dev->ifname, ni_sockaddr_print(&addr)); return 0; }
/* * Reload an old lease from file, and see whether we can reuse it. * This is used during restart of wickedd. */ int ni_dhcp4_recover_lease(ni_dhcp4_device_t *dev) { ni_addrconf_lease_t *lease; ni_sockaddr_t addr; if (dev->lease) return 1; lease = ni_addrconf_lease_file_read(dev->ifname, NI_ADDRCONF_DHCP, AF_INET); if (!lease) return -1; if (!ni_addrconf_lease_is_valid(dev->lease)) { ni_debug_verbose(NI_LOG_DEBUG1, NI_TRACE_DHCP, "%s: discarding existing lease, not granted", dev->ifname); goto discard; } /* We cannot renew/rebind/reboot without it */ ni_sockaddr_set_ipv4(&addr, lease->dhcp4.server_id, 0); if (!ni_sockaddr_is_ipv4_specified(&addr)) { ni_debug_verbose(NI_LOG_DEBUG1, NI_TRACE_DHCP, "%s: discarding existing lease, no server-id", dev->ifname); goto discard; } ni_dhcp4_device_set_lease(dev, lease); return 0; discard: ni_addrconf_lease_free(lease); return -1; }
static int __ni_dhcp4_build_msg_decline(const ni_dhcp4_device_t *dev, const ni_addrconf_lease_t *lease, ni_buffer_t *msgbuf) { unsigned int msg_code = DHCP4_DECLINE; ni_dhcp4_message_t *message; ni_sockaddr_t addr; /* Decline IP address the server offered to us; * we've found another host using it already. */ ni_sockaddr_set_ipv4(&addr, lease->dhcp4.address, 0); if (!ni_sockaddr_is_ipv4_specified(&addr)) { ni_error("%s: cannot decline - no ip-address in lease", dev->ifname); return -1; } if (!(message = __ni_dhcp4_build_msg_init_head(dev, msg_code, msgbuf))) return -1; if (__ni_dhcp4_build_msg_put_hwspec(dev, message) < 0) return -1; if (__ni_dhcp4_build_msg_put_client_id(dev, msg_code, message, msgbuf) < 0) return -1; if (__ni_dhcp4_build_msg_put_server_id(dev, lease, msg_code, msgbuf) < 0) return -1; ni_dhcp4_option_put_ipv4(msgbuf, DHCP4_ADDRESS, lease->dhcp4.address); ni_debug_verbose(NI_LOG_DEBUG1, NI_TRACE_DHCP, "%s: using decline ip-address: %s", dev->ifname, ni_sockaddr_print(&addr)); 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; }