/* * Open ARP socket */ ni_arp_socket_t * ni_arp_socket_open(const ni_capture_devinfo_t *dev_info, ni_arp_callback_t *callback, void *calldata) { ni_capture_protinfo_t prot_info; ni_arp_socket_t *arph; arph = calloc(1, sizeof(*arph)); arph->dev_info = *dev_info; arph->callback = callback; arph->user_data = calldata; memset(&prot_info, 0, sizeof(prot_info)); prot_info.eth_protocol = ETHERTYPE_ARP; arph->capture = ni_capture_open(dev_info, &prot_info, ni_arp_socket_recv); if (!arph->capture) { ni_arp_socket_close(arph); return NULL; } ni_capture_set_user_data(arph->capture, arph); return arph; }
/* * Open a DHCP socket for send and receive */ int ni_dhcp_socket_open(ni_dhcp_device_t *dev) { ni_capture_protinfo_t prot_info; ni_capture_t *capture; /* We need to bind to a port, otherwise Linux will generate * ICMP_UNREACHABLE messages telling the server that there's * no DHCP client listening at all. * * We don't actually use this fd at all, instead using our packet * filter socket. * * (It would be nice if we did, at least in BOUND/RENEWING state * where good manners would dictate unicast requests anyway). */ if (dev->listen_fd == -1) { struct sockaddr_in sin; struct ifreq ifr; int on = 1; int fd; if ((fd = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { ni_error("socket: %m"); return -1; } if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) ni_error("SO_REUSEADDR: %m"); if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &on, sizeof(on)) == -1) ni_error("SO_RCVBUF: %m"); memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, dev->ifname, sizeof(ifr.ifr_name)); if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) == -1) ni_error("SO_SOBINDTODEVICE: %m"); memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(DHCP_CLIENT_PORT); if (bind(fd, (struct sockaddr *) &sin, sizeof(sin)) == -1) { ni_error("bind: %m"); close(fd); } else { dev->listen_fd = fd; fcntl(fd, F_SETFD, FD_CLOEXEC); } } memset(&prot_info, 0, sizeof(prot_info)); prot_info.eth_protocol = ETHERTYPE_IP; prot_info.ip_protocol = IPPROTO_UDP; prot_info.ip_port = DHCP_CLIENT_PORT; if ((capture = dev->capture) != NULL) { if (ni_capture_is_valid(capture, ETHERTYPE_IP)) return 0; ni_capture_free(dev->capture); dev->capture = NULL; } dev->capture = ni_capture_open(&dev->system, &prot_info, ni_dhcp_socket_recv); if (!dev->capture) return -1; ni_capture_set_user_data(dev->capture, dev); return 0; }