]> git.saurik.com Git - apple/network_cmds.git/blob - pktmnglr/packet_mangler.c
fab5ce90d81dcd4e98458abf1ddb00a0146b9f60
[apple/network_cmds.git] / pktmnglr / packet_mangler.c
1 /*
2 * Copyright (c) 2014 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_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. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 //
30 // Created by Prabhakar Lakhera on 06/23/14.
31 //
32
33 #include <stdio.h>
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <netdb.h>
37 #include <sys/errno.h>
38 #include <sys/sys_domain.h>
39 #include <sys/ioctl.h>
40 #include <sys/kern_control.h>
41 #include <sys/queue.h>
42 #include <netinet/in.h>
43 #include <stdio.h>
44 #include <err.h>
45 #include <string.h>
46 #include <stdlib.h>
47 #include <unistd.h>
48 #include <ctype.h>
49 #include <sysexits.h>
50 #include <net/packet_mangler.h>
51
52
53 #define BUF_MAX 1000
54 int doit();
55
56 Pkt_Mnglr_Flow dir = INOUT;
57 struct addrinfo * p_localaddr = NULL;
58 struct addrinfo * p_remoteaddr = NULL;
59 struct sockaddr_storage l_saddr = {0};
60 struct sockaddr_storage r_saddr = {0};
61
62 int sf = -1;
63 uint32_t duration = 0;
64 uint32_t protocol = 0;
65 uint32_t proto_act_mask = 0;
66 uint32_t ip_act_mask = 0;
67 uint16_t local_port = 0;
68 uint16_t remote_port = 0;
69 uint8_t activate = 1;
70
71 static const char *
72 basename(const char * str)
73 {
74 const char *last_slash = strrchr(str, '/');
75
76 if (last_slash == NULL)
77 return (str);
78 else
79 return (last_slash + 1);
80 }
81
82 struct option_desc {
83 const char *option;
84 const char *description;
85 int required;
86 };
87
88 struct option_desc option_desc_list[] = {
89 { "-h ", "Help", 0 },
90 { "-f flow", "flow direction to apply mangler on. Values can be: in/out/inout. default is inout", 0 },
91 { "-l IP address ", "Local IP we are interested in ", 0 },
92 { "-r IP address ", "Remote IP we are interested in", 0 },
93 { "-m IP action mask ", "IP action mask", 0 },
94 { "-t time", "Run duration for which packet mangler will run. A value of 0 means forever (till program is killed).", 0 },
95 { "-p IP Protocol ", "IP protocol i.e. one of tcp, udp, icmp, icmpv6", 0 },
96 { "-L Local port ", "Local port", 0 },
97 { "-R Remote port ", "Remote port", 0 },
98 { "-M Protocol action mask ", "Protocol action mask", 0 },
99 { NULL, NULL, 0 } /* Mark end of list */
100 };
101
102
103 static void
104 usage(const char *cmd)
105 {
106 struct option_desc *option_desc;
107 char * usage_str = (char *)malloc(BUF_MAX);
108 size_t usage_len;
109
110 if (usage_str == NULL)
111 err(1, "%s: malloc(%d)", __func__, BUF_MAX);
112
113 usage_len = snprintf(usage_str, BUF_MAX, "# usage: %s ", basename(cmd));
114
115 for (option_desc = option_desc_list; option_desc->option != NULL; option_desc++) {
116 int len;
117
118 if (option_desc->required)
119 len = snprintf(usage_str + usage_len, BUF_MAX - usage_len, "%s ", option_desc->option);
120 else
121 len = snprintf(usage_str + usage_len, BUF_MAX - usage_len, "[%s] ", option_desc->option);
122 if (len < 0)
123 err(1, "%s: snprintf(", __func__);
124
125 usage_len += len;
126 if (usage_len > BUF_MAX)
127 break;
128 }
129 printf("%s\n", usage_str);
130 printf("options:\n");
131
132 for (option_desc = option_desc_list; option_desc->option != NULL; option_desc++) {
133 printf(" %-20s # %s\n", option_desc->option, option_desc->description);
134 }
135
136 }
137
138 int
139 main(int argc, char * const argv[]) {
140 int ch;
141 int error;
142
143 if (argc == 1) {
144 usage(argv[0]);
145 exit(0);
146 }
147
148 while ((ch = getopt(argc, argv, "hf:l:r:t:p:m:M:L:R")) != -1) {
149 switch (ch) {
150 case 'h':
151 usage(argv[0]);
152 exit(0);
153 break;
154 case 'f': {
155 if (strcasecmp(optarg, "in") == 0) {
156 dir = IN;
157 } else if (strcasecmp(optarg, "out") == 0) {
158 dir = OUT;
159 } else if (strcasecmp(optarg, "inout") == 0) {
160 dir = INOUT;
161 } else {
162 usage(argv[0]);
163 errx(1, "syntax error");
164 }
165 }
166 break;
167 case 'l':
168 if ((error = getaddrinfo(optarg, NULL, NULL, &p_localaddr)))
169 errx(1, "getaddrinfo returned error: %s", gai_strerror(error));
170
171 break;
172 case 'r':
173 if ((error = getaddrinfo(optarg, NULL, NULL, &p_remoteaddr)))
174 errx(1, "getaddrinfo returned error: %s", gai_strerror(error));
175
176 break;
177 case 'm':
178 ip_act_mask = (uint32_t)atoi(optarg);
179 break;
180 case 't':
181 duration = (uint32_t)atoi(optarg);
182 break;
183 case 'p':
184 /* Only support tcp for now */
185 if (strcasecmp(optarg, "tcp") == 0) {
186 protocol = IPPROTO_TCP;
187 } else if (strcasecmp(optarg, "udp") == 0) {
188 protocol = IPPROTO_UDP;
189 errx(1, "Protocol not supported.");
190 } else if (strcasecmp(optarg, "icmp") == 0) {
191 protocol = IPPROTO_ICMP;
192 errx(1, "Protocol not supported.");
193 } else if (strcasecmp(optarg, "icmpv6") == 0) {
194 protocol = IPPROTO_ICMPV6;
195 errx(1, "Protocol not supported.");
196 } else {
197 errx(1, "Protocol not supported.");
198 }
199 break;
200
201 case 'L':
202 local_port = (uint16_t)atoi(optarg);
203 break;
204 case 'R':
205 remote_port = (uint16_t)atoi(optarg);
206 break;
207 case 'M':
208 proto_act_mask = (uint32_t)atoi(optarg);
209 break;
210
211 default:
212 warnx("# syntax error, unknow option '%d'", ch);
213 usage(argv[0]);
214 exit(0);
215 }
216 }
217
218 if (p_localaddr && p_remoteaddr) {
219 if (p_localaddr->ai_family!=p_remoteaddr->ai_family) {
220 errx(1, "The address families for local and remote address"
221 " when both present, must be equal");
222 }
223 }
224
225
226 doit();
227
228 return (0);
229 }
230
231
232 int
233 doit()
234 {
235 struct sockaddr_ctl addr;
236
237 sf = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
238 if (sf == -1) {
239 err(1, "socket()");
240 }
241
242 /* Connect the socket */
243 bzero(&addr, sizeof(addr));
244 addr.sc_len = sizeof(addr);
245 addr.sc_family = AF_SYSTEM;
246 addr.ss_sysaddr = AF_SYS_CONTROL;
247
248 {
249 struct ctl_info info;
250 memset(&info, 0, sizeof(info));
251 strncpy(info.ctl_name, PACKET_MANGLER_CONTROL_NAME, sizeof(info.ctl_name));
252 if (ioctl(sf, CTLIOCGINFO, &info)) {
253 perror("Could not get ID for kernel control.\n");
254 exit(-1);
255 }
256 addr.sc_id = info.ctl_id;
257 addr.sc_unit = 1;
258 }
259
260 if (connect(sf, (struct sockaddr *)&addr, sizeof(struct sockaddr_ctl)) == -1) {
261 err(1, "connect()");
262 }
263
264 if (setsockopt(sf, SYSPROTO_CONTROL, PKT_MNGLR_OPT_DIRECTION,
265 &dir, sizeof(uint32_t)) == -1) {
266 err(1, "setsockopt could not set direction.");
267 }
268
269 /* Set the IP addresses for the flow */
270 if (p_localaddr) {
271 l_saddr = *((struct sockaddr_storage *)(p_localaddr->ai_addr));
272
273 if (setsockopt(sf, SYSPROTO_CONTROL, PKT_MNGLR_OPT_LOCAL_IP,
274 &l_saddr, sizeof(struct sockaddr_storage)) == -1) {
275 err(1, "setsockopt could not set local address.");
276 }
277 freeaddrinfo(p_localaddr);
278 p_localaddr = NULL;
279 }
280
281 if (p_remoteaddr) {
282 r_saddr = *((struct sockaddr_storage *)(p_remoteaddr->ai_addr));
283
284 if (setsockopt(sf, SYSPROTO_CONTROL, PKT_MNGLR_OPT_REMOTE_IP,
285 &r_saddr, sizeof(struct sockaddr_storage)) == -1) {
286 err(1, "setsockopt could not set remote address.");
287 }
288 freeaddrinfo(p_remoteaddr);
289 p_remoteaddr = NULL;
290 }
291
292 /* Set ports for the flow */
293 if (local_port && (setsockopt(sf, SYSPROTO_CONTROL, PKT_MNGLR_OPT_LOCAL_PORT,
294 &local_port, sizeof(uint16_t)) == -1)) {
295 err(1, "setsockopt could not set local port.");
296
297 }
298
299 if (remote_port && (setsockopt(sf, SYSPROTO_CONTROL, PKT_MNGLR_OPT_REMOTE_PORT,
300 &remote_port, sizeof(uint16_t)) == -1)) {
301 err(1, "setsockopt could not set remote port.");
302
303 }
304
305 if (protocol && setsockopt(sf, SYSPROTO_CONTROL, PKT_MNGLR_OPT_PROTOCOL,
306 &protocol, sizeof(uint32_t)) == -1) {
307 err(1, "setsockopt could not set protocol.");
308 }
309
310 if (proto_act_mask &&
311 (setsockopt(sf, SYSPROTO_CONTROL, PKT_MNGLR_OPT_PROTO_ACT_MASK,
312 &proto_act_mask, sizeof(uint32_t))==-1)) {
313 err(1, "setsockopt could not set protocol action mask.");
314 }
315
316 if (setsockopt(sf, SYSPROTO_CONTROL, PKT_MNGLR_OPT_ACTIVATE,
317 &activate, sizeof(uint8_t))== -1) {
318 err(1, "setsockopt could not activate packet mangler.");
319 }
320
321 if (!duration) {
322 pause();
323 } else {
324 sleep(duration);
325 }
326
327 close(sf);
328 return 0;
329 }