]>
git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/P2PPacketFilter.c
1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2011 Apple Inc. All rights reserved.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <System/net/pfvar.h>
23 #include <sys/ioctl.h>
25 #include <AssertMacros.h>
26 #include "P2PPacketFilter.h"
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
32 #define PF_DEV_PATH "/dev/pf"
33 #define BONJOUR_PORT 5353
35 static int openPFDevice( int * outFD
)
38 int fd
= open( PF_DEV_PATH
, O_RDWR
);
53 static int getTicket( int devFD
, u_int32_t
* outTicket
, char * anchorPath
)
55 struct pfioc_trans_e trans_e
;
57 trans_e
.rs_num
= PF_RULESET_FILTER
;
58 strlcpy( trans_e
.anchor
, anchorPath
, sizeof( trans_e
.anchor
) );
60 struct pfioc_trans trans
;
63 trans
.esize
= sizeof( trans_e
);
64 trans
.array
= &trans_e
;
66 int result
, ioctlError
;
68 ioctlError
= ioctl( devFD
, DIOCXBEGIN
, &trans
);
76 *outTicket
= trans_e
.ticket
;
82 static int commitChange( int devFD
, u_int32_t ticket
, char * anchorPath
)
84 struct pfioc_trans_e trans_e
;
86 trans_e
.rs_num
= PF_RULESET_FILTER
;
87 strlcpy( trans_e
.anchor
, anchorPath
, sizeof( trans_e
.anchor
) );
88 trans_e
.ticket
= ticket
;
90 struct pfioc_trans trans
;
93 trans
.esize
= sizeof( trans_e
);
94 trans
.array
= &trans_e
;
96 int result
, ioctlError
;
98 ioctlError
= ioctl( devFD
, DIOCXCOMMIT
, &trans
);
107 static int getPoolTicket( int devFD
, u_int32_t
* outPoolTicket
)
109 struct pfioc_pooladdr pp
;
111 int result
, ioctlError
;
113 ioctlError
= ioctl( devFD
, DIOCBEGINADDRS
, &pp
);
121 *outPoolTicket
= pp
.ticket
;
127 static int addRule( int devFD
, struct pfioc_rule
* pr
)
129 int result
, ioctlResult
;
131 ioctlResult
= ioctl( devFD
, DIOCADDRULE
, pr
);
140 static void initRuleHeader( struct pfioc_rule
* pr
,
142 u_int32_t poolTicket
,
145 pr
->action
= PF_CHANGE_NONE
;
147 pr
->pool_ticket
= poolTicket
;
148 strlcpy( pr
->anchor
, anchorPath
, sizeof( pr
->anchor
) );
151 // allow inbound traffice on the Bonjour port (5353)
152 static void initBonjourRule( struct pfioc_rule
* pr
,
153 const char * interfaceName
,
155 u_int32_t poolTicket
,
158 memset( pr
, 0, sizeof( *pr
) );
161 initRuleHeader( pr
, ticket
, poolTicket
, anchorPath
);
164 pr
->rule
.dst
.xport
.range
.port
[0] = htons( BONJOUR_PORT
);
165 pr
->rule
.dst
.xport
.range
.op
= PF_OP_EQ
;
167 strlcpy( pr
->rule
.ifname
, interfaceName
, sizeof( pr
->rule
.ifname
) );
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
;
177 // allow outbound TCP connections and return traffic for those connections
178 static void initOutboundTCPRule( struct pfioc_rule
* pr
,
179 const char * interfaceName
,
181 u_int32_t poolTicket
,
184 memset( pr
, 0, sizeof( *pr
) );
187 initRuleHeader( pr
, ticket
, poolTicket
, anchorPath
);
190 strlcpy( pr
->rule
.ifname
, interfaceName
, sizeof( pr
->rule
.ifname
) );
192 pr
->rule
.action
= PF_PASS
;
193 pr
->rule
.direction
= PF_OUT
;
194 pr
->rule
.keep_state
= 1;
195 pr
->rule
.proto
= IPPROTO_TCP
;
198 // allow inbound traffic on the specified port and protocol
199 static void initPortRule( struct pfioc_rule
* pr
,
200 const char * interfaceName
,
202 u_int32_t poolTicket
,
207 memset( pr
, 0, sizeof( *pr
) );
210 initRuleHeader( pr
, ticket
, poolTicket
, anchorPath
);
213 // mDNSResponder passes the port in Network Byte Order, so htons(port) is not required
214 pr
->rule
.dst
.xport
.range
.port
[0] = port
;
215 pr
->rule
.dst
.xport
.range
.op
= PF_OP_EQ
;
217 strlcpy( pr
->rule
.ifname
, interfaceName
, sizeof( pr
->rule
.ifname
) );
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
;
227 // allow inbound traffic on the Bonjour port (5353) and the specified port and protocol sets
228 int P2PPacketFilterAddBonjourRuleSet(const char * interfaceName
, u_int32_t count
, pfArray_t portArray
, pfArray_t protocolArray
)
232 u_int32_t ticket
= 0;
233 u_int32_t poolTicket
= 0;
235 char * anchorPath
= MDNS_ANCHOR_PATH
;
237 result
= openPFDevice( &devFD
);
238 require( result
== 0, exit
);
240 result
= getTicket( devFD
, &ticket
, anchorPath
);
241 require( result
== 0, exit
);
243 result
= getPoolTicket( devFD
, &poolTicket
);
244 require( result
== 0, exit
);
246 struct pfioc_rule pr
;
248 // allow inbound Bonjour traffice to port 5353
249 initBonjourRule( &pr
, interfaceName
, ticket
, poolTicket
, anchorPath
);
251 result
= addRule( devFD
, &pr
);
252 require( result
== 0, exit
);
254 // open inbound port for each service
255 for (i
= 0; i
< count
; i
++)
257 initPortRule( &pr
, interfaceName
, ticket
, poolTicket
, anchorPath
, portArray
[i
], protocolArray
[i
] );
258 result
= addRule( devFD
, &pr
);
259 require( result
== 0, exit
);
262 // allow outbound TCP connections and return traffic for those connections
263 initOutboundTCPRule( &pr
, interfaceName
, ticket
, poolTicket
, anchorPath
);
265 result
= addRule( devFD
, &pr
);
266 require( result
== 0, exit
);
268 result
= commitChange( devFD
, ticket
, anchorPath
);
269 require( result
== 0, exit
);
279 int P2PPacketFilterClearBonjourRules()
283 u_int32_t ticket
= 0;
284 char * anchorPath
= MDNS_ANCHOR_PATH
;
286 result
= openPFDevice( &pfDev
);
287 require( result
== 0, exit
);
289 result
= getTicket( pfDev
, &ticket
, anchorPath
);
290 require( result
== 0, exit
);
292 result
= commitChange( pfDev
, ticket
, anchorPath
);