]>
Commit | Line | Data |
---|---|---|
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 | ||
61 | SYSCTL_NODE(_net, OID_AUTO, pktmnglr, CTLFLAG_RW|CTLFLAG_LOCKED, 0, "pktmnglr"); | |
62 | SYSCTL_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 | */ | |
68 | struct 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 */ | |
92 | struct packet_mangler **packet_manglers = NULL; | |
93 | ||
94 | uint32_t pkt_mnglr_active_count = 0; /* Number of active packet filters */ | |
95 | uint32_t pkt_mnglr_close_wait_timeout = 1000; /* in milliseconds */ | |
96 | ||
97 | static kern_ctl_ref pkt_mnglr_kctlref = NULL; | |
98 | ||
99 | static lck_grp_attr_t *pkt_mnglr_lck_grp_attr = NULL; | |
100 | static lck_attr_t *pkt_mnglr_lck_attr = NULL; | |
101 | static lck_grp_t *pkt_mnglr_lck_grp = NULL; | |
102 | ||
103 | /* The lock below protects packet_manglers DS, packet_mangler DS */ | |
104 | decl_lck_rw_data(static, pkt_mnglr_lck_rw); | |
105 | ||
106 | #define PKT_MNGLR_RW_LCK_MAX 8 | |
107 | ||
108 | int pkt_mnglr_rw_nxt_lck = 0; | |
109 | void* pkt_mnglr_rw_lock_history[PKT_MNGLR_RW_LCK_MAX]; | |
110 | ||
111 | int pkt_mnglr_rw_nxt_unlck = 0; | |
112 | void* 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 | |
117 | static struct zone *packet_mangler_zone = NULL; /* zone for packet_mangler */ | |
118 | ||
119 | /* | |
120 | * For troubleshooting | |
121 | */ | |
122 | int pkt_mnglr_log_level = LOG_ERR; | |
123 | int pkt_mnglr_debug = 1; | |
124 | ||
125 | /* | |
126 | * Forward declaration to appease the compiler | |
127 | */ | |
128 | static void pkt_mnglr_rw_lock_exclusive(lck_rw_t *); | |
129 | static void pkt_mnglr_rw_unlock_exclusive(lck_rw_t *); | |
130 | static void pkt_mnglr_rw_lock_shared(lck_rw_t *); | |
131 | static void pkt_mnglr_rw_unlock_shared(lck_rw_t *); | |
132 | ||
133 | static errno_t pktmnglr_ipfilter_output(void *cookie, mbuf_t *data, | |
134 | ipf_pktopts_t options); | |
135 | static errno_t pktmnglr_ipfilter_input(void *cookie, mbuf_t *data, | |
136 | int offset, u_int8_t protocol); | |
137 | static void pktmnglr_ipfilter_detach(void *cookie); | |
138 | ||
139 | static void chksm_update(mbuf_t data); | |
140 | ||
141 | /* | |
142 | * packet filter global read write lock | |
143 | */ | |
144 | ||
145 | static void | |
146 | pkt_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 | ||
159 | static void | |
160 | pkt_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 | ||
173 | static void | |
174 | pkt_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 | ||
186 | static void | |
187 | pkt_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 | */ | |
202 | static errno_t | |
203 | pkt_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 | ||
286 | done: | |
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 | ||
296 | static errno_t | |
297 | pkt_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); | |
342 | done: | |
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 | ||
349 | static errno_t | |
350 | pkt_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 | } | |
489 | done: | |
490 | pkt_mnglr_rw_unlock_shared(&pkt_mnglr_lck_rw); | |
491 | ||
492 | return (error); | |
493 | } | |
494 | ||
495 | static errno_t | |
496 | pkt_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 | } | |
678 | done: | |
679 | pkt_mnglr_rw_unlock_exclusive(&pkt_mnglr_lck_rw); | |
680 | ||
681 | return (error); | |
682 | } | |
683 | ||
684 | void | |
685 | pkt_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 | ||
755 | static 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 | ||
815 | static 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); | |
989 | input_done: | |
990 | return 0; | |
991 | } | |
992 | ||
993 | static 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 */ | |
1000 | static 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 | } |