ISC DHCP  4.4.3-P1
A reference DHCPv4 and DHCPv6 implementation
nit.c
Go to the documentation of this file.
1 /* nit.c
2 
3  Network Interface Tap (NIT) network interface code, by Ted Lemon
4  with one crucial tidbit of help from Stu Grossmen. */
5 
6 /*
7  * Copyright (C) 2004-2022 Internet Systems Consortium, Inc. ("ISC")
8  * Copyright (c) 1996-2003 by Internet Software Consortium
9  *
10  * This Source Code Form is subject to the terms of the Mozilla Public
11  * License, v. 2.0. If a copy of the MPL was not distributed with this
12  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
15  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
17  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
20  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21  *
22  * Internet Systems Consortium, Inc.
23  * PO Box 360
24  * Newmarket, NH 03857 USA
25  * <info@isc.org>
26  * https://www.isc.org/
27  *
28  */
29 
30 #include "dhcpd.h"
31 #if defined (USE_NIT_SEND) || defined (USE_NIT_RECEIVE)
32 #include <sys/ioctl.h>
33 #include <sys/uio.h>
34 
35 #include <sys/time.h>
36 #include <net/nit.h>
37 #include <net/nit_if.h>
38 #include <net/nit_pf.h>
39 #include <net/nit_buf.h>
40 #include <sys/stropts.h>
41 #include <net/packetfilt.h>
42 
43 #include <netinet/in_systm.h>
44 #include "includes/netinet/ip.h"
45 #include "includes/netinet/udp.h"
47 
48 /* Reinitializes the specified interface after an address change. This
49  is not required for packet-filter APIs. */
50 
51 #ifdef USE_NIT_SEND
52 void if_reinitialize_send (info)
53  struct interface_info *info;
54 {
55 }
56 #endif
57 
58 #ifdef USE_NIT_RECEIVE
59 void if_reinitialize_receive (info)
60  struct interface_info *info;
61 {
62 }
63 #endif
64 
65 /* Called by get_interface_list for each interface that's discovered.
66  Opens a packet filter for each interface and adds it to the select
67  mask. */
68 
69 int if_register_nit (info)
70  struct interface_info *info;
71 {
72  int sock;
73  char filename[50];
74  struct ifreq ifr;
75  struct strioctl sio;
76 
77  /* Open a NIT device */
78  sock = open ("/dev/nit", O_RDWR | O_CLOEXEC);
79  if (sock < 0)
80  log_fatal ("Can't open NIT device for %s: %m", info -> name);
81 
82  /* Set the NIT device to point at this interface. */
83  sio.ic_cmd = NIOCBIND;
84  sio.ic_len = sizeof *(info -> ifp);
85  sio.ic_dp = (char *)(info -> ifp);
86  sio.ic_timout = INFTIM;
87  if (ioctl (sock, I_STR, &sio) < 0)
88  log_fatal ("Can't attach interface %s to nit device: %m",
89  info -> name);
90 
91  /* Get the low-level address... */
92  sio.ic_cmd = SIOCGIFADDR;
93  sio.ic_len = sizeof ifr;
94  sio.ic_dp = (char *)&ifr;
95  sio.ic_timout = INFTIM;
96  if (ioctl (sock, I_STR, &sio) < 0)
97  log_fatal ("Can't get physical layer address for %s: %m",
98  info -> name);
99 
100  /* XXX code below assumes ethernet interface! */
101  info -> hw_address.hlen = 7;
102  info -> hw_address.hbuf [0] = ARPHRD_ETHER;
103  memcpy (&info -> hw_address.hbuf [1],
104  ifr.ifr_ifru.ifru_addr.sa_data, 6);
105 
106  if (ioctl (sock, I_PUSH, "pf") < 0)
107  log_fatal ("Can't push packet filter onto NIT for %s: %m",
108  info -> name);
109 
110  return sock;
111 }
112 #endif /* USE_NIT_SEND || USE_NIT_RECEIVE */
113 
114 #ifdef USE_NIT_SEND
115 void if_register_send (info)
116  struct interface_info *info;
117 {
118  /* If we're using the nit API for sending and receiving,
119  we don't need to register this interface twice. */
120 #ifndef USE_NIT_RECEIVE
121  struct packetfilt pf;
122  struct strioctl sio;
123 
124  info -> wfdesc = if_register_nit (info);
125 
126  pf.Pf_Priority = 0;
127  pf.Pf_FilterLen = 1;
128  pf.Pf_Filter [0] = ENF_PUSHZERO;
129 
130  /* Set up an NIT filter that rejects everything... */
131  sio.ic_cmd = NIOCSETF;
132  sio.ic_len = sizeof pf;
133  sio.ic_dp = (char *)&pf;
134  sio.ic_timout = INFTIM;
135  if (ioctl (info -> wfdesc, I_STR, &sio) < 0)
136  log_fatal ("Can't set NIT filter: %m");
137 #else
138  info -> wfdesc = info -> rfdesc;
139 #endif
141  log_info ("Sending on NIT/%s%s%s",
142  print_hw_addr (info -> hw_address.hbuf [0],
143  info -> hw_address.hlen - 1,
144  &info -> hw_address.hbuf [1]),
145  (info -> shared_network ? "/" : ""),
146  (info -> shared_network ?
147  info -> shared_network -> name : ""));
148 }
149 
150 void if_deregister_send (info)
151  struct interface_info *info;
152 {
153  /* If we're using the nit API for sending and receiving,
154  we don't need to register this interface twice. */
155 #ifndef USE_NIT_RECEIVE
156  close (info -> wfdesc);
157 #endif
158  info -> wfdesc = -1;
160  log_info ("Disabling output on NIT/%s%s%s",
161  print_hw_addr (info -> hw_address.hbuf [0],
162  info -> hw_address.hlen - 1,
163  &info -> hw_address.hbuf [1]),
164  (info -> shared_network ? "/" : ""),
165  (info -> shared_network ?
166  info -> shared_network -> name : ""));
167 }
168 #endif /* USE_NIT_SEND */
169 
170 #ifdef USE_NIT_RECEIVE
171 /* Packet filter program...
172  XXX Changes to the filter program may require changes to the constant
173  offsets used in if_register_send to patch the NIT program! XXX */
174 
175 #if defined(RELAY_PORT)
176 #error "Relay port is not yet supported for NIT"
177 #endif
178 
179 void if_register_receive (info)
180  struct interface_info *info;
181 {
182  int flag = 1;
183  u_int32_t x;
184  struct packetfilt pf;
185  struct strioctl sio;
186  u_int16_t addr [2];
187  struct timeval t;
188 
189  /* Open a NIT device and hang it on this interface... */
190  info -> rfdesc = if_register_nit (info);
191 
192  /* Set the snap length to 0, which means always take the whole
193  packet. */
194  x = 0;
195  if (ioctl (info -> rfdesc, NIOCSSNAP, &x) < 0)
196  log_fatal ("Can't set NIT snap length on %s: %m", info -> name);
197 
198  /* Set the stream to byte stream mode */
199  if (ioctl (info -> rfdesc, I_SRDOPT, RMSGN) != 0)
200  log_info ("I_SRDOPT failed on %s: %m", info -> name);
201 
202 #if 0
203  /* Push on the chunker... */
204  if (ioctl (info -> rfdesc, I_PUSH, "nbuf") < 0)
205  log_fatal ("Can't push chunker onto NIT STREAM: %m");
206 
207  /* Set the timeout to zero. */
208  t.tv_sec = 0;
209  t.tv_usec = 0;
210  if (ioctl (info -> rfdesc, NIOCSTIME, &t) < 0)
211  log_fatal ("Can't set chunk timeout: %m");
212 #endif
213 
214  /* Ask for no header... */
215  x = 0;
216  if (ioctl (info -> rfdesc, NIOCSFLAGS, &x) < 0)
217  log_fatal ("Can't set NIT flags on %s: %m", info -> name);
218 
219  /* Set up the NIT filter program. */
220  /* XXX Unlike the BPF filter program, this one won't work if the
221  XXX IP packet is fragmented or if there are options on the IP
222  XXX header. */
223  pf.Pf_Priority = 0;
224  pf.Pf_FilterLen = 0;
225 
226  pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + 6;
227  pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT + ENF_CAND;
228  pf.Pf_Filter [pf.Pf_FilterLen++] = htons (ETHERTYPE_IP);
229  pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT;
230  pf.Pf_Filter [pf.Pf_FilterLen++] = htons (IPPROTO_UDP);
231  pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + 11;
232  pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT + ENF_AND;
233  pf.Pf_Filter [pf.Pf_FilterLen++] = htons (0xFF);
234  pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_CAND;
235  pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + 18;
236  pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT + ENF_CAND;
237  pf.Pf_Filter [pf.Pf_FilterLen++] = local_port;
238 
239  /* Install the filter... */
240  sio.ic_cmd = NIOCSETF;
241  sio.ic_len = sizeof pf;
242  sio.ic_dp = (char *)&pf;
243  sio.ic_timout = INFTIM;
244  if (ioctl (info -> rfdesc, I_STR, &sio) < 0)
245  log_fatal ("Can't set NIT filter on %s: %m", info -> name);
246 
248  log_info ("Listening on NIT/%s%s%s",
249  print_hw_addr (info -> hw_address.hbuf [0],
250  info -> hw_address.hlen - 1,
251  &info -> hw_address.hbuf [1]),
252  (info -> shared_network ? "/" : ""),
253  (info -> shared_network ?
254  info -> shared_network -> name : ""));
255 }
256 
257 void if_deregister_receive (info)
258  struct interface_info *info;
259 {
260  /* If we're using the nit API for sending and receiving,
261  we don't need to register this interface twice. */
262  close (info -> rfdesc);
263  info -> rfdesc = -1;
264 
266  log_info ("Disabling input on NIT/%s%s%s",
267  print_hw_addr (info -> hw_address.hbuf [0],
268  info -> hw_address.hlen - 1,
269  &info -> hw_address.hbuf [1]),
270  (info -> shared_network ? "/" : ""),
271  (info -> shared_network ?
272  info -> shared_network -> name : ""));
273 }
274 #endif /* USE_NIT_RECEIVE */
275 
276 #ifdef USE_NIT_SEND
277 ssize_t send_packet (interface, packet, raw, len, from, to, hto)
278  struct interface_info *interface;
279  struct packet *packet;
280  struct dhcp_packet *raw;
281  size_t len;
282  struct in_addr from;
283  struct sockaddr_in *to;
284  struct hardware *hto;
285 {
286  unsigned hbufp, ibufp;
287  double hh [16];
288  double ih [1536 / sizeof (double)];
289  unsigned char *buf = (unsigned char *)ih;
290  struct sockaddr *junk;
291  struct strbuf ctl, data;
292  struct sockaddr_in foo;
293  int result;
294 
295  if (!strcmp (interface -> name, "fallback"))
296  return send_fallback (interface, packet, raw,
297  len, from, to, hto);
298 
299  if (hto == NULL && interface->anycast_mac_addr.hlen)
300  hto = &interface->anycast_mac_addr;
301 
302  /* Start with the sockaddr struct... */
303  junk = (struct sockaddr *)&hh [0];
304  hbufp = (((unsigned char *)&junk -> sa_data [0]) -
305  (unsigned char *)&hh[0]);
306  ibufp = 0;
307 
308  /* Assemble the headers... */
309  assemble_hw_header (interface, (unsigned char *)junk, &hbufp, hto);
310  assemble_udp_ip_header (interface, buf, &ibufp,
311  from.s_addr, to -> sin_addr.s_addr,
312  to -> sin_port, (unsigned char *)raw, len);
313 
314  /* Copy the data into the buffer (yuk). */
315  memcpy (buf + ibufp, raw, len);
316 
317  /* Set up the sockaddr structure... */
318 #if USE_SIN_LEN
319  junk -> sa_len = hbufp - 2; /* XXX */
320 #endif
321  junk -> sa_family = AF_UNSPEC;
322 
323  /* Set up the msg_buf structure... */
324  ctl.buf = (char *)&hh [0];
325  ctl.maxlen = ctl.len = hbufp;
326  data.buf = (char *)&ih [0];
327  data.maxlen = data.len = ibufp + len;
328 
329  result = putmsg (interface -> wfdesc, &ctl, &data, 0);
330  if (result < 0)
331  log_error ("send_packet: %m");
332  return result;
333 }
334 #endif /* USE_NIT_SEND */
335 
336 #ifdef USE_NIT_RECEIVE
337 ssize_t receive_packet (interface, buf, len, from, hfrom)
338  struct interface_info *interface;
339  unsigned char *buf;
340  size_t len;
341  struct sockaddr_in *from;
342  struct hardware *hfrom;
343 {
344  int nread;
345  int length = 0;
346  int offset = 0;
347  unsigned char ibuf [1536];
348  int bufix = 0;
349  unsigned paylen;
350 
351  length = read (interface -> rfdesc, ibuf, sizeof ibuf);
352  if (length <= 0)
353  return length;
354 
355  /* Decode the physical header... */
356  offset = decode_hw_header (interface, ibuf, bufix, hfrom);
357 
358  /* If a physical layer checksum failed (dunno of any
359  physical layer that supports this, but WTH), skip this
360  packet. */
361  if (offset < 0) {
362  return 0;
363  }
364 
365  bufix += offset;
366  length -= offset;
367 
368  /* Decode the IP and UDP headers... */
369  offset = decode_udp_ip_header (interface, ibuf, bufix,
370  from, length, &paylen, 1);
371 
372  /* If the IP or UDP checksum was bad, skip the packet... */
373  if (offset < 0)
374  return 0;
375 
376  bufix += offset;
377  length -= offset;
378 
379  if (length < paylen)
380  log_fatal("Internal inconsistency at %s:%d.", MDL);
381 
382  /* Copy out the data in the packet... */
383  memcpy(buf, &ibuf[bufix], paylen);
384  return paylen;
385 }
386 
388  struct interface_info *ip;
389 {
390  return 1;
391 }
392 
394  struct interface_info *ip;
395 {
396  return 1;
397 }
398 
400  struct interface_info *ip;
401 {
402  return 1;
403 }
404 
405 void maybe_setup_fallback ()
406 {
407  isc_result_t status;
408  struct interface_info *fbi = (struct interface_info *)0;
409  if (setup_fallback (&fbi, MDL)) {
410  if_register_fallback (fbi);
411  status = omapi_register_io_object ((omapi_object_t *)fbi,
412  if_readsocket, 0,
413  fallback_discard, 0, 0);
414  if (status != ISC_R_SUCCESS)
415  log_fatal ("Can't register I/O handle for %s: %s",
416  fbi -> name, isc_result_totext (status));
417  interface_dereference (&fbi, MDL);
418  }
419 }
420 #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:1048
char name[IFNAMSIZ]
Definition: dhcpd.h:1408
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:1059
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: discover.c:48
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:1386
int int log_info(const char *,...) __attribute__((__format__(__printf__
#define ISC_R_SUCCESS
int quiet_interface_discovery
Definition: discover.c:47
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:1438
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