2 * Copyright (c) 2014 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
30 // Created by Prabhakar Lakhera on 06/23/14.
34 #include <sys/types.h>
35 #include <sys/socket.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>
50 #include <net/packet_mangler.h>
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};
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;
72 basename(const char * str
)
74 const char *last_slash
= strrchr(str
, '/');
76 if (last_slash
== NULL
)
79 return (last_slash
+ 1);
84 const char *description
;
88 struct option_desc option_desc_list
[] = {
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 */
104 usage(const char *cmd
)
106 struct option_desc
*option_desc
;
107 char * usage_str
= (char *)malloc(BUF_MAX
);
110 if (usage_str
== NULL
)
111 err(1, "%s: malloc(%d)", __func__
, BUF_MAX
);
113 usage_len
= snprintf(usage_str
, BUF_MAX
, "# usage: %s ", basename(cmd
));
115 for (option_desc
= option_desc_list
; option_desc
->option
!= NULL
; option_desc
++) {
118 if (option_desc
->required
)
119 len
= snprintf(usage_str
+ usage_len
, BUF_MAX
- usage_len
, "%s ", option_desc
->option
);
121 len
= snprintf(usage_str
+ usage_len
, BUF_MAX
- usage_len
, "[%s] ", option_desc
->option
);
123 err(1, "%s: snprintf(", __func__
);
126 if (usage_len
> BUF_MAX
)
129 printf("%s\n", usage_str
);
130 printf("options:\n");
132 for (option_desc
= option_desc_list
; option_desc
->option
!= NULL
; option_desc
++) {
133 printf(" %-20s # %s\n", option_desc
->option
, option_desc
->description
);
139 main(int argc
, char * const argv
[]) {
148 while ((ch
= getopt(argc
, argv
, "hf:l:r:t:p:m:M:L:R:")) != -1) {
155 if (strcasecmp(optarg
, "in") == 0) {
157 } else if (strcasecmp(optarg
, "out") == 0) {
159 } else if (strcasecmp(optarg
, "inout") == 0) {
163 errx(1, "syntax error");
168 if ((error
= getaddrinfo(optarg
, NULL
, NULL
, &p_localaddr
)))
169 errx(1, "getaddrinfo returned error: %s", gai_strerror(error
));
173 if ((error
= getaddrinfo(optarg
, NULL
, NULL
, &p_remoteaddr
)))
174 errx(1, "getaddrinfo returned error: %s", gai_strerror(error
));
178 ip_act_mask
= (uint32_t)atoi(optarg
);
181 duration
= (uint32_t)atoi(optarg
);
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.");
197 errx(1, "Protocol not supported.");
202 local_port
= htons((uint16_t)atoi(optarg
));
205 remote_port
= htons((uint16_t)atoi(optarg
));
208 proto_act_mask
= (uint32_t)atoi(optarg
);
212 warnx("# syntax error, unknow option '%d'", ch
);
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");
235 struct sockaddr_ctl addr
;
237 sf
= socket(PF_SYSTEM
, SOCK_DGRAM
, SYSPROTO_CONTROL
);
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
;
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");
256 addr
.sc_id
= info
.ctl_id
;
260 if (connect(sf
, (struct sockaddr
*)&addr
, sizeof(struct sockaddr_ctl
)) == -1) {
264 if (setsockopt(sf
, SYSPROTO_CONTROL
, PKT_MNGLR_OPT_DIRECTION
,
265 &dir
, sizeof(uint32_t)) == -1) {
266 err(1, "setsockopt could not set direction.");
269 /* Set the IP addresses for the flow */
271 l_saddr
= *((struct sockaddr_storage
*)(p_localaddr
->ai_addr
));
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.");
277 freeaddrinfo(p_localaddr
);
282 r_saddr
= *((struct sockaddr_storage
*)(p_remoteaddr
->ai_addr
));
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.");
288 freeaddrinfo(p_remoteaddr
);
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.");
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.");
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.");
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.");
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.");