}
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;
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,
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
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 ||
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;
} 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
* 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;
}
}
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
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 .
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;
}
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);
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 *);
}
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;
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)
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.