1 /* $NetBSD: nit.c,v 1.1.1.2 2014/07/12 11:57:45 spz Exp $ */
4 Network Interface Tap (NIT) network interface code, by Ted Lemon
5 with one crucial tidbit of help from Stu Grossmen. */
8 * Copyright (c) 2004,2007,2009,2014 by Internet Systems Consortium, Inc. ("ISC")
9 * Copyright (c) 1996-2003 by Internet Software Consortium
11 * Permission to use, copy, modify, and distribute this software for any
12 * purpose with or without fee is hereby granted, provided that the above
13 * copyright notice and this permission notice appear in all copies.
15 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
16 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
18 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 * Internet Systems Consortium, Inc.
25 * Redwood City, CA 94063
27 * https://www.isc.org/
31 #include <sys/cdefs.h>
32 __RCSID("$NetBSD: nit.c,v 1.1.1.2 2014/07/12 11:57:45 spz Exp $");
35 #if defined (USE_NIT_SEND) || defined (USE_NIT_RECEIVE)
36 #include <sys/ioctl.h>
41 #include <net/nit_if.h>
42 #include <net/nit_pf.h>
43 #include <net/nit_buf.h>
44 #include <sys/stropts.h>
45 #include <net/packetfilt.h>
47 #include <netinet/in_systm.h>
48 #include "includes/netinet/ip.h"
49 #include "includes/netinet/udp.h"
50 #include "includes/netinet/if_ether.h"
52 /* Reinitializes the specified interface after an address change. This
53 is not required for packet-filter APIs. */
56 void if_reinitialize_send (info
)
57 struct interface_info
*info
;
62 #ifdef USE_NIT_RECEIVE
63 void if_reinitialize_receive (info
)
64 struct interface_info
*info
;
69 /* Called by get_interface_list for each interface that's discovered.
70 Opens a packet filter for each interface and adds it to the select
73 int if_register_nit (info
)
74 struct interface_info
*info
;
81 /* Open a NIT device */
82 sock
= open ("/dev/nit", O_RDWR
);
84 log_fatal ("Can't open NIT device for %s: %m", info
-> name
);
86 /* Set the NIT device to point at this interface. */
87 sio
.ic_cmd
= NIOCBIND
;
88 sio
.ic_len
= sizeof *(info
-> ifp
);
89 sio
.ic_dp
= (char *)(info
-> ifp
);
90 sio
.ic_timout
= INFTIM
;
91 if (ioctl (sock
, I_STR
, &sio
) < 0)
92 log_fatal ("Can't attach interface %s to nit device: %m",
95 /* Get the low-level address... */
96 sio
.ic_cmd
= SIOCGIFADDR
;
97 sio
.ic_len
= sizeof ifr
;
98 sio
.ic_dp
= (char *)&ifr
;
99 sio
.ic_timout
= INFTIM
;
100 if (ioctl (sock
, I_STR
, &sio
) < 0)
101 log_fatal ("Can't get physical layer address for %s: %m",
104 /* XXX code below assumes ethernet interface! */
105 info
-> hw_address
.hlen
= 7;
106 info
-> hw_address
.hbuf
[0] = ARPHRD_ETHER
;
107 memcpy (&info
-> hw_address
.hbuf
[1],
108 ifr
.ifr_ifru
.ifru_addr
.sa_data
, 6);
110 if (ioctl (sock
, I_PUSH
, "pf") < 0)
111 log_fatal ("Can't push packet filter onto NIT for %s: %m",
116 #endif /* USE_NIT_SEND || USE_NIT_RECEIVE */
119 void if_register_send (info
)
120 struct interface_info
*info
;
122 /* If we're using the nit API for sending and receiving,
123 we don't need to register this interface twice. */
124 #ifndef USE_NIT_RECEIVE
125 struct packetfilt pf
;
128 info
-> wfdesc
= if_register_nit (info
);
132 pf
.Pf_Filter
[0] = ENF_PUSHZERO
;
134 /* Set up an NIT filter that rejects everything... */
135 sio
.ic_cmd
= NIOCSETF
;
136 sio
.ic_len
= sizeof pf
;
137 sio
.ic_dp
= (char *)&pf
;
138 sio
.ic_timout
= INFTIM
;
139 if (ioctl (info
-> wfdesc
, I_STR
, &sio
) < 0)
140 log_fatal ("Can't set NIT filter: %m");
142 info
-> wfdesc
= info
-> rfdesc
;
144 if (!quiet_interface_discovery
)
145 log_info ("Sending on NIT/%s%s%s",
146 print_hw_addr (info
-> hw_address
.hbuf
[0],
147 info
-> hw_address
.hlen
- 1,
148 &info
-> hw_address
.hbuf
[1]),
149 (info
-> shared_network
? "/" : ""),
150 (info
-> shared_network
?
151 info
-> shared_network
-> name
: ""));
154 void if_deregister_send (info
)
155 struct interface_info
*info
;
157 /* If we're using the nit API for sending and receiving,
158 we don't need to register this interface twice. */
159 #ifndef USE_NIT_RECEIVE
160 close (info
-> wfdesc
);
163 if (!quiet_interface_discovery
)
164 log_info ("Disabling output on NIT/%s%s%s",
165 print_hw_addr (info
-> hw_address
.hbuf
[0],
166 info
-> hw_address
.hlen
- 1,
167 &info
-> hw_address
.hbuf
[1]),
168 (info
-> shared_network
? "/" : ""),
169 (info
-> shared_network
?
170 info
-> shared_network
-> name
: ""));
172 #endif /* USE_NIT_SEND */
174 #ifdef USE_NIT_RECEIVE
175 /* Packet filter program...
176 XXX Changes to the filter program may require changes to the constant
177 offsets used in if_register_send to patch the NIT program! XXX */
179 void if_register_receive (info
)
180 struct interface_info
*info
;
184 struct packetfilt pf
;
189 /* Open a NIT device and hang it on this interface... */
190 info
-> rfdesc
= if_register_nit (info
);
192 /* Set the snap length to 0, which means always take the whole
195 if (ioctl (info
-> rfdesc
, NIOCSSNAP
, &x
) < 0)
196 log_fatal ("Can't set NIT snap length on %s: %m", info
-> name
);
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
);
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");
207 /* Set the timeout to zero. */
210 if (ioctl (info
-> rfdesc
, NIOCSTIME
, &t
) < 0)
211 log_fatal ("Can't set chunk timeout: %m");
214 /* Ask for no header... */
216 if (ioctl (info
-> rfdesc
, NIOCSFLAGS
, &x
) < 0)
217 log_fatal ("Can't set NIT flags on %s: %m", info
-> name
);
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
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
;
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
);
247 if (!quiet_interface_discovery
)
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
: ""));
257 void if_deregister_receive (info
)
258 struct interface_info
*info
;
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
);
265 if (!quiet_interface_discovery
)
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
: ""));
274 #endif /* USE_NIT_RECEIVE */
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
;
283 struct sockaddr_in
*to
;
284 struct hardware
*hto
;
286 unsigned hbufp
, ibufp
;
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
;
295 if (!strcmp (interface
-> name
, "fallback"))
296 return send_fallback (interface
, packet
, raw
,
299 if (hto
== NULL
&& interface
->anycast_mac_addr
.hlen
)
300 hto
= &interface
->anycast_mac_addr
;
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]);
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
);
314 /* Copy the data into the buffer (yuk). */
315 memcpy (buf
+ ibufp
, raw
, len
);
317 /* Set up the sockaddr structure... */
319 junk
-> sa_len
= hbufp
- 2; /* XXX */
321 junk
-> sa_family
= AF_UNSPEC
;
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
;
329 result
= putmsg (interface
-> wfdesc
, &ctl
, &data
, 0);
331 log_error ("send_packet: %m");
334 #endif /* USE_NIT_SEND */
336 #ifdef USE_NIT_RECEIVE
337 ssize_t
receive_packet (interface
, buf
, len
, from
, hfrom
)
338 struct interface_info
*interface
;
341 struct sockaddr_in
*from
;
342 struct hardware
*hfrom
;
347 unsigned char ibuf
[1536];
351 length
= read (interface
-> rfdesc
, ibuf
, sizeof ibuf
);
355 /* Decode the physical header... */
356 offset
= decode_hw_header (interface
, ibuf
, bufix
, hfrom
);
358 /* If a physical layer checksum failed (dunno of any
359 physical layer that supports this, but WTH), skip this
368 /* Decode the IP and UDP headers... */
369 offset
= decode_udp_ip_header (interface
, ibuf
, bufix
,
370 from
, length
, &paylen
);
372 /* If the IP or UDP checksum was bad, skip the packet... */
380 log_fatal("Internal inconsistency at %s:%d.", MDL
);
382 /* Copy out the data in the packet... */
383 memcpy(buf
, &ibuf
[bufix
], paylen
);
387 int can_unicast_without_arp (ip
)
388 struct interface_info
*ip
;
393 int can_receive_unicast_unconfigured (ip
)
394 struct interface_info
*ip
;
399 int supports_multiple_interfaces (ip
)
400 struct interface_info
*ip
;
405 void maybe_setup_fallback ()
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
,
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
);