]> git.saurik.com Git - apple/xnu.git/blame_incremental - bsd/net/packet_mangler.c
xnu-2782.30.5.tar.gz
[apple/xnu.git] / bsd / net / packet_mangler.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 2014 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http: www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24/*
25 * THEORY OF OPERATION
26 *
27 * The packet mangler subsystem provides a limited way for user space
28 * applications to apply certain actions on certain flows.
29 *
30 * A user space applications opens a kernel control socket with the name
31 * PACKET_MANGLER_CONTROL_NAME to attach to the packet mangler subsystem.
32 * When connected, a "struct packet_mangler" is created and set as the
33 * "unitinfo" of the corresponding kernel control socket instance.
34 * Connect call for packet mangler's kernel control socket also registers
35 * ip filers with cookie set to the packet_mangler instance.
36 * The ip filters are removed when control socket is disconnected.
37 */
38#include <sys/types.h>
39#include <sys/kern_control.h>
40#include <sys/domain.h>
41#include <sys/protosw.h>
42#include <sys/syslog.h>
43
44#include <kern/locks.h>
45#include <kern/zalloc.h>
46#include <kern/debug.h>
47
48#include <net/packet_mangler.h>
49
50#include <netinet/tcp.h>
51#include <netinet/tcp_var.h>
52#include <netinet/ip.h>
53#include <netinet/kpi_ipfilter.h>
54#include <string.h>
55#include <libkern/libkern.h>
56
57#define MAX_PACKET_MANGLER 1
58
59#define PKT_MNGLR_FLG_IPFILTER_ATTACHED 0x00000001
60
61SYSCTL_NODE(_net, OID_AUTO, pktmnglr, CTLFLAG_RW|CTLFLAG_LOCKED, 0, "pktmnglr");
62SYSCTL_INT(_net_pktmnglr, OID_AUTO, log, CTLFLAG_RW|CTLFLAG_LOCKED,
63 &pkt_mnglr_log_level, 0, "");
64/*
65 * The structure packet_mangler represents a user space packet filter
66 * It's created and associated with a kernel control socket instance
67 */
68struct packet_mangler {
69 kern_ctl_ref pkt_mnglr_kcref;
70 uint32_t pkt_mnglr_kcunit;
71 uint32_t pkt_mnglr_flags;
72 /* IP filter related params */
73 ipfilter_t pkt_mnglr_ipfref;
74 ipfilter_t pkt_mnglr_ipfrefv6;
75 struct ipf_filter pkt_mnglr_ipfilter;
76
77 /* Options */
78 uint8_t activate;
79 Pkt_Mnglr_Flow dir;
80 struct sockaddr_storage lsaddr;
81 struct sockaddr_storage rsaddr;
82 struct sockaddr_storage swap_lsaddr;
83 struct sockaddr_storage swap_rsaddr;
84 uint32_t ip_action_mask;
85 uint16_t lport;
86 uint16_t rport;
87 uint32_t proto;
88 uint32_t proto_action_mask;
89};
90
91/* Array of all the packet mangler instancesi */
92struct packet_mangler **packet_manglers = NULL;
93
94uint32_t pkt_mnglr_active_count = 0; /* Number of active packet filters */
95uint32_t pkt_mnglr_close_wait_timeout = 1000; /* in milliseconds */
96
97static kern_ctl_ref pkt_mnglr_kctlref = NULL;
98
99static lck_grp_attr_t *pkt_mnglr_lck_grp_attr = NULL;
100static lck_attr_t *pkt_mnglr_lck_attr = NULL;
101static lck_grp_t *pkt_mnglr_lck_grp = NULL;
102
103/* The lock below protects packet_manglers DS, packet_mangler DS */
104decl_lck_rw_data(static, pkt_mnglr_lck_rw);
105
106#define PKT_MNGLR_RW_LCK_MAX 8
107
108int pkt_mnglr_rw_nxt_lck = 0;
109void* pkt_mnglr_rw_lock_history[PKT_MNGLR_RW_LCK_MAX];
110
111int pkt_mnglr_rw_nxt_unlck = 0;
112void* pkt_mnglr_rw_unlock_history[PKT_MNGLR_RW_LCK_MAX];
113
114
115#define PACKET_MANGLER_ZONE_NAME "packet_mangler"
116#define PACKET_MANGLER_ZONE_MAX 10
117static struct zone *packet_mangler_zone = NULL; /* zone for packet_mangler */
118
119/*
120 * For troubleshooting
121 */
122int pkt_mnglr_log_level = LOG_ERR;
123int pkt_mnglr_debug = 1;
124
125/*
126 * Forward declaration to appease the compiler
127 */
128static void pkt_mnglr_rw_lock_exclusive(lck_rw_t *);
129static void pkt_mnglr_rw_unlock_exclusive(lck_rw_t *);
130static void pkt_mnglr_rw_lock_shared(lck_rw_t *);
131static void pkt_mnglr_rw_unlock_shared(lck_rw_t *);
132
133static errno_t pktmnglr_ipfilter_output(void *cookie, mbuf_t *data,
134 ipf_pktopts_t options);
135static errno_t pktmnglr_ipfilter_input(void *cookie, mbuf_t *data,
136 int offset, u_int8_t protocol);
137static void pktmnglr_ipfilter_detach(void *cookie);
138
139static void chksm_update(mbuf_t data);
140
141/*
142 * packet filter global read write lock
143 */
144
145static void
146pkt_mnglr_rw_lock_exclusive(lck_rw_t *lck)
147{
148 void *lr_saved;
149
150 lr_saved = __builtin_return_address(0);
151
152 lck_rw_lock_exclusive(lck);
153
154 pkt_mnglr_rw_lock_history[pkt_mnglr_rw_nxt_lck] = lr_saved;
155 pkt_mnglr_rw_nxt_lck =
156 (pkt_mnglr_rw_nxt_lck + 1) % PKT_MNGLR_RW_LCK_MAX;
157}
158
159static void
160pkt_mnglr_rw_unlock_exclusive(lck_rw_t *lck)
161{
162 void *lr_saved;
163
164 lr_saved = __builtin_return_address(0);
165
166 lck_rw_unlock_exclusive(lck);
167
168 pkt_mnglr_rw_unlock_history[pkt_mnglr_rw_nxt_unlck] =
169 lr_saved;
170 pkt_mnglr_rw_nxt_unlck = (pkt_mnglr_rw_nxt_unlck + 1) % PKT_MNGLR_RW_LCK_MAX;
171}
172
173static void
174pkt_mnglr_rw_lock_shared(lck_rw_t *lck)
175{
176 void *lr_saved;
177
178 lr_saved = __builtin_return_address(0);
179
180 lck_rw_lock_shared(lck);
181
182 pkt_mnglr_rw_lock_history[pkt_mnglr_rw_nxt_lck] = lr_saved;
183 pkt_mnglr_rw_nxt_lck = (pkt_mnglr_rw_nxt_lck + 1) % PKT_MNGLR_RW_LCK_MAX;
184}
185
186static void
187pkt_mnglr_rw_unlock_shared(lck_rw_t *lck)
188{
189 void *lr_saved;
190
191 lr_saved = __builtin_return_address(0);
192
193 lck_rw_unlock_shared(lck);
194
195 pkt_mnglr_rw_unlock_history[pkt_mnglr_rw_nxt_unlck] = lr_saved;
196 pkt_mnglr_rw_nxt_unlck = (pkt_mnglr_rw_nxt_unlck + 1) % PKT_MNGLR_RW_LCK_MAX;
197}
198
199/*
200 * Packet Mangler's Kernel control socket callbacks
201 */
202static errno_t
203pkt_mnglr_ctl_connect(kern_ctl_ref kctlref, struct sockaddr_ctl *sac,
204 void **unitinfo)
205{
206 errno_t error = 0;
207 struct packet_mangler *p_pkt_mnglr = NULL;
208
209 PKT_MNGLR_LOG(LOG_NOTICE, "Connecting packet mangler filter.");
210
211 p_pkt_mnglr = zalloc(packet_mangler_zone);
212 if (p_pkt_mnglr == NULL) {
213 PKT_MNGLR_LOG(LOG_ERR, "zalloc failed");
214 error = ENOMEM;
215 goto done;
216 }
217
218 bzero(p_pkt_mnglr, sizeof(struct packet_mangler));
219
220 pkt_mnglr_rw_lock_exclusive(&pkt_mnglr_lck_rw);
221 if (packet_manglers == NULL) {
222 struct packet_mangler **tmp;
223
224 pkt_mnglr_rw_unlock_exclusive(&pkt_mnglr_lck_rw);
225
226 MALLOC(tmp,
227 struct packet_mangler **,
228 MAX_PACKET_MANGLER * sizeof(struct packet_mangler *),
229 M_TEMP,
230 M_WAITOK | M_ZERO);
231
232 pkt_mnglr_rw_lock_exclusive(&pkt_mnglr_lck_rw);
233
234 if (tmp == NULL && packet_manglers == NULL) {
235 error = ENOMEM;
236 pkt_mnglr_rw_unlock_exclusive(&pkt_mnglr_lck_rw);
237 goto done;
238 }
239 /* Another thread may have won the race */
240 if (packet_manglers != NULL)
241 FREE(tmp, M_TEMP);
242 else
243 packet_manglers = tmp;
244 }
245
246 if (sac->sc_unit == 0 || sac->sc_unit > MAX_PACKET_MANGLER) {
247 PKT_MNGLR_LOG(LOG_ERR, "bad sc_unit %u", sac->sc_unit);
248 error = EINVAL;
249 } else if (packet_manglers[sac->sc_unit - 1] != NULL) {
250 PKT_MNGLR_LOG(LOG_ERR, "sc_unit %u in use", sac->sc_unit);
251 error = EADDRINUSE;
252 } else {
253 /*
254 * kernel control socket kcunit numbers start at 1
255 */
256 packet_manglers[sac->sc_unit - 1] = p_pkt_mnglr;
257
258 p_pkt_mnglr->pkt_mnglr_kcref = kctlref;
259 p_pkt_mnglr->pkt_mnglr_kcunit = sac->sc_unit;
260
261 *unitinfo = p_pkt_mnglr;
262 pkt_mnglr_active_count++;
263 }
264
265 p_pkt_mnglr->pkt_mnglr_ipfilter.cookie = p_pkt_mnglr;
266 p_pkt_mnglr->pkt_mnglr_ipfilter.name = "com.apple.pktmnglripfilter";
267 p_pkt_mnglr->pkt_mnglr_ipfilter.ipf_input = pktmnglr_ipfilter_input;
268 p_pkt_mnglr->pkt_mnglr_ipfilter.ipf_output = pktmnglr_ipfilter_output;
269 p_pkt_mnglr->pkt_mnglr_ipfilter.ipf_detach = pktmnglr_ipfilter_detach;
270 error = ipf_addv4(&(p_pkt_mnglr->pkt_mnglr_ipfilter), &(p_pkt_mnglr->pkt_mnglr_ipfref));
271 if (error) {
272 PKT_MNGLR_LOG(LOG_ERR, "Could not register packet mangler's IPv4 Filter");
273 goto done;
274 }
275 error = ipf_addv6(&(p_pkt_mnglr->pkt_mnglr_ipfilter), &(p_pkt_mnglr->pkt_mnglr_ipfrefv6));
276 if (error) {
277 ipf_remove(p_pkt_mnglr->pkt_mnglr_ipfref);
278 PKT_MNGLR_LOG(LOG_ERR, "Could not register packet mangler's IPv6 Filter");
279 goto done;
280 }
281
282 PKT_MNGLR_LOG(LOG_INFO, "Registered packet mangler's IP Filters");
283 p_pkt_mnglr->pkt_mnglr_flags |= PKT_MNGLR_FLG_IPFILTER_ATTACHED;
284 pkt_mnglr_rw_unlock_exclusive(&pkt_mnglr_lck_rw);
285
286done:
287 if (error != 0 && p_pkt_mnglr != NULL)
288 zfree(packet_mangler_zone, p_pkt_mnglr);
289
290 PKT_MNGLR_LOG(LOG_INFO, "return %d pkt_mnglr_active_count %u kcunit %u",
291 error, pkt_mnglr_active_count, sac->sc_unit);
292
293 return (error);
294}
295
296static errno_t
297pkt_mnglr_ctl_disconnect(kern_ctl_ref kctlref, u_int32_t kcunit, void *unitinfo)
298{
299#pragma unused(kctlref)
300 errno_t error = 0;
301 struct packet_mangler *p_pkt_mnglr;
302
303 PKT_MNGLR_LOG(LOG_INFO, "Disconnecting packet mangler kernel control");
304
305 if (packet_manglers == NULL) {
306 PKT_MNGLR_LOG(LOG_ERR, "no packet filter");
307 error = EINVAL;
308 goto done;
309 }
310 if (kcunit > MAX_PACKET_MANGLER) {
311 PKT_MNGLR_LOG(LOG_ERR, "kcunit %u > MAX_PACKET_MANGLER (%d)",
312 kcunit, MAX_PACKET_MANGLER);
313 error = EINVAL;
314 goto done;
315 }
316
317 p_pkt_mnglr = (struct packet_mangler *)unitinfo;
318 if (p_pkt_mnglr == NULL) {
319 PKT_MNGLR_LOG(LOG_ERR, "Unit info is NULL");
320 goto done;
321 }
322
323 pkt_mnglr_rw_lock_exclusive(&pkt_mnglr_lck_rw);
324 if (packet_manglers[kcunit - 1] != p_pkt_mnglr || p_pkt_mnglr->pkt_mnglr_kcunit != kcunit) {
325 PKT_MNGLR_LOG(LOG_ERR, "bad unit info %u)",
326 kcunit);
327 pkt_mnglr_rw_unlock_exclusive(&pkt_mnglr_lck_rw);
328 goto done;
329 }
330
331 /*
332 * Make filter inactive
333 */
334 packet_manglers[kcunit - 1] = NULL;
335 pkt_mnglr_active_count--;
336 if (p_pkt_mnglr->pkt_mnglr_flags & PKT_MNGLR_FLG_IPFILTER_ATTACHED) {
337 (void) ipf_remove(p_pkt_mnglr->pkt_mnglr_ipfref);
338 (void) ipf_remove(p_pkt_mnglr->pkt_mnglr_ipfrefv6);
339 }
340 pkt_mnglr_rw_unlock_exclusive(&pkt_mnglr_lck_rw);
341 zfree(packet_mangler_zone, p_pkt_mnglr);
342done:
343 PKT_MNGLR_LOG(LOG_INFO, "return %d pkt_mnglr_active_count %u kcunit %u",
344 error, pkt_mnglr_active_count, kcunit);
345
346 return (error);
347}
348
349static errno_t
350pkt_mnglr_ctl_getopt(kern_ctl_ref kctlref, u_int32_t kcunit, void *unitinfo,
351 int opt, void *data, size_t *len)
352{
353#pragma unused(kctlref, opt)
354 errno_t error = 0;
355 struct packet_mangler *p_pkt_mnglr = (struct packet_mangler *)unitinfo;
356
357 PKT_MNGLR_LOG(LOG_NOTICE, "");
358
359 pkt_mnglr_rw_lock_shared(&pkt_mnglr_lck_rw);
360
361 if (packet_manglers == NULL) {
362 PKT_MNGLR_LOG(LOG_ERR, "no packet filter");
363 error = EINVAL;
364 goto done;
365 }
366 if (kcunit > MAX_PACKET_MANGLER) {
367 PKT_MNGLR_LOG(LOG_ERR, "kcunit %u > MAX_PACKET_MANGLER (%d)",
368 kcunit, MAX_PACKET_MANGLER);
369 error = EINVAL;
370 goto done;
371 }
372 if (p_pkt_mnglr != (void *)packet_manglers[kcunit - 1]) {
373 PKT_MNGLR_LOG(LOG_ERR, "unitinfo does not match for kcunit %u",
374 kcunit);
375 error = EINVAL;
376 goto done;
377 }
378 switch (opt) {
379 case PKT_MNGLR_OPT_PROTO_ACT_MASK:
380 if (*len < sizeof(uint32_t)) {
381 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_PROTO_ACT_MASK "
382 "len too small %lu", *len);
383 error = EINVAL;
384 goto done;
385 }
386
387 if (data != NULL) {
388 *(uint32_t *)data = p_pkt_mnglr->proto_action_mask;
389 }
390 break;
391 case PKT_MNGLR_OPT_IP_ACT_MASK:
392 if (*len < sizeof(uint32_t)) {
393 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_IP_ACT_MASK "
394 "len too small %lu", *len);
395 error = EINVAL;
396 goto done;
397 }
398
399 if (data != NULL) {
400 *(uint32_t *)data = p_pkt_mnglr->ip_action_mask;
401 }
402 break;
403 case PKT_MNGLR_OPT_LOCAL_IP:
404 if (*len < sizeof(struct sockaddr_storage)) {
405 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_LOCAL_IP "
406 "len too small %lu", *len);
407 error = EINVAL;
408 goto done;
409 }
410
411 if (data != NULL) {
412 *(struct sockaddr_storage *)data = p_pkt_mnglr->lsaddr;
413 }
414 break;
415 case PKT_MNGLR_OPT_REMOTE_IP:
416 if (*len < sizeof(struct sockaddr_storage)) {
417 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_REMOTE_IP "
418 "len too small %lu", *len);
419 error = EINVAL;
420 goto done;
421 }
422
423 if (data != NULL) {
424 *(struct sockaddr_storage *)data = p_pkt_mnglr->rsaddr;
425 }
426 break;
427 case PKT_MNGLR_OPT_LOCAL_PORT:
428 if (*len < sizeof(uint16_t)) {
429 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_LOCAL_PORT "
430 "len too small %lu", *len);
431 error = EINVAL;
432 goto done;
433 }
434
435 if (data != NULL) {
436 *(uint16_t *)data = p_pkt_mnglr->lport;
437 }
438 break;
439 case PKT_MNGLR_OPT_REMOTE_PORT:
440 if (*len < sizeof(uint16_t)) {
441 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_REMOTE_PORT "
442 "len too small %lu", *len);
443 error = EINVAL;
444 goto done;
445 }
446
447 if (data != NULL) {
448 *(uint16_t *)data = p_pkt_mnglr->rport;
449 }
450 break;
451 case PKT_MNGLR_OPT_DIRECTION:
452 if (*len < sizeof(uint32_t)) {
453 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_DIRECTION "
454 "len too small %lu", *len);
455 error = EINVAL;
456 goto done;
457 }
458 if (data != NULL) {
459 *(uint32_t *)data = p_pkt_mnglr->dir;
460 }
461 break;
462 case PKT_MNGLR_OPT_PROTOCOL:
463 if (*len < sizeof(uint32_t)) {
464 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_PROTOCOL "
465 "len too small %lu", *len);
466 error = EINVAL;
467 goto done;
468 }
469 if (data != NULL) {
470 *(uint32_t *)data = p_pkt_mnglr->proto;
471 }
472 break;
473 case PKT_MNGLR_OPT_ACTIVATE:
474 if (*len < sizeof(uint8_t)) {
475 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_ACTIVATE "
476 "len too small %lu", *len);
477 error = EINVAL;
478 goto done;
479 }
480
481 if (data != NULL) {
482 *(uint8_t *)data = p_pkt_mnglr->activate;
483 }
484 break;
485 default:
486 error = ENOPROTOOPT;
487 break;
488 }
489done:
490 pkt_mnglr_rw_unlock_shared(&pkt_mnglr_lck_rw);
491
492 return (error);
493}
494
495static errno_t
496pkt_mnglr_ctl_setopt(kern_ctl_ref kctlref, u_int32_t kcunit, void *unitinfo,
497 int opt, void *data, size_t len)
498{
499#pragma unused(kctlref, opt)
500 errno_t error = 0;
501 struct packet_mangler *p_pkt_mnglr = (struct packet_mangler *)unitinfo;
502
503 PKT_MNGLR_LOG(LOG_NOTICE, "");
504
505 pkt_mnglr_rw_lock_exclusive(&pkt_mnglr_lck_rw);
506
507 if (packet_manglers == NULL) {
508 PKT_MNGLR_LOG(LOG_ERR, "no packet filter");
509 error = EINVAL;
510 goto done;
511 }
512 if (kcunit > MAX_PACKET_MANGLER) {
513 PKT_MNGLR_LOG(LOG_ERR, "kcunit %u > MAX_PACKET_MANGLER (%d)",
514 kcunit, MAX_PACKET_MANGLER);
515 error = EINVAL;
516 goto done;
517 }
518 if (p_pkt_mnglr != (void *)packet_manglers[kcunit - 1]) {
519 PKT_MNGLR_LOG(LOG_ERR, "unitinfo does not match for kcunit %u",
520 kcunit);
521 error = EINVAL;
522 goto done;
523 }
524 switch (opt) {
525 case PKT_MNGLR_OPT_PROTO_ACT_MASK:
526 if (len < sizeof(uint32_t)) {
527 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_PROTO_ACT_MASK "
528 "len too small %lu", len);
529 error = EINVAL;
530 goto done;
531 }
532 if (p_pkt_mnglr->proto_action_mask != 0) {
533 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_PROTO_ACT_MASK "
534 "already set %u",
535 p_pkt_mnglr->proto_action_mask);
536 error = EINVAL;
537 goto done;
538 }
539 p_pkt_mnglr->proto_action_mask = *(uint32_t *)data;
540 PKT_MNGLR_LOG(LOG_INFO, "p_pkt_mnglr->proto_action_mask set to :%d", p_pkt_mnglr->proto_action_mask);
541 break;
542 case PKT_MNGLR_OPT_IP_ACT_MASK:
543 if (len < sizeof(uint32_t)) {
544 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_IP_ACT_MASK "
545 "len too small %lu", len);
546 error = EINVAL;
547 goto done;
548 }
549 if (p_pkt_mnglr->ip_action_mask != 0) {
550 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_IP_ACT_MASK "
551 "already set %u",
552 p_pkt_mnglr->ip_action_mask);
553 error = EINVAL;
554 goto done;
555 }
556 p_pkt_mnglr->ip_action_mask = *(uint32_t *)data;
557 break;
558 case PKT_MNGLR_OPT_LOCAL_IP:
559 if (len < sizeof(struct sockaddr_storage)) {
560 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_LOCAL_IP "
561 "len too small %lu", len);
562 error = EINVAL;
563 goto done;
564 }
565 if (p_pkt_mnglr->lsaddr.ss_family) {
566 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_LOCAL_IP "
567 "already set");
568 error = EINVAL;
569 goto done;
570 }
571 p_pkt_mnglr->lsaddr = *(struct sockaddr_storage *)data;
572 break;
573 case PKT_MNGLR_OPT_REMOTE_IP:
574 if (len < sizeof(struct sockaddr_storage)) {
575 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_REMOTE_IP "
576 "len too small %lu", len);
577 error = EINVAL;
578 goto done;
579 }
580 if (p_pkt_mnglr->rsaddr.ss_family) {
581 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_REMOTE_IP "
582 "already set");
583 error = EINVAL;
584 goto done;
585 }
586
587 p_pkt_mnglr->rsaddr = *(struct sockaddr_storage *)data;
588 PKT_MNGLR_LOG(LOG_INFO,
589 "Remote IP registered for address family: %d",
590 p_pkt_mnglr->rsaddr.ss_family);
591 break;
592 case PKT_MNGLR_OPT_LOCAL_PORT:
593 if (len < sizeof(uint16_t)) {
594 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_LOCAL_PORT "
595 "len too small %lu", len);
596 error = EINVAL;
597 goto done;
598 }
599 if (p_pkt_mnglr->lport != 0) {
600 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_LOCAL_PORT "
601 "already set %d",
602 p_pkt_mnglr->lport);
603 error = EINVAL;
604 goto done;
605 }
606 p_pkt_mnglr->lport = *(uint16_t *)data;
607 break;
608 case PKT_MNGLR_OPT_REMOTE_PORT:
609 if (len < sizeof(uint16_t)) {
610 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_REMOTE_PORT "
611 "len too small %lu", len);
612 error = EINVAL;
613 goto done;
614 }
615 if (p_pkt_mnglr->rport != 0) {
616 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_REMOTE_PORT "
617 "already set %d",
618 p_pkt_mnglr->rport);
619 error = EINVAL;
620 goto done;
621 }
622 p_pkt_mnglr->rport = *(uint16_t *)data;
623 break;
624 case PKT_MNGLR_OPT_DIRECTION:
625 if (len < sizeof(uint32_t)) {
626 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_DIRECTION "
627 "len too small %lu", len);
628 error = EINVAL;
629 goto done;
630 }
631 if (p_pkt_mnglr->dir != 0) {
632 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_DIRECTION "
633 "already set %u",
634 p_pkt_mnglr->dir);
635 error = EINVAL;
636 goto done;
637 }
638 p_pkt_mnglr->dir = *(uint32_t *)data;
639 break;
640 case PKT_MNGLR_OPT_PROTOCOL:
641 if (len < sizeof(uint32_t)) {
642 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_PROTOCOL "
643 "len too small %lu", len);
644 error = EINVAL;
645 goto done;
646 }
647 if (p_pkt_mnglr->proto != 0) {
648 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_PROTOCOL "
649 "already set %u",
650 p_pkt_mnglr->proto);
651 error = EINVAL;
652 goto done;
653 }
654 p_pkt_mnglr->proto = *(uint32_t *)data;
655 break;
656 case PKT_MNGLR_OPT_ACTIVATE:
657 if (len < sizeof(uint8_t)) {
658 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_ACTIVATE "
659 "len too small %lu", len);
660 error = EINVAL;
661 goto done;
662 }
663 if (p_pkt_mnglr->activate != 0) {
664 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_ACTIVATE "
665 "already set %u",
666 p_pkt_mnglr->activate);
667 error = EINVAL;
668 goto done;
669 }
670 p_pkt_mnglr->activate = *(uint8_t *)data;
671 PKT_MNGLR_LOG(LOG_ERR, "p_pkt_mnglr->activate set to :%d",
672 p_pkt_mnglr->activate);
673 break;
674 default:
675 error = ENOPROTOOPT;
676 break;
677 }
678done:
679 pkt_mnglr_rw_unlock_exclusive(&pkt_mnglr_lck_rw);
680
681 return (error);
682}
683
684void
685pkt_mnglr_init(void)
686{
687 struct kern_ctl_reg kern_ctl;
688 errno_t error = 0;
689 vm_size_t pkt_mnglr_size = 0;
690
691 PKT_MNGLR_LOG(LOG_NOTICE, "");
692
693 /*
694 * Compile time verifications
695 */
696 _CASSERT(PKT_MNGLR_MAX_FILTER_COUNT == MAX_PACKET_MANGLER);
697
698 /*
699 * Zone for packet mangler kernel control sockets
700 */
701 pkt_mnglr_size = sizeof(struct packet_mangler);
702 packet_mangler_zone = zinit(pkt_mnglr_size,
703 PACKET_MANGLER_ZONE_MAX * pkt_mnglr_size,
704 0,
705 PACKET_MANGLER_ZONE_NAME);
706
707 if (packet_mangler_zone == NULL) {
708 panic("%s: zinit(%s) failed", __func__,
709 PACKET_MANGLER_ZONE_NAME);
710 /* NOTREACHED */
711 }
712 zone_change(packet_mangler_zone, Z_CALLERACCT, FALSE);
713 zone_change(packet_mangler_zone, Z_EXPAND, TRUE);
714
715 /*
716 * Allocate locks
717 */
718 pkt_mnglr_lck_grp_attr = lck_grp_attr_alloc_init();
719 if (pkt_mnglr_lck_grp_attr == NULL) {
720 panic("%s: lck_grp_attr_alloc_init failed", __func__);
721 /* NOTREACHED */
722 }
723 pkt_mnglr_lck_grp = lck_grp_alloc_init("packet manglerr",
724 pkt_mnglr_lck_grp_attr);
725 if (pkt_mnglr_lck_grp == NULL) {
726 panic("%s: lck_grp_alloc_init failed", __func__);
727 /* NOTREACHED */
728 }
729 pkt_mnglr_lck_attr = lck_attr_alloc_init();
730 if (pkt_mnglr_lck_attr == NULL) {
731 panic("%s: lck_attr_alloc_init failed", __func__);
732 /* NOTREACHED */
733 }
734 lck_rw_init(&pkt_mnglr_lck_rw, pkt_mnglr_lck_grp, pkt_mnglr_lck_attr);
735
736 /*
737 * Register kernel control
738 */
739 bzero(&kern_ctl, sizeof(kern_ctl));
740 strlcpy(kern_ctl.ctl_name, PACKET_MANGLER_CONTROL_NAME,
741 sizeof(kern_ctl.ctl_name));
742 kern_ctl.ctl_flags = CTL_FLAG_PRIVILEGED | CTL_FLAG_REG_EXTENDED;
743 kern_ctl.ctl_connect = pkt_mnglr_ctl_connect;
744 kern_ctl.ctl_disconnect = pkt_mnglr_ctl_disconnect;
745 kern_ctl.ctl_getopt = pkt_mnglr_ctl_getopt;
746 kern_ctl.ctl_setopt = pkt_mnglr_ctl_setopt;
747 error = ctl_register(&kern_ctl, &pkt_mnglr_kctlref);
748 if (error != 0) {
749 PKT_MNGLR_LOG(LOG_ERR, "ctl_register failed: %d", error);
750 } else {
751 PKT_MNGLR_LOG(LOG_INFO, "Registered packet mangler kernel control.");
752 }
753}
754
755static errno_t pktmnglr_ipfilter_output(void *cookie, mbuf_t *data, ipf_pktopts_t options)
756{
757 struct packet_mangler *p_pkt_mnglr = (struct packet_mangler *)cookie;
758 unsigned char *ptr = (unsigned char *)mbuf_data(*data);
759 struct ip *ip = (struct ip *)(void *)ptr;
760 struct tcphdr *tcp;
761 int optlen = 0;
762
763#pragma unused(tcp, optlen, options)
764
765 if (p_pkt_mnglr == NULL) {
766 return 0;
767 }
768
769 if (!p_pkt_mnglr->activate) {
770 return 0;
771 }
772
773 if (data == NULL) {
774 PKT_MNGLR_LOG(LOG_INFO, "%s:%d Data pointer is NULL\n", __FILE__, __LINE__);
775 return 0;
776 }
777
778 if (p_pkt_mnglr->dir == IN) {
779 return 0;
780 }
781
782 if ((p_pkt_mnglr->lsaddr.ss_family == AF_INET6) && (ip->ip_v == 4)) {
783 return 0;
784 }
785
786 if ((p_pkt_mnglr->lsaddr.ss_family == AF_INET) && (ip->ip_v == 6)) {
787 return 0;
788 }
789
790 if (p_pkt_mnglr->lsaddr.ss_family == AF_INET) {
791 struct sockaddr_in laddr = *(struct sockaddr_in *)(&(p_pkt_mnglr->lsaddr));
792 if (ip->ip_src.s_addr != laddr.sin_addr.s_addr) {
793 return 0;
794 }
795 }
796
797 if (p_pkt_mnglr->rsaddr.ss_family == AF_INET) {
798 struct sockaddr_in raddr = *(struct sockaddr_in *)(&(p_pkt_mnglr->rsaddr));
799 if (ip->ip_dst.s_addr != raddr.sin_addr.s_addr) {
800 return 0;
801 }
802 }
803
804 if (ip->ip_v != 4) {
805 PKT_MNGLR_LOG(LOG_INFO, "%s:%d Not handling IP version %d\n", __FILE__, __LINE__, ip->ip_v);
806 return 0;
807 }
808
809 /* Not handling output flow */
810 return 0;
811}
812
813#define TCP_MAX_OPTLEN 40
814
815static errno_t pktmnglr_ipfilter_input(void *cookie, mbuf_t *data, int offset, u_int8_t protocol)
816{
817 struct packet_mangler *p_pkt_mnglr = (struct packet_mangler *)cookie;
818 struct ip ip;
819 struct tcphdr tcp;
820 char tcp_opt_buf[TCP_MAX_OPTLEN] = {0};
821 int orig_tcp_optlen;
822 int tcp_optlen = 0;
823 errno_t error = 0;
824
825 if (p_pkt_mnglr == NULL) {
826 PKT_MNGLR_LOG(LOG_ERR, "p_pkt_mnglr is NULL");
827 goto input_done;
828 }
829
830 if (p_pkt_mnglr->activate == 0) {
831 PKT_MNGLR_LOG(LOG_INFO, "p_pkt_mnglr not yet activated");
832 goto input_done;
833 }
834
835 if (data == NULL) {
836 PKT_MNGLR_LOG(LOG_ERR, "Data pointer is NULL");
837 goto input_done;
838 }
839
840 if (p_pkt_mnglr->dir == OUT) {
841 goto input_done;
842 }
843
844 /* Check for IP filter options */
845 error = mbuf_copydata(*data, 0, sizeof(ip), &ip);
846 if (error) {
847 PKT_MNGLR_LOG(LOG_ERR, "Could not make local IP header copy");
848 goto input_done;
849 }
850
851 if ((p_pkt_mnglr->lsaddr.ss_family == AF_INET6) && (ip.ip_v == 4)) {
852 PKT_MNGLR_LOG(LOG_INFO, "Skipping filtering as address family of packet is IPv4 but local "
853 "address is set to IPv6");
854 goto input_done;
855 }
856
857 if ((p_pkt_mnglr->lsaddr.ss_family == AF_INET) && (ip.ip_v == 6)) {
858 PKT_MNGLR_LOG(LOG_INFO, "Skipping filtering as address family "
859 "of packet is IPv6 but local address is set to IPv4");
860 goto input_done;
861 }
862
863 if (p_pkt_mnglr->lsaddr.ss_family == AF_INET) {
864 struct sockaddr_in laddr = *(struct sockaddr_in *)(&(p_pkt_mnglr->lsaddr));
865 if (ip.ip_dst.s_addr != laddr.sin_addr.s_addr) {
866 goto input_done;
867 }
868 }
869
870 if (p_pkt_mnglr->rsaddr.ss_family == AF_INET) {
871 struct sockaddr_in raddr = *(struct sockaddr_in *)(&(p_pkt_mnglr->rsaddr));
872 if (ip.ip_src.s_addr != raddr.sin_addr.s_addr) {
873 goto input_done;
874 }
875 PKT_MNGLR_LOG(LOG_INFO, "Remote IP: %x Source IP: %x in input path",
876 raddr.sin_addr.s_addr,
877 ip.ip_src.s_addr);
878 }
879
880 if (ip.ip_v != 4) {
881 goto input_done;
882 }
883
884 if (protocol != p_pkt_mnglr->proto) {
885 PKT_MNGLR_LOG(LOG_INFO, "Skip: Protocol mismatch");
886 goto input_done;
887 }
888
889 switch (protocol) {
890 case IPPROTO_TCP:
891 error = mbuf_copydata(*data, offset, sizeof(tcp), &tcp);
892 if (error) {
893 PKT_MNGLR_LOG(LOG_ERR, "Could not make local TCP header copy");
894 goto input_done;
895 }
896
897 if (p_pkt_mnglr->lport && (p_pkt_mnglr->lport != tcp.th_dport)) {
898 PKT_MNGLR_LOG(LOG_INFO, "Local port and IP des port do not match");
899 goto input_done;
900 }
901
902 if (p_pkt_mnglr->rport && (p_pkt_mnglr->rport != tcp.th_sport)) {
903 PKT_MNGLR_LOG(LOG_INFO, "Remote port and IP src port do not match");
904 goto input_done;
905 }
906 break;
907 case IPPROTO_UDP:
908 goto input_done;
909 break;
910 case IPPROTO_ICMP:
911 goto input_done;
912 break;
913 case IPPROTO_ICMPV6:
914 goto input_done;
915 break;
916 default:
917 goto input_done;
918 break;
919 }
920
921 /* XXX Do IP actions here */
922 PKT_MNGLR_LOG(LOG_INFO, "Proceeding with packet mangler actions on the packet");
923
924 /* Protocol actions */
925 switch (protocol) {
926 case IPPROTO_TCP:
927 if (p_pkt_mnglr->proto_action_mask & PKT_MNGLR_TCP_ACT_NOP_MPTCP) {
928 int i = 0;
929 tcp_optlen = (tcp.th_off << 2)-sizeof(struct tcphdr);
930 PKT_MNGLR_LOG(LOG_INFO, "Packet from F5 is TCP\n");
931 PKT_MNGLR_LOG(LOG_INFO, "Optlen: %d\n", tcp_optlen);
932 orig_tcp_optlen = tcp_optlen;
933 if (orig_tcp_optlen) {
934 error = mbuf_copydata(*data, offset+sizeof(struct tcphdr), orig_tcp_optlen, tcp_opt_buf);
935 if (error) {
936 PKT_MNGLR_LOG(LOG_ERR, "Failed to copy tcp options");
937 goto input_done;
938 }
939 }
940
941 while (tcp_optlen) {
942 if (tcp_opt_buf[i] == 0x1) {
943 PKT_MNGLR_LOG(LOG_INFO, "Skipping NOP\n");
944 tcp_optlen--;
945 i++;
946 continue;
947 } else if ((tcp_opt_buf[i] != 0) && (tcp_opt_buf[i] != 0x1e)) {
948 PKT_MNGLR_LOG(LOG_INFO, "Skipping option %x\n", tcp_opt_buf[i]);
949 tcp_optlen -= tcp_opt_buf[i+1];
950 i += tcp_opt_buf[i+1];
951 continue;
952 } else if (tcp_opt_buf[i] == 0x1e) {
953 int j = 0;
954 int mptcpoptlen = tcp_opt_buf[i+1];
955 PKT_MNGLR_LOG(LOG_INFO, "Got MPTCP option %x\n", tcp_opt_buf[i]);
956 PKT_MNGLR_LOG(LOG_INFO, "Overwriting with NOP\n");
957 for (; j < mptcpoptlen; j++) {
958 tcp_opt_buf[i+j] = 0x1;
959 }
960 tcp_optlen -= mptcpoptlen;
961 i += mptcpoptlen;
962 } else {
963 tcp_optlen--;
964 i++;
965 }
966 }
967 error = mbuf_copyback(*data,
968 offset+sizeof(struct tcphdr),
969 orig_tcp_optlen, tcp_opt_buf, MBUF_WAITOK);
970
971 if (error) {
972 PKT_MNGLR_LOG(LOG_ERR,
973 "Failed to copy tcp options");
974 goto input_done;
975 }
976 }
977 break;
978 case IPPROTO_UDP:
979 /* Don't handle UDP */
980 break;
981 case IPPROTO_ICMP:
982 break;
983 case IPPROTO_ICMPV6:
984 break;
985 default:
986 break;
987 }
988 chksm_update(*data);
989input_done:
990 return 0;
991}
992
993static void pktmnglr_ipfilter_detach(void *cookie)
994{
995#pragma unused(cookie)
996 return;
997}
998
999/* XXX Still need to modify this to use mbuf_copy* macros */
1000static void chksm_update(mbuf_t data)
1001{
1002 u_int16_t ip_sum;
1003 u_int16_t tsum;
1004 struct tcphdr *tcp;
1005
1006 unsigned char *ptr = (unsigned char *)mbuf_data(data);
1007 struct ip *ip = (struct ip *)(void *)ptr;
1008 if (ip->ip_v != 4) {
1009 return;
1010 }
1011
1012 ip->ip_sum = 0;
1013 mbuf_inet_cksum(data, 0, 0, ip->ip_hl << 2, &ip_sum); // ip sum
1014
1015 ip->ip_sum = ip_sum;
1016 switch (ip->ip_p) {
1017 case IPPROTO_TCP:
1018 tcp = (struct tcphdr *)(void *)(ptr + (ip->ip_hl << 2));
1019 tcp->th_sum = 0;
1020 mbuf_inet_cksum(data, IPPROTO_TCP, ip->ip_hl << 2,
1021 ntohs(ip->ip_len) - (ip->ip_hl << 2), &tsum);
1022 tcp->th_sum = tsum;
1023 break;
1024 case IPPROTO_UDP:
1025 /* Don't handle UDP */
1026 break;
1027 case IPPROTO_ICMP:
1028 break;
1029 case IPPROTO_ICMPV6:
1030 break;
1031 default:
1032 break;
1033 }
1034
1035 mbuf_clear_csum_performed(data);
1036 return;
1037}