ISC DHCP  4.3.0
A reference DHCPv4 and DHCPv6 implementation
upf.c
Go to the documentation of this file.
1 /* upf.c
2 
3  Ultrix PacketFilter interface code. */
4 
5 /*
6  * Copyright (c) 2004,2007,2009,2014 by Internet Systems Consortium, Inc. ("ISC")
7  * Copyright (c) 1996-2003 by Internet Software Consortium
8  *
9  * Permission to use, copy, modify, and distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  *
21  * Internet Systems Consortium, Inc.
22  * 950 Charter Street
23  * Redwood City, CA 94063
24  * <info@isc.org>
25  * https://www.isc.org/
26  *
27  */
28 
29 #include "dhcpd.h"
30 #if defined (USE_UPF_SEND) || defined (USE_UPF_RECEIVE)
31 #include <sys/ioctl.h>
32 #include <sys/uio.h>
33 
34 #include <net/pfilt.h>
35 #include <netinet/in_systm.h>
36 #include "includes/netinet/ip.h"
37 #include "includes/netinet/udp.h"
39 
40 /* Reinitializes the specified interface after an address change. This
41  is not required for packet-filter APIs. */
42 
43 #ifdef USE_UPF_SEND
44 void if_reinitialize_send (info)
45  struct interface_info *info;
46 {
47 }
48 #endif
49 
50 #ifdef USE_UPF_RECEIVE
51 void if_reinitialize_receive (info)
52  struct interface_info *info;
53 {
54 }
55 #endif
56 
57 /* Called by get_interface_list for each interface that's discovered.
58  Opens a packet filter for each interface and adds it to the select
59  mask. */
60 
61 int if_register_upf (info)
62  struct interface_info *info;
63 {
64  int sock;
65  char filename[50];
66  int b;
67  struct endevp param;
68 
69  /* Open a UPF device */
70  for (b = 0; 1; b++) {
71  /* %Audit% Cannot exceed 36 bytes. %2004.06.17,Safe% */
72  sprintf(filename, "/dev/pf/pfilt%d", b);
73 
74  sock = open (filename, O_RDWR | O_CLOEXEC, 0);
75  if (sock < 0) {
76  if (errno == EBUSY) {
77  continue;
78  } else {
79  log_fatal ("Can't find free upf: %m");
80  }
81  } else {
82  break;
83  }
84  }
85 
86  /* Set the UPF device to point at this interface. */
87  if (ioctl (sock, EIOCSETIF, info -> ifp) < 0)
88  log_fatal ("Can't attach interface %s to upf device %s: %m",
89  info -> name, filename);
90 
91  /* Get the hardware address. */
92  if (ioctl (sock, EIOCDEVP, &param) < 0)
93  log_fatal ("Can't get interface %s hardware address: %m",
94  info -> name);
95 
96  /* We only know how to do ethernet. */
97  if (param.end_dev_type != ENDT_10MB)
98  log_fatal ("Invalid device type on network interface %s: %d",
99  info -> name, param.end_dev_type);
100 
101  if (param.end_addr_len != 6)
102  log_fatal ("Invalid hardware address length on %s: %d",
103  info -> name, param.end_addr_len);
104 
105  info -> hw_address.hlen = 7;
106  info -> hw_address.hbuf [0] = ARPHRD_ETHER;
107  memcpy (&info -> hw_address.hbuf [1], param.end_addr, 6);
108 
109  return sock;
110 }
111 #endif /* USE_UPF_SEND || USE_UPF_RECEIVE */
112 
113 #ifdef USE_UPF_SEND
114 void if_register_send (info)
115  struct interface_info *info;
116 {
117  /* If we're using the upf API for sending and receiving,
118  we don't need to register this interface twice. */
119 #ifndef USE_UPF_RECEIVE
120  info -> wfdesc = if_register_upf (info, interface);
121 #else
122  info -> wfdesc = info -> rfdesc;
123 #endif
125  log_info ("Sending on UPF/%s/%s%s%s",
126  info -> name,
127  print_hw_addr (info -> hw_address.hbuf [0],
128  info -> hw_address.hlen - 1,
129  &info -> hw_address.hbuf [1]),
130  (info -> shared_network ? "/" : ""),
131  (info -> shared_network ?
132  info -> shared_network -> name : ""));
133 }
134 
135 void if_deregister_send (info)
136  struct interface_info *info;
137 {
138 #ifndef USE_UPF_RECEIVE
139  close (info -> wfdesc);
140 #endif
141  info -> wfdesc = -1;
143  log_info ("Disabling output on UPF/%s/%s%s%s",
144  info -> name,
145  print_hw_addr (info -> hw_address.hbuf [0],
146  info -> hw_address.hlen - 1,
147  &info -> hw_address.hbuf [1]),
148  (info -> shared_network ? "/" : ""),
149  (info -> shared_network ?
150  info -> shared_network -> name : ""));
151 }
152 #endif /* USE_UPF_SEND */
153 
154 #ifdef USE_UPF_RECEIVE
155 /* Packet filter program...
156  XXX Changes to the filter program may require changes to the constant
157  offsets used in if_register_send to patch the UPF program! XXX */
158 
159 
160 void if_register_receive (info)
161  struct interface_info *info;
162 {
163  int flag = 1;
164  u_int32_t addr;
165  struct enfilter pf;
166  u_int32_t bits;
167 
168  /* Open a UPF device and hang it on this interface... */
169  info -> rfdesc = if_register_upf (info);
170 
171  /* Allow the copyall flag to be set... */
172  if (ioctl(info -> rfdesc, EIOCALLOWCOPYALL, &flag) < 0)
173  log_fatal ("Can't set ALLOWCOPYALL: %m");
174 
175  /* Clear all the packet filter mode bits first... */
176  flag = (ENHOLDSIG | ENBATCH | ENTSTAMP | ENPROMISC |
177  ENNONEXCL | ENCOPYALL);
178  if (ioctl (info -> rfdesc, EIOCMBIC, &flag) < 0)
179  log_fatal ("Can't clear pfilt bits: %m");
180 
181  /* Set the ENBATCH and ENCOPYALL bits... */
182  bits = ENBATCH | ENCOPYALL;
183  if (ioctl (info -> rfdesc, EIOCMBIS, &bits) < 0)
184  log_fatal ("Can't set ENBATCH|ENCOPYALL: %m");
185 
186  /* Set up the UPF filter program. */
187  /* XXX Unlike the BPF filter program, this one won't work if the
188  XXX IP packet is fragmented or if there are options on the IP
189  XXX header. */
190  pf.enf_Priority = 0;
191  pf.enf_FilterLen = 0;
192 
193  pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 6;
194  pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_CAND;
195  pf.enf_Filter [pf.enf_FilterLen++] = htons (ETHERTYPE_IP);
196  pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT;
197  pf.enf_Filter [pf.enf_FilterLen++] = htons (IPPROTO_UDP);
198  pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 11;
199  pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_AND;
200  pf.enf_Filter [pf.enf_FilterLen++] = htons (0xFF);
201  pf.enf_Filter [pf.enf_FilterLen++] = ENF_CAND;
202  pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 18;
203  pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_CAND;
204  pf.enf_Filter [pf.enf_FilterLen++] = local_port;
205 
206  if (ioctl (info -> rfdesc, EIOCSETF, &pf) < 0)
207  log_fatal ("Can't install packet filter program: %m");
209  log_info ("Listening on UPF/%s/%s%s%s",
210  info -> name,
211  print_hw_addr (info -> hw_address.hbuf [0],
212  info -> hw_address.hlen - 1,
213  &info -> hw_address.hbuf [1]),
214  (info -> shared_network ? "/" : ""),
215  (info -> shared_network ?
216  info -> shared_network -> name : ""));
217 }
218 
219 void if_deregister_receive (info)
220  struct interface_info *info;
221 {
222  close (info -> rfdesc);
223  info -> rfdesc = -1;
225  log_info ("Disabling input on UPF/%s/%s%s%s",
226  info -> name,
227  print_hw_addr (info -> hw_address.hbuf [0],
228  info -> hw_address.hlen - 1,
229  &info -> hw_address.hbuf [1]),
230  (info -> shared_network ? "/" : ""),
231  (info -> shared_network ?
232  info -> shared_network -> name : ""));
233 }
234 #endif /* USE_UPF_RECEIVE */
235 
236 #ifdef USE_UPF_SEND
237 ssize_t send_packet (interface, packet, raw, len, from, to, hto)
238  struct interface_info *interface;
239  struct packet *packet;
240  struct dhcp_packet *raw;
241  size_t len;
242  struct in_addr from;
243  struct sockaddr_in *to;
244  struct hardware *hto;
245 {
246  unsigned hbufp = 0, ibufp = 0;
247  double hw [4];
248  double ip [32];
249  struct iovec iov [3];
250  int result;
251  int fudge;
252 
253  if (!strcmp (interface -> name, "fallback"))
254  return send_fallback (interface, packet, raw,
255  len, from, to, hto);
256 
257  if (hto == NULL && interface->anycast_mac_addr.hlen)
258  hto = &interface->anycast_mac_addr;
259 
260  /* Assemble the headers... */
261  assemble_hw_header (interface, (unsigned char *)hw, &hbufp, hto);
262  assemble_udp_ip_header (interface,
263  (unsigned char *)ip, &ibufp, from.s_addr,
264  to -> sin_addr.s_addr, to -> sin_port,
265  (unsigned char *)raw, len);
266 
267  /* Fire it off */
268  iov [0].iov_base = ((char *)hw);
269  iov [0].iov_len = hbufp;
270  iov [1].iov_base = ((char *)ip);
271  iov [1].iov_len = ibufp;
272  iov [2].iov_base = (char *)raw;
273  iov [2].iov_len = len;
274 
275  result = writev(interface -> wfdesc, iov, 3);
276  if (result < 0)
277  log_error ("send_packet: %m");
278  return result;
279 }
280 #endif /* USE_UPF_SEND */
281 
282 #ifdef USE_UPF_RECEIVE
283 ssize_t receive_packet (interface, buf, len, from, hfrom)
284  struct interface_info *interface;
285  unsigned char *buf;
286  size_t len;
287  struct sockaddr_in *from;
288  struct hardware *hfrom;
289 {
290  int nread;
291  int length = 0;
292  int offset = 0;
293  unsigned char ibuf [1500 + sizeof (struct enstamp)];
294  int bufix = 0;
295  unsigned paylen;
296 
297  length = read (interface -> rfdesc, ibuf, sizeof ibuf);
298  if (length <= 0)
299  return length;
300 
301  bufix = sizeof (struct enstamp);
302  /* Decode the physical header... */
303  offset = decode_hw_header (interface, ibuf, bufix, hfrom);
304 
305  /* If a physical layer checksum failed (dunno of any
306  physical layer that supports this, but WTH), skip this
307  packet. */
308  if (offset < 0) {
309  return 0;
310  }
311 
312  bufix += offset;
313  length -= offset;
314 
315  /* Decode the IP and UDP headers... */
316  offset = decode_udp_ip_header (interface, ibuf, bufix,
317  from, length, &paylen, 0);
318 
319  /* If the IP or UDP checksum was bad, skip the packet... */
320  if (offset < 0)
321  return 0;
322 
323  bufix += offset;
324  length -= offset;
325 
326  if (length < paylen)
327  log_fatal("Internal inconsistency at %s:%d.", MDL);
328 
329  /* Copy out the data in the packet... */
330  memcpy (buf, &ibuf[bufix], paylen);
331  return paylen;
332 }
333 
335  struct interface_info *ip;
336 {
337  return 1;
338 }
339 
341  struct interface_info *ip;
342 {
343  return 1;
344 }
345 
347  struct interface_info *ip;
348 {
349  return 1;
350 }
351 
352 void maybe_setup_fallback ()
353 {
354  isc_result_t status;
355  struct interface_info *fbi = (struct interface_info *)0;
356  if (setup_fallback (&fbi, MDL)) {
357  if_register_fallback (fbi);
358  status = omapi_register_io_object ((omapi_object_t *)fbi,
359  if_readsocket, 0,
360  fallback_discard, 0, 0);
361  if (status != ISC_R_SUCCESS)
362  log_fatal ("Can't register I/O handle for %s: %s",
363  fbi -> name, isc_result_totext (status));
364  interface_dereference (&fbi, MDL);
365  }
366 }
367 #endif
void if_register_send(struct interface_info *)
isc_result_t omapi_register_io_object(omapi_object_t *, int(*)(omapi_object_t *), int(*)(omapi_object_t *), isc_result_t(*)(omapi_object_t *), isc_result_t(*)(omapi_object_t *), isc_result_t(*)(omapi_object_t *))
Definition: dispatch.c:199
void assemble_udp_ip_header(struct interface_info *, unsigned char *, unsigned *, u_int32_t, u_int32_t, u_int32_t, unsigned char *, unsigned)
#define ETHERTYPE_IP
Definition: if_ether.h:57
u_int8_t hlen
Definition: dhcpd.h:440
int if_readsocket(omapi_object_t *h)
Definition: discover.c:961
char name[IFNAMSIZ]
Definition: dhcpd.h:1267
void if_reinitialize_send(struct interface_info *)
ssize_t decode_udp_ip_header(struct interface_info *, unsigned char *, unsigned, struct sockaddr_in *, unsigned, unsigned *, int)
#define MDL
Definition: omapip.h:568
int can_receive_unicast_unconfigured(struct interface_info *)
int setup_fallback(struct interface_info **fp, const char *file, int line)
Definition: discover.c:972
int log_error(const char *,...) __attribute__((__format__(__printf__
void if_deregister_receive(struct interface_info *)
void maybe_setup_fallback(void)
void if_deregister_send(struct interface_info *)
void log_fatal(const char *,...) __attribute__((__format__(__printf__
u_int16_t local_port
Definition: dhclient.c:87
Definition: dhcpd.h:369
void assemble_hw_header(struct interface_info *, unsigned char *, unsigned *, struct hardware *)
Definition: ip.h:47
ssize_t send_packet(struct interface_info *, struct packet *, struct dhcp_packet *, size_t, struct in_addr, struct sockaddr_in *, struct hardware *)
struct hardware hw_address
Definition: dhcpd.h:1245
int int log_info(const char *,...) __attribute__((__format__(__printf__
int quiet_interface_discovery
Definition: discover.c:42
void if_register_fallback(struct interface_info *)
ssize_t send_fallback(struct interface_info *, struct packet *, struct dhcp_packet *, size_t, struct in_addr, struct sockaddr_in *, struct hardware *)
int supports_multiple_interfaces(struct interface_info *)
u_int8_t hbuf[HARDWARE_ADDR_LEN+1]
Definition: dhcpd.h:441
struct hardware anycast_mac_addr
Definition: dhcpd.h:1296
ssize_t receive_packet(struct interface_info *, unsigned char *, size_t, struct sockaddr_in *, struct hardware *)
ssize_t decode_hw_header(struct interface_info *, unsigned char *, unsigned, struct hardware *)
void if_reinitialize_receive(struct interface_info *)
int can_unicast_without_arp(struct interface_info *)
void if_register_receive(struct interface_info *)
isc_result_t fallback_discard(omapi_object_t *)