]> git.saurik.com Git - apple/mdnsresponder.git/blame - mDNSMacOSX/P2PPacketFilter.c
mDNSResponder-878.270.2.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / P2PPacketFilter.c
CommitLineData
9f221bca 1/* -*- Mode: C; tab-width: 4 -*-
294beb6e
A
2 *
3 * Copyright (c) 2011 Apple Inc. All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#include <net/if.h>
19#include <System/net/pfvar.h>
20#include <string.h>
21#include <fcntl.h>
22#include <errno.h>
23#include <sys/ioctl.h>
24#include <unistd.h>
25#include <AssertMacros.h>
26#include "P2PPacketFilter.h"
27
83fb1e36
A
28#define AIRDROP_ANCHOR_PATH "com.apple/200.AirDrop"
29#define MDNS_ANCHOR_NAME "Bonjour"
30#define MDNS_ANCHOR_PATH AIRDROP_ANCHOR_PATH "/" MDNS_ANCHOR_NAME
294beb6e
A
31
32#define PF_DEV_PATH "/dev/pf"
33#define BONJOUR_PORT 5353
34
35static int openPFDevice( int * outFD )
36{
37 int err;
38 int fd = open( PF_DEV_PATH, O_RDWR );
83fb1e36 39
294beb6e
A
40 if( fd >= 0 )
41 {
42 err = 0;
43 *outFD = fd;
44 }
45 else
46 {
47 err = errno;
48 }
83fb1e36 49
294beb6e
A
50 return err;
51}
52
53static int getTicket( int devFD, u_int32_t * outTicket, char * anchorPath )
54{
55 struct pfioc_trans_e trans_e;
83fb1e36 56
294beb6e
A
57 trans_e.rs_num = PF_RULESET_FILTER;
58 strlcpy( trans_e.anchor, anchorPath, sizeof( trans_e.anchor ) );
83fb1e36 59
294beb6e 60 struct pfioc_trans trans;
83fb1e36 61
294beb6e
A
62 trans.size = 1;
63 trans.esize = sizeof( trans_e );
64 trans.array = &trans_e;
83fb1e36 65
294beb6e 66 int result, ioctlError;
83fb1e36 67
294beb6e
A
68 ioctlError = ioctl( devFD, DIOCXBEGIN, &trans );
69 if( ioctlError )
70 {
71 result = errno;
72 }
73 else
74 {
75 result = 0;
76 *outTicket = trans_e.ticket;
77 }
83fb1e36 78
294beb6e
A
79 return result;
80}
81
82static int commitChange( int devFD, u_int32_t ticket, char * anchorPath )
83{
84 struct pfioc_trans_e trans_e;
83fb1e36 85
294beb6e
A
86 trans_e.rs_num = PF_RULESET_FILTER;
87 strlcpy( trans_e.anchor, anchorPath, sizeof( trans_e.anchor ) );
88 trans_e.ticket = ticket;
83fb1e36 89
294beb6e 90 struct pfioc_trans trans;
83fb1e36 91
294beb6e
A
92 trans.size = 1;
93 trans.esize = sizeof( trans_e );
94 trans.array = &trans_e;
83fb1e36 95
294beb6e 96 int result, ioctlError;
83fb1e36 97
294beb6e
A
98 ioctlError = ioctl( devFD, DIOCXCOMMIT, &trans );
99 if( ioctlError )
100 result = errno;
101 else
102 result = 0;
83fb1e36 103
294beb6e
A
104 return result;
105}
106
107static int getPoolTicket( int devFD, u_int32_t * outPoolTicket )
108{
109 struct pfioc_pooladdr pp;
83fb1e36 110
294beb6e 111 int result, ioctlError;
83fb1e36 112
294beb6e
A
113 ioctlError = ioctl( devFD, DIOCBEGINADDRS, &pp );
114 if( ioctlError )
115 {
116 result = errno;
117 }
118 else
119 {
120 result = 0;
121 *outPoolTicket = pp.ticket;
122 }
83fb1e36 123
294beb6e
A
124 return result;
125}
126
127static int addRule( int devFD, struct pfioc_rule * pr )
128{
129 int result, ioctlResult;
83fb1e36 130
294beb6e
A
131 ioctlResult = ioctl( devFD, DIOCADDRULE, pr );
132 if( ioctlResult )
133 result = errno;
134 else
135 result = 0;
83fb1e36 136
294beb6e
A
137 return result;
138}
139
140static void initRuleHeader( struct pfioc_rule * pr,
83fb1e36
A
141 u_int32_t ticket,
142 u_int32_t poolTicket,
143 char * anchorPath )
294beb6e
A
144{
145 pr->action = PF_CHANGE_NONE;
146 pr->ticket = ticket;
147 pr->pool_ticket = poolTicket;
148 strlcpy( pr->anchor, anchorPath, sizeof( pr->anchor ) );
149}
150
83fb1e36 151// allow inbound traffice on the Bonjour port (5353)
294beb6e 152static void initBonjourRule( struct pfioc_rule * pr,
83fb1e36
A
153 const char * interfaceName,
154 u_int32_t ticket,
155 u_int32_t poolTicket,
156 char * anchorPath )
294beb6e
A
157{
158 memset( pr, 0, sizeof( *pr ) );
83fb1e36 159
294beb6e
A
160 // Header
161 initRuleHeader( pr, ticket, poolTicket, anchorPath );
83fb1e36 162
294beb6e
A
163 // Rule
164 pr->rule.dst.xport.range.port[0] = htons( BONJOUR_PORT );
165 pr->rule.dst.xport.range.op = PF_OP_EQ;
83fb1e36 166
294beb6e 167 strlcpy( pr->rule.ifname, interfaceName, sizeof( pr->rule.ifname ) );
83fb1e36 168
294beb6e
A
169 pr->rule.action = PF_PASS;
170 pr->rule.direction = PF_IN;
171 pr->rule.keep_state = 1;
172 pr->rule.af = AF_INET6;
173 pr->rule.proto = IPPROTO_UDP;
174 pr->rule.extfilter = PF_EXTFILTER_APD;
175}
176
177// allow outbound TCP connections and return traffic for those connections
178static void initOutboundTCPRule( struct pfioc_rule * pr,
83fb1e36
A
179 const char * interfaceName,
180 u_int32_t ticket,
181 u_int32_t poolTicket,
182 char * anchorPath )
294beb6e
A
183{
184 memset( pr, 0, sizeof( *pr ) );
83fb1e36 185
294beb6e
A
186 // Header
187 initRuleHeader( pr, ticket, poolTicket, anchorPath );
83fb1e36 188
294beb6e
A
189 // Rule
190 strlcpy( pr->rule.ifname, interfaceName, sizeof( pr->rule.ifname ) );
83fb1e36 191
294beb6e
A
192 pr->rule.action = PF_PASS;
193 pr->rule.direction = PF_OUT;
194 pr->rule.keep_state = 1;
195 pr->rule.proto = IPPROTO_TCP;
196}
197
198// allow inbound traffic on the specified port and protocol
199static void initPortRule( struct pfioc_rule * pr,
83fb1e36
A
200 const char * interfaceName,
201 u_int32_t ticket,
202 u_int32_t poolTicket,
203 char * anchorPath,
204 u_int16_t port,
205 u_int16_t protocol )
294beb6e
A
206{
207 memset( pr, 0, sizeof( *pr ) );
83fb1e36 208
294beb6e
A
209 // Header
210 initRuleHeader( pr, ticket, poolTicket, anchorPath );
83fb1e36 211
294beb6e 212 // Rule
83fb1e36 213 // mDNSResponder passes the port in Network Byte Order, so htons(port) is not required
294beb6e
A
214 pr->rule.dst.xport.range.port[0] = port;
215 pr->rule.dst.xport.range.op = PF_OP_EQ;
83fb1e36 216
294beb6e 217 strlcpy( pr->rule.ifname, interfaceName, sizeof( pr->rule.ifname ) );
83fb1e36 218
294beb6e
A
219 pr->rule.action = PF_PASS;
220 pr->rule.direction = PF_IN;
221 pr->rule.keep_state = 1;
222 pr->rule.af = AF_INET6;
223 pr->rule.proto = protocol;
224 pr->rule.extfilter = PF_EXTFILTER_APD;
225}
226
83fb1e36
A
227// allow inbound traffic on the Bonjour port (5353) and the specified port and protocol sets
228int P2PPacketFilterAddBonjourRuleSet(const char * interfaceName, u_int32_t count, pfArray_t portArray, pfArray_t protocolArray )
294beb6e
A
229{
230 int result;
9f221bca
A
231 u_int32_t i;
232 u_int32_t ticket = 0;
233 u_int32_t poolTicket = 0;
294beb6e 234 int devFD = -1;
83fb1e36
A
235 char * anchorPath = MDNS_ANCHOR_PATH;
236
294beb6e
A
237 result = openPFDevice( &devFD );
238 require( result == 0, exit );
83fb1e36 239
294beb6e
A
240 result = getTicket( devFD, &ticket, anchorPath );
241 require( result == 0, exit );
83fb1e36 242
294beb6e
A
243 result = getPoolTicket( devFD, &poolTicket );
244 require( result == 0, exit );
83fb1e36 245
294beb6e 246 struct pfioc_rule pr;
83fb1e36
A
247
248 // allow inbound Bonjour traffice to port 5353
294beb6e 249 initBonjourRule( &pr, interfaceName, ticket, poolTicket, anchorPath);
83fb1e36 250
294beb6e
A
251 result = addRule( devFD, &pr );
252 require( result == 0, exit );
83fb1e36
A
253
254 // open inbound port for each service
9f221bca
A
255 for (i = 0; i < count; i++)
256 {
83fb1e36
A
257 initPortRule( &pr, interfaceName, ticket, poolTicket, anchorPath, portArray[i], protocolArray[i] );
258 result = addRule( devFD, &pr );
259 require( result == 0, exit );
260 }
261
294beb6e
A
262 // allow outbound TCP connections and return traffic for those connections
263 initOutboundTCPRule( &pr, interfaceName, ticket, poolTicket, anchorPath);
83fb1e36 264
294beb6e
A
265 result = addRule( devFD, &pr );
266 require( result == 0, exit );
83fb1e36 267
294beb6e
A
268 result = commitChange( devFD, ticket, anchorPath );
269 require( result == 0, exit );
83fb1e36 270
294beb6e 271exit:
83fb1e36 272
294beb6e
A
273 if( devFD >= 0 )
274 close( devFD );
83fb1e36 275
294beb6e
A
276 return result;
277}
278
279int P2PPacketFilterClearBonjourRules()
280{
83fb1e36
A
281 int result;
282 int pfDev = -1;
9f221bca 283 u_int32_t ticket = 0;
83fb1e36
A
284 char * anchorPath = MDNS_ANCHOR_PATH;
285
286 result = openPFDevice( &pfDev );
287 require( result == 0, exit );
288
289 result = getTicket( pfDev, &ticket, anchorPath );
290 require( result == 0, exit );
291
292 result = commitChange( pfDev, ticket, anchorPath );
293
294beb6e 294exit:
294beb6e 295
83fb1e36
A
296 if( pfDev >= 0 )
297 close( pfDev );
298
299 return result;
294beb6e
A
300}
301