ISC DHCP  4.4.2b1
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-2017 by Internet Systems Consortium, Inc. ("ISC")
7  * Copyright (c) 1996-2003 by Internet Software Consortium
8  *
9  * This Source Code Form is subject to the terms of the Mozilla Public
10  * License, v. 2.0. If a copy of the MPL was not distributed with this
11  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
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 #if defined(RELAY_PORT)
160 #error "Relay port is not yet supported for UPF"
161 #endif
162 
163 void if_register_receive (info)
164  struct interface_info *info;
165 {
166  int flag = 1;
167  u_int32_t addr;
168  struct enfilter pf;
169  u_int32_t bits;
170 
171  /* Open a UPF device and hang it on this interface... */
172  info -> rfdesc = if_register_upf (info);
173 
174  /* Allow the copyall flag to be set... */
175  if (ioctl(info -> rfdesc, EIOCALLOWCOPYALL, &flag) < 0)
176  log_fatal ("Can't set ALLOWCOPYALL: %m");
177 
178  /* Clear all the packet filter mode bits first... */
179  flag = (ENHOLDSIG | ENBATCH | ENTSTAMP | ENPROMISC |
180  ENNONEXCL | ENCOPYALL);
181  if (ioctl (info -> rfdesc, EIOCMBIC, &flag) < 0)
182  log_fatal ("Can't clear pfilt bits: %m");
183 
184  /* Set the ENBATCH and ENCOPYALL bits... */
185  bits = ENBATCH | ENCOPYALL;
186  if (ioctl (info -> rfdesc, EIOCMBIS, &bits) < 0)
187  log_fatal ("Can't set ENBATCH|ENCOPYALL: %m");
188 
189  /* Set up the UPF filter program. */
190  /* XXX Unlike the BPF filter program, this one won't work if the
191  XXX IP packet is fragmented or if there are options on the IP
192  XXX header. */
193  pf.enf_Priority = 0;
194  pf.enf_FilterLen = 0;
195 
196  pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 6;
197  pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_CAND;
198  pf.enf_Filter [pf.enf_FilterLen++] = htons (ETHERTYPE_IP);
199  pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT;
200  pf.enf_Filter [pf.enf_FilterLen++] = htons (IPPROTO_UDP);
201  pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 11;
202  pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_AND;
203  pf.enf_Filter [pf.enf_FilterLen++] = htons (0xFF);
204  pf.enf_Filter [pf.enf_FilterLen++] = ENF_CAND;
205  pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 18;
206  pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_CAND;
207  pf.enf_Filter [pf.enf_FilterLen++] = local_port;
208 
209  if (ioctl (info -> rfdesc, EIOCSETF, &pf) < 0)
210  log_fatal ("Can't install packet filter program: %m");
212  log_info ("Listening on UPF/%s/%s%s%s",
213  info -> name,
214  print_hw_addr (info -> hw_address.hbuf [0],
215  info -> hw_address.hlen - 1,
216  &info -> hw_address.hbuf [1]),
217  (info -> shared_network ? "/" : ""),
218  (info -> shared_network ?
219  info -> shared_network -> name : ""));
220 }
221 
222 void if_deregister_receive (info)
223  struct interface_info *info;
224 {
225  close (info -> rfdesc);
226  info -> rfdesc = -1;
228  log_info ("Disabling input on UPF/%s/%s%s%s",
229  info -> name,
230  print_hw_addr (info -> hw_address.hbuf [0],
231  info -> hw_address.hlen - 1,
232  &info -> hw_address.hbuf [1]),
233  (info -> shared_network ? "/" : ""),
234  (info -> shared_network ?
235  info -> shared_network -> name : ""));
236 }
237 #endif /* USE_UPF_RECEIVE */
238 
239 #ifdef USE_UPF_SEND
240 ssize_t send_packet (interface, packet, raw, len, from, to, hto)
241  struct interface_info *interface;
242  struct packet *packet;
243  struct dhcp_packet *raw;
244  size_t len;
245  struct in_addr from;
246  struct sockaddr_in *to;
247  struct hardware *hto;
248 {
249  unsigned hbufp = 0, ibufp = 0;
250  double hw [4];
251  double ip [32];
252  struct iovec iov [3];
253  int result;
254  int fudge;
255 
256  if (!strcmp (interface -> name, "fallback"))
257  return send_fallback (interface, packet, raw,
258  len, from, to, hto);
259 
260  if (hto == NULL && interface->anycast_mac_addr.hlen)
261  hto = &interface->anycast_mac_addr;
262 
263  /* Assemble the headers... */
264  assemble_hw_header (interface, (unsigned char *)hw, &hbufp, hto);
265  assemble_udp_ip_header (interface,
266  (unsigned char *)ip, &ibufp, from.s_addr,
267  to -> sin_addr.s_addr, to -> sin_port,
268  (unsigned char *)raw, len);
269 
270  /* Fire it off */
271  iov [0].iov_base = ((char *)hw);
272  iov [0].iov_len = hbufp;
273  iov [1].iov_base = ((char *)ip);
274  iov [1].iov_len = ibufp;
275  iov [2].iov_base = (char *)raw;
276  iov [2].iov_len = len;
277 
278  result = writev(interface -> wfdesc, iov, 3);
279  if (result < 0)
280  log_error ("send_packet: %m");
281  return result;
282 }
283 #endif /* USE_UPF_SEND */
284 
285 #ifdef USE_UPF_RECEIVE
286 ssize_t receive_packet (interface, buf, len, from, hfrom)
287  struct interface_info *interface;
288  unsigned char *buf;
289  size_t len;
290  struct sockaddr_in *from;
291  struct hardware *hfrom;
292 {
293  int nread;
294  int length = 0;
295  int offset = 0;
296  unsigned char ibuf [1500 + sizeof (struct enstamp)];
297  int bufix = 0;
298  unsigned paylen;
299 
300  length = read (interface -> rfdesc, ibuf, sizeof ibuf);
301  if (length <= 0)
302  return length;
303 
304  bufix = sizeof (struct enstamp);
305  /* Decode the physical header... */
306  offset = decode_hw_header (interface, ibuf, bufix, hfrom);
307 
308  /* If a physical layer checksum failed (dunno of any
309  physical layer that supports this, but WTH), skip this
310  packet. */
311  if (offset < 0) {
312  return 0;
313  }
314 
315  bufix += offset;
316  length -= offset;
317 
318  /* Decode the IP and UDP headers... */
319  offset = decode_udp_ip_header (interface, ibuf, bufix,
320  from, length, &paylen, 1);
321 
322  /* If the IP or UDP checksum was bad, skip the packet... */
323  if (offset < 0)
324  return 0;
325 
326  bufix += offset;
327  length -= offset;
328 
329  if (length < paylen)
330  log_fatal("Internal inconsistency at %s:%d.", MDL);
331 
332  /* Copy out the data in the packet... */
333  memcpy (buf, &ibuf[bufix], paylen);
334  return paylen;
335 }
336 
338  struct interface_info *ip;
339 {
340  return 1;
341 }
342 
344  struct interface_info *ip;
345 {
346  return 1;
347 }
348 
350  struct interface_info *ip;
351 {
352  return 1;
353 }
354 
355 void maybe_setup_fallback ()
356 {
357  isc_result_t status;
358  struct interface_info *fbi = (struct interface_info *)0;
359  if (setup_fallback (&fbi, MDL)) {
360  if_register_fallback (fbi);
361  status = omapi_register_io_object ((omapi_object_t *)fbi,
362  if_readsocket, 0,
363  fallback_discard, 0, 0);
364  if (status != ISC_R_SUCCESS)
365  log_fatal ("Can't register I/O handle for %s: %s",
366  fbi -> name, isc_result_totext (status));
367  interface_dereference (&fbi, MDL);
368  }
369 }
370 #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:198
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:492
int if_readsocket(omapi_object_t *h)
Definition: discover.c:1045
char name[IFNAMSIZ]
Definition: dhcpd.h:1403
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:567
int can_receive_unicast_unconfigured(struct interface_info *)
int setup_fallback(struct interface_info **fp, const char *file, int line)
Definition: discover.c:1056
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:96
Definition: dhcpd.h:405
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:1381
int int log_info(const char *,...) __attribute__((__format__(__printf__
#define ISC_R_SUCCESS
int quiet_interface_discovery
Definition: discover.c:44
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:493
struct hardware anycast_mac_addr
Definition: dhcpd.h:1433
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 *)
char * print_hw_addr(int htype, const int hlen, const unsigned char *data) const
Definition: print.c:171