upf.c 10.2 KB
Newer Older
Ted Lemon's avatar
Ted Lemon committed
1 2
/* upf.c

Ted Lemon's avatar
Ted Lemon committed
3
   Ultrix PacketFilter interface code. */
Ted Lemon's avatar
Ted Lemon committed
4 5

/*
6
 * Copyright (c) 2004-2017 by Internet Systems Consortium, Inc. ("ISC")
7
 * Copyright (c) 1996-2003 by Internet Software Consortium
Ted Lemon's avatar
Ted Lemon committed
8
 *
9 10 11
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
Ted Lemon's avatar
Ted Lemon committed
12
 *
13 14 15 16 17 18 19
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Ted Lemon's avatar
Ted Lemon committed
20
 *
21 22 23 24
 *   Internet Systems Consortium, Inc.
 *   950 Charter Street
 *   Redwood City, CA 94063
 *   <info@isc.org>
25
 *   https://www.isc.org/
Ted Lemon's avatar
Ted Lemon committed
26
 *
Ted Lemon's avatar
Ted Lemon committed
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
 */

#include "dhcpd.h"
#if defined (USE_UPF_SEND) || defined (USE_UPF_RECEIVE)
#include <sys/ioctl.h>
#include <sys/uio.h>

#include <net/pfilt.h>
#include <netinet/in_systm.h>
#include "includes/netinet/ip.h"
#include "includes/netinet/udp.h"
#include "includes/netinet/if_ether.h"

/* Reinitializes the specified interface after an address change.   This
   is not required for packet-filter APIs. */

#ifdef USE_UPF_SEND
void if_reinitialize_send (info)
	struct interface_info *info;
{
}
#endif

#ifdef USE_UPF_RECEIVE
void if_reinitialize_receive (info)
	struct interface_info *info;
{
}
#endif

/* Called by get_interface_list for each interface that's discovered.
   Opens a packet filter for each interface and adds it to the select
   mask. */

int if_register_upf (info)
	struct interface_info *info;
{
	int sock;
	char filename[50];
	int b;
	struct endevp param;

	/* Open a UPF device */
	for (b = 0; 1; b++) {
71
		/* %Audit% Cannot exceed 36 bytes. %2004.06.17,Safe% */
Ted Lemon's avatar
Ted Lemon committed
72
		sprintf(filename, "/dev/pf/pfilt%d", b);
73

Ted Lemon's avatar
Ted Lemon committed
74 75 76 77 78
		sock = open (filename, O_RDWR, 0);
		if (sock < 0) {
			if (errno == EBUSY) {
				continue;
			} else {
79
				log_fatal ("Can't find free upf: %m");
Ted Lemon's avatar
Ted Lemon committed
80 81 82 83 84 85 86 87
			}
		} else {
			break;
		}
	}

	/* Set the UPF device to point at this interface. */
	if (ioctl (sock, EIOCSETIF, info -> ifp) < 0)
88
		log_fatal ("Can't attach interface %s to upf device %s: %m",
Ted Lemon's avatar
Ted Lemon committed
89 90 91 92
		       info -> name, filename);

	/* Get the hardware address. */
	if (ioctl (sock, EIOCDEVP, &param) < 0)
93
		log_fatal ("Can't get interface %s hardware address: %m",
Ted Lemon's avatar
Ted Lemon committed
94 95 96 97
		       info -> name);

	/* We only know how to do ethernet. */
	if (param.end_dev_type != ENDT_10MB)	
98
		log_fatal ("Invalid device type on network interface %s: %d",
Ted Lemon's avatar
Ted Lemon committed
99 100 101
		       info -> name, param.end_dev_type);

	if (param.end_addr_len != 6)
102
		log_fatal ("Invalid hardware address length on %s: %d",
Ted Lemon's avatar
Ted Lemon committed
103 104
		       info -> name, param.end_addr_len);

Ted Lemon's avatar
Ted Lemon committed
105 106 107
	info -> hw_address.hlen = 7;
	info -> hw_address.hbuf [0] = ARPHRD_ETHER;
	memcpy (&info -> hw_address.hbuf [1], param.end_addr, 6);
Ted Lemon's avatar
Ted Lemon committed
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123

	return sock;
}
#endif /* USE_UPF_SEND || USE_UPF_RECEIVE */

#ifdef USE_UPF_SEND
void if_register_send (info)
	struct interface_info *info;
{
	/* If we're using the upf API for sending and receiving,
	   we don't need to register this interface twice. */
#ifndef USE_UPF_RECEIVE
	info -> wfdesc = if_register_upf (info, interface);
#else
	info -> wfdesc = info -> rfdesc;
#endif
124
        if (!quiet_interface_discovery)
125
		log_info ("Sending on   UPF/%s/%s%s%s",
126
		      info -> name,
Ted Lemon's avatar
Ted Lemon committed
127 128 129
		      print_hw_addr (info -> hw_address.hbuf [0],
				     info -> hw_address.hlen - 1,
				     &info -> hw_address.hbuf [1]),
130
		      (info -> shared_network ? "/" : ""),
131
		      (info -> shared_network ?
132
		       info -> shared_network -> name : ""));
Ted Lemon's avatar
Ted Lemon committed
133
}
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151

void if_deregister_send (info)
	struct interface_info *info;
{
#ifndef USE_UPF_RECEIVE
	close (info -> wfdesc);
#endif
	info -> wfdesc = -1;
        if (!quiet_interface_discovery)
		log_info ("Disabling output on UPF/%s/%s%s%s",
		      info -> name,
		      print_hw_addr (info -> hw_address.hbuf [0],
				     info -> hw_address.hlen - 1,
				     &info -> hw_address.hbuf [1]),
		      (info -> shared_network ? "/" : ""),
		      (info -> shared_network ?
		       info -> shared_network -> name : ""));
}
Ted Lemon's avatar
Ted Lemon committed
152 153 154 155 156 157 158
#endif /* USE_UPF_SEND */

#ifdef USE_UPF_RECEIVE
/* Packet filter program...
   XXX Changes to the filter program may require changes to the constant
   offsets used in if_register_send to patch the UPF program! XXX */

Francis Dupont's avatar
Francis Dupont committed
159 160 161
#if defined(RELAY_PORT)
#error "Relay port is not yet supported for UPF"
#endif
Ted Lemon's avatar
Ted Lemon committed
162 163 164 165 166 167 168 169 170 171 172 173 174 175

void if_register_receive (info)
	struct interface_info *info;
{
	int flag = 1;
	u_int32_t addr;
	struct enfilter pf;
	u_int32_t bits;

	/* Open a UPF device and hang it on this interface... */
	info -> rfdesc = if_register_upf (info);

	/* Allow the copyall flag to be set... */
	if (ioctl(info -> rfdesc, EIOCALLOWCOPYALL, &flag) < 0)
176
		log_fatal ("Can't set ALLOWCOPYALL: %m");
Ted Lemon's avatar
Ted Lemon committed
177 178 179 180 181

	/* Clear all the packet filter mode bits first... */
	flag = (ENHOLDSIG | ENBATCH | ENTSTAMP | ENPROMISC |
		ENNONEXCL | ENCOPYALL);
	if (ioctl (info -> rfdesc, EIOCMBIC, &flag) < 0)
182
		log_fatal ("Can't clear pfilt bits: %m");
Ted Lemon's avatar
Ted Lemon committed
183 184 185 186

	/* Set the ENBATCH and ENCOPYALL bits... */
	bits = ENBATCH | ENCOPYALL;
	if (ioctl (info -> rfdesc, EIOCMBIS, &bits) < 0)
187
		log_fatal ("Can't set ENBATCH|ENCOPYALL: %m");
Ted Lemon's avatar
Ted Lemon committed
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209

	/* Set up the UPF filter program. */
	/* XXX Unlike the BPF filter program, this one won't work if the
	   XXX IP packet is fragmented or if there are options on the IP
	   XXX header. */
	pf.enf_Priority = 0;
	pf.enf_FilterLen = 0;

	pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 6;
	pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_CAND;
	pf.enf_Filter [pf.enf_FilterLen++] = htons (ETHERTYPE_IP);
	pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT;
	pf.enf_Filter [pf.enf_FilterLen++] = htons (IPPROTO_UDP);
	pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 11;
	pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_AND;
	pf.enf_Filter [pf.enf_FilterLen++] = htons (0xFF);
	pf.enf_Filter [pf.enf_FilterLen++] = ENF_CAND;
	pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 18;
	pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_CAND;
	pf.enf_Filter [pf.enf_FilterLen++] = local_port;

	if (ioctl (info -> rfdesc, EIOCSETF, &pf) < 0)
210
		log_fatal ("Can't install packet filter program: %m");
211
        if (!quiet_interface_discovery)
212
		log_info ("Listening on UPF/%s/%s%s%s",
213
		      info -> name,
Ted Lemon's avatar
Ted Lemon committed
214 215 216
		      print_hw_addr (info -> hw_address.hbuf [0],
				     info -> hw_address.hlen - 1,
				     &info -> hw_address.hbuf [1]),
217
		      (info -> shared_network ? "/" : ""),
218
		      (info -> shared_network ?
219
		       info -> shared_network -> name : ""));
Ted Lemon's avatar
Ted Lemon committed
220
}
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236

void if_deregister_receive (info)
	struct interface_info *info;
{
	close (info -> rfdesc);
	info -> rfdesc = -1;
        if (!quiet_interface_discovery)
		log_info ("Disabling input on UPF/%s/%s%s%s",
		      info -> name,
		      print_hw_addr (info -> hw_address.hbuf [0],
				     info -> hw_address.hlen - 1,
				     &info -> hw_address.hbuf [1]),
		      (info -> shared_network ? "/" : ""),
		      (info -> shared_network ?
		       info -> shared_network -> name : ""));
}
Ted Lemon's avatar
Ted Lemon committed
237 238 239
#endif /* USE_UPF_RECEIVE */

#ifdef USE_UPF_SEND
240
ssize_t send_packet (interface, packet, raw, len, from, to, hto)
Ted Lemon's avatar
Ted Lemon committed
241 242 243 244 245 246 247 248
	struct interface_info *interface;
	struct packet *packet;
	struct dhcp_packet *raw;
	size_t len;
	struct in_addr from;
	struct sockaddr_in *to;
	struct hardware *hto;
{
249 250 251 252
	unsigned hbufp = 0, ibufp = 0;
	double hw [4];
	double ip [32];
	struct iovec iov [3];
253
	int result;
254
	int fudge;
Ted Lemon's avatar
Ted Lemon committed
255

Ted Lemon's avatar
Ted Lemon committed
256 257 258 259
	if (!strcmp (interface -> name, "fallback"))
		return send_fallback (interface, packet, raw,
				      len, from, to, hto);

260 261 262
	if (hto == NULL && interface->anycast_mac_addr.hlen)
		hto = &interface->anycast_mac_addr;

Ted Lemon's avatar
Ted Lemon committed
263
	/* Assemble the headers... */
264 265 266
	assemble_hw_header (interface, (unsigned char *)hw, &hbufp, hto);
	assemble_udp_ip_header (interface,
				(unsigned char *)ip, &ibufp, from.s_addr,
Ted Lemon's avatar
Ted Lemon committed
267 268 269 270
				to -> sin_addr.s_addr, to -> sin_port,
				(unsigned char *)raw, len);

	/* Fire it off */
271 272 273 274 275 276 277 278
	iov [0].iov_base = ((char *)hw);
	iov [0].iov_len = hbufp;
	iov [1].iov_base = ((char *)ip);
	iov [1].iov_len = ibufp;
	iov [2].iov_base = (char *)raw;
	iov [2].iov_len = len;

	result = writev(interface -> wfdesc, iov, 3);
279
	if (result < 0)
Ted Lemon's avatar
Ted Lemon committed
280
		log_error ("send_packet: %m");
281
	return result;
Ted Lemon's avatar
Ted Lemon committed
282 283 284 285
}
#endif /* USE_UPF_SEND */

#ifdef USE_UPF_RECEIVE
286
ssize_t receive_packet (interface, buf, len, from, hfrom)
Ted Lemon's avatar
Ted Lemon committed
287 288 289 290 291 292 293 294 295 296 297
	struct interface_info *interface;
	unsigned char *buf;
	size_t len;
	struct sockaddr_in *from;
	struct hardware *hfrom;
{
	int nread;
	int length = 0;
	int offset = 0;
	unsigned char ibuf [1500 + sizeof (struct enstamp)];
	int bufix = 0;
298
	unsigned paylen;
Ted Lemon's avatar
Ted Lemon committed
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319

	length = read (interface -> rfdesc, ibuf, sizeof ibuf);
	if (length <= 0)
		return length;

	bufix = sizeof (struct enstamp);
	/* Decode the physical header... */
	offset = decode_hw_header (interface, ibuf, bufix, hfrom);

	/* If a physical layer checksum failed (dunno of any
	   physical layer that supports this, but WTH), skip this
	   packet. */
	if (offset < 0) {
		return 0;
	}

	bufix += offset;
	length -= offset;

	/* Decode the IP and UDP headers... */
	offset = decode_udp_ip_header (interface, ibuf, bufix,
320
				       from, length, &paylen, 1);
Ted Lemon's avatar
Ted Lemon committed
321 322 323 324 325 326 327 328

	/* If the IP or UDP checksum was bad, skip the packet... */
	if (offset < 0)
		return 0;

	bufix += offset;
	length -= offset;

329 330 331
	if (length < paylen)
		log_fatal("Internal inconsistency at %s:%d.", MDL);

Ted Lemon's avatar
Ted Lemon committed
332
	/* Copy out the data in the packet... */
333 334
	memcpy (buf, &ibuf[bufix], paylen);
	return paylen;
Ted Lemon's avatar
Ted Lemon committed
335
}
Ted Lemon's avatar
Ted Lemon committed
336

Ted Lemon's avatar
Ted Lemon committed
337 338
int can_unicast_without_arp (ip)
	struct interface_info *ip;
Ted Lemon's avatar
Ted Lemon committed
339 340 341 342
{
	return 1;
}

Ted Lemon's avatar
Ted Lemon committed
343 344
int can_receive_unicast_unconfigured (ip)
	struct interface_info *ip;
345 346 347 348
{
	return 1;
}

349 350 351 352 353 354
int supports_multiple_interfaces (ip)
	struct interface_info *ip;
{
	return 1;
}

Ted Lemon's avatar
Ted Lemon committed
355 356
void maybe_setup_fallback ()
{
Ted Lemon's avatar
Ted Lemon committed
357
	isc_result_t status;
358 359
	struct interface_info *fbi = (struct interface_info *)0;
	if (setup_fallback (&fbi, MDL)) {
Ted Lemon's avatar
Ted Lemon committed
360
		if_register_fallback (fbi);
361
		status = omapi_register_io_object ((omapi_object_t *)fbi,
Ted Lemon's avatar
Ted Lemon committed
362 363 364 365 366
						   if_readsocket, 0,
						   fallback_discard, 0, 0);
		if (status != ISC_R_SUCCESS)
			log_fatal ("Can't register I/O handle for %s: %s",
				   fbi -> name, isc_result_totext (status));
367
		interface_dereference (&fbi, MDL);
Ted Lemon's avatar
Ted Lemon committed
368 369
	}
}
Ted Lemon's avatar
Ted Lemon committed
370
#endif