From: Roy Marples Date: Sun, 20 Apr 2008 19:02:19 +0000 (+0000) Subject: We should send packets to a specific IP over the udp socket so we don't broadcast... X-Git-Tag: v4.0.2~467 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=35ff0dbb35b746c5594773ddc47516af440cdae7;p=thirdparty%2Fdhcpcd.git We should send packets to a specific IP over the udp socket so we don't broadcast on layer 2 and unicast on layer 3, #64. --- diff --git a/bpf.c b/bpf.c index e419cb40..da75a315 100644 --- a/bpf.c +++ b/bpf.c @@ -122,8 +122,8 @@ eexit: } ssize_t -send_packet(const struct interface *iface, int type, - const unsigned char *data, ssize_t len) +send_raw_packet(const struct interface *iface, int type, + const unsigned char *data, ssize_t len) { struct iovec iov[2]; struct ether_header hw; diff --git a/client.c b/client.c index ae280230..48d17ac7 100644 --- a/client.c +++ b/client.c @@ -601,10 +601,12 @@ send_message(struct if_state *state, int type, const struct options *options) struct dhcp_message *dhcp; uint8_t *udp; ssize_t len; - ssize_t retval; + ssize_t r; struct in_addr from; struct in_addr to; + logger(LOG_DEBUG, "sending %s with xid 0x%x", + get_dhcp_op(type), state->xid); state->last_type = type; state->last_sent = uptime(); len = make_message(&dhcp, state->interface, &state->lease, state->xid, @@ -614,15 +616,19 @@ send_message(struct if_state *state, int type, const struct options *options) to.s_addr = state->lease.server.s_addr; else to.s_addr = 0; - len = make_udp_packet(&udp, (uint8_t *)dhcp, len, from, to); - free(dhcp); - logger(LOG_DEBUG, "sending %s with xid 0x%x", - get_dhcp_op(type), state->xid); - retval = send_packet(state->interface, ETHERTYPE_IP, udp, len); - if (retval == -1) - logger(LOG_ERR, "send_packet: %s", strerror(errno)); - free(udp); - return retval; + if (to.s_addr) { + r = send_packet(state->interface, to, (uint8_t *)dhcp, len); + if (r == -1) + logger(LOG_ERR, "send_packet: %s", strerror(errno)); + } else { + len = make_udp_packet(&udp, (uint8_t *)dhcp, len, from, to); + free(dhcp); + r = send_raw_packet(state->interface, ETHERTYPE_IP, udp, len); + if (r == -1) + logger(LOG_ERR, "send_raw_packet: %s", strerror(errno)); + free(udp); + } + return r; } static void @@ -809,7 +815,8 @@ handle_timeout(struct if_state *state, const struct options *options) do_socket(state, SOCKET_CLOSED); - if (options->options & DHCPCD_INFORM) + if (options->options & DHCPCD_INFORM || + options->options & DHCPCD_TEST) return -1; if (state->options & DHCPCD_IPV4LL || diff --git a/dhcp.c b/dhcp.c index ebd3284b..820f3dd5 100644 --- a/dhcp.c +++ b/dhcp.c @@ -696,8 +696,8 @@ make_message(struct dhcp_message **message, uint32_t xid, uint8_t type, const struct options *options) { struct dhcp_message *dhcp; - uint8_t *m; - uint8_t *p; + uint8_t *d, *m, *p; + const char *c; uint8_t *n_params = NULL; size_t l; time_t up = uptime() - iface->start_uptime; @@ -826,8 +826,9 @@ make_message(struct dhcp_message **message, } else { /* Draft IETF DHC-FQDN option (81) */ *p++ = DHCP_FQDN; - *p++ = (l = strlen(options->hostname)) + 3; - /* Flags: 0000NEOS + *p++ = strlen(options->hostname) + 5; + /* + * Flags: 0000NEOS * S: 1 => Client requests Server to update * a RR in DNS as well as PTR * O: 1 => Server indicates to client that @@ -836,11 +837,20 @@ make_message(struct dhcp_message **message, * N: 1 => Client requests Server to not * update DNS */ - *p++ = options->fqdn & 0x9; + *p++ = (options->fqdn & 0x9) | 0x4; *p++ = 0; /* from server for PTR RR */ *p++ = 0; /* from server for A RR if S=1 */ - memcpy(p, options->hostname, l); - p += l; + c = options->hostname; + d = p++; + while (*c) { + if (*c == '.') { + *d = p - d - 1; + d = p++; + } else + *p++ = (uint8_t) *c; + c++; + } + *p ++ = 0; } } diff --git a/dhcpcd.8.in b/dhcpcd.8.in index d187e8f8..8ff4f605 100644 --- a/dhcpcd.8.in +++ b/dhcpcd.8.in @@ -132,7 +132,9 @@ You can use this option to specify the sent, or an empty string to stop any .Ar hostname -from being sent. +from being sent. If +.Ar hostname +is an FQDN (ie, contains a .) then it will be encoded as such. .It Fl i , -classid Ar classid Override the DHCP vendor .Ar classid diff --git a/dhcpcd.conf.5 b/dhcpcd.conf.5 index 9b95fba1..9befff3a 100644 --- a/dhcpcd.conf.5 +++ b/dhcpcd.conf.5 @@ -46,7 +46,14 @@ from the server. It can be a variable to be used in or the numerical value. You can specify more seperated by commas, spaces or more option lines. .It Ic hostname Ar name -Sends specified hostname to the DHCP server so it can be registered in DNS. +Sends specified +.Ar hostname +o the DHCP server so it can be registered in DNS. If +.Ar hostname +if a FQDN (ie, contains a .) then it will be encoded a such. +.It Ic fqdn Op none | ptr | both +none disables FQDN encoding, ptr just asks the DHCP server to update the PTR +record of the host in DNS whereas both also updates the A record. .It Ic leasetime Ar seconds Request a leasetime of .Ar seconds . diff --git a/net.c b/net.c index 10661956..467cdf7e 100644 --- a/net.c +++ b/net.c @@ -443,6 +443,23 @@ eexit: return -1; } +ssize_t +send_packet(const struct interface *iface, struct in_addr to, + const uint8_t *data, ssize_t len) +{ + union sockunion { + struct sockaddr sa; + struct sockaddr_in sin; + } su; + + memset(&su, 0, sizeof(su)); + su.sin.sin_family = AF_INET; + su.sin.sin_addr.s_addr = to.s_addr; + su.sin.sin_port = htons(DHCP_SERVER_PORT); + + return sendto(iface->udp_fd, data, len, 0, &su.sa, sizeof(su)); +} + struct udp_dhcp_packet { struct ip ip; @@ -648,8 +665,8 @@ send_arp(const struct interface *iface, int op, struct in_addr sip, } memcpy(ar_tpa(arp), &tip, (size_t)arp->ar_pln); - retval = send_packet(iface, ETHERTYPE_ARP, - (unsigned char *) arp, arphdr_len(arp)); + retval = send_raw_packet(iface, ETHERTYPE_ARP, + (uint8_t *)arp, arphdr_len(arp)); if (retval == -1) logger(LOG_ERR,"send_packet: %s", strerror(errno)); free(arp); diff --git a/net.h b/net.h index d767a9ee..ef968e18 100644 --- a/net.h +++ b/net.h @@ -166,8 +166,10 @@ int valid_udp_packet(uint8_t *); void setup_packet_filters(void); #endif int open_socket(struct interface *, int); -ssize_t send_packet(const struct interface *, int, +ssize_t send_packet(const struct interface *, struct in_addr, const uint8_t *, ssize_t); +ssize_t send_raw_packet(const struct interface *, int, + const uint8_t *, ssize_t); ssize_t get_packet(const struct interface *, uint8_t *, uint8_t *, ssize_t *, ssize_t *); diff --git a/socket.c b/socket.c index 97a24be4..54d2706d 100644 --- a/socket.c +++ b/socket.c @@ -141,8 +141,8 @@ eexit: } ssize_t -send_packet(const struct interface *iface, int type, - const uint8_t *data, ssize_t len) +send_raw_packet(const struct interface *iface, int type, + const uint8_t *data, ssize_t len) { union sockunion { struct sockaddr sa; @@ -153,12 +153,10 @@ send_packet(const struct interface *iface, int type, memset(&su, 0, sizeof(su)); su.sll.sll_family = AF_PACKET; su.sll.sll_protocol = htons(type); - if (!(su.sll.sll_ifindex = if_nametoindex(iface->name))) { errno = ENOENT; return -1; } - su.sll.sll_hatype = htons(iface->family); su.sll.sll_halen = iface->hwlen; if (iface->family == ARPHRD_INFINIBAND) @@ -167,7 +165,7 @@ send_packet(const struct interface *iface, int type, else memset(&su.sll.sll_addr, 0xff, iface->hwlen); - return sendto(iface->fd, data, len,0,&su.sa,sizeof(su)); + return sendto(iface->fd, data, len, 0, &su.sa, sizeof(su)); } /* Linux has no need for the buffer as we can read as much as we want.