1/*
2 * Copyright (c) 2010 Apple Computer, 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#include <string.h>
25#include <stdio.h>
26#include <sys/errno.h>
27#include <sys/signal.h>
28#include <sys/types.h>
29#include <sys/socket.h>
30#include <sys/stat.h>
31#include <sys/un.h>
32#include <unistd.h>
33#include <sys/param.h>
34#include <sys/fcntl.h>
35#include <CoreFoundation/CoreFoundation.h>
36#include <CoreFoundation/CFUserNotification.h>
37#include <SystemConfiguration/SystemConfiguration.h>
38#include <SystemConfiguration/SCPrivate.h>      // for SCLog()
39#include <SystemConfiguration/SCPreferencesPathKey.h>
40#include <IOKit/pwr_mgt/IOPMLib.h>
41#include <IOKit/IOMessage.h>
42#include <mach/mach_time.h>
43#include <mach/task_special_ports.h>
44#include <mach/mach.h>
45#include <mach/message.h>
46#include <mach/boolean.h>
47#include <mach/mach_error.h>
48#include <mach/mach_time.h>
49#include <notify.h>
50#include <sys/sysctl.h>
51#include <ifaddrs.h>
52#include <SystemConfiguration/SCNetworkSignature.h>
53
54#include "scnc_mach_server.h"
55#include "scnc_main.h"
56#include "ppp_msg.h"
57#include "ppp_privmsg.h"
58#include "scnc_client.h"
59#include "ipsec_manager.h"
60#include "ppp_manager.h"
61#include "ppp_option.h"
62#include "ppp_socket_server.h"
63#include "scnc_utils.h"
64#include "if_ppplink.h"
65#include "PPPControllerPriv.h"
66#include "pppd.h"
67
68/* -----------------------------------------------------------------------------
69  Declarations
70 ----------------------------------------------------------------------------- */
71
72int racoon_send_cmd_start_dpd(int fd, u_int32_t address) ;
73
74
75static void
76startProbe (struct service *serv)
77{
78    if (serv->type == TYPE_IPSEC) {
79        racoon_send_cmd_start_dpd(serv->u.ipsec.controlfd,
80                                  serv->u.ipsec.peer_address.sin_addr.s_addr);
81        serv->u.ipsec.awaiting_peer_resp = 1;
82    }
83}
84
85static const char *
86getPortMappingType (struct service *serv)
87{
88	if (serv) {
89		switch (serv->type) {
90			case TYPE_IPSEC: return (const char *)"IPSec";
91		}
92	}
93
94	return (const char *)"INVALID";
95}
96
97static int
98isServiceConnected (struct service *serv)
99{
100	switch (serv->type) {
101		case TYPE_IPSEC: return (serv->u.ipsec.phase != IPSEC_IDLE);
102	}
103	return 0;
104}
105
106static const char *
107getInterfaceName (struct service *serv)
108{
109	if (serv) {
110		switch (serv->type) {
111			case TYPE_IPSEC: return (const char*)serv->u.ipsec.lower_interface;
112		}
113	}
114	return (const char *)"NULL";
115}
116
117static u_int32_t
118getInterfaceNameSize (struct service *serv)
119{
120	if (serv) {
121		switch (serv->type) {
122			case TYPE_IPSEC: return sizeof(serv->u.ipsec.lower_interface);
123		}
124	}
125	return 4; // "NULL"
126}
127
128static uint32_t
129getInterfaceIndex (struct service *serv)
130{
131	const char *str = getInterfaceName(serv);
132
133	if (str)
134		return if_nametoindex(str);
135	return 0;
136}
137
138static void
139clearOnePortMapping (mdns_nat_mapping_t *mapping)
140{
141	if (mapping) {
142		// what about mapping->mDNSRef_fd?
143		if (mapping->mDNSRef != NULL) {
144			DNSServiceRefDeallocate(mapping->mDNSRef);
145		}
146		bzero(mapping, sizeof(*mapping));
147	}
148}
149
150static int
151ignorePortMappingUpdate (DNSServiceRef       sdRef,
152						 struct service     *serv,
153						 char               *sd_name,
154						 char               *if_name,
155						 uint32_t            if_name_siz,
156						 uint32_t            interfaceIndex,
157						 uint32_t            publicAddress,
158						 DNSServiceProtocol  protocol,
159						 uint16_t            privatePort,
160						 uint16_t            publicPort)
161{
162    int i = 0, vpn = 0, found = 0;
163    struct ifaddrs *ifap = NULL;
164	u_int8_t interfaceName[sizeof(serv->u.ipsec.lower_interface)];
165
166	/* check if address still exist */
167	if (getifaddrs(&ifap) == 0) {
168		struct ifaddrs *ifa;
169		for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
170			if (ifa->ifa_name
171				&& ifa->ifa_addr
172				&& (!strncmp(ifa->ifa_name, "utun", 4) || !strncmp(ifa->ifa_name, "ppp", 3))
173				&& ifa->ifa_addr->sa_family == AF_INET
174				&& (ALIGNED_CAST(struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == htonl(publicAddress)) {
175				SCLog(TRUE, LOG_INFO, CFSTR("%s port-mapping update for %s ignored: related to VPN interface. Public Address: %x, Protocol: %s, Private Port: %d, Public Port: %d."),
176					   sd_name,
177					   ifa->ifa_name,
178					   publicAddress,
179					   (protocol == 0)? "None":((protocol == kDNSServiceProtocol_UDP)? "UDP":"TCP"),
180					   privatePort,
181					   publicPort);
182				vpn = 1;
183			}
184			if (ifa->ifa_name
185				&& ifa->ifa_addr
186				&& !strncmp(ifa->ifa_name, if_name, if_name_siz)
187				&& ifa->ifa_addr->sa_family == AF_INET
188				&& (ALIGNED_CAST(struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == serv->u.ipsec.our_address.sin_addr.s_addr) {
189				found = 1;
190			}
191		}
192		freeifaddrs(ifap);
193	} else {
194		SCLog(TRUE, LOG_ERR, CFSTR("%s port-mapping update for %s ignored: failed to get interface list."),
195			   sd_name,
196			   if_name);
197		return 1;
198	}
199
200	if (vpn) {
201		return 1;
202	}
203
204	if_indextoname(interfaceIndex, (char *)interfaceName);
205	if (!strncmp((const char *)interfaceName, (const char *)if_name, if_name_siz)) {
206		if (strstr(if_name, "ppp") || strstr(if_name, "utun")) {
207			// change on PPP interface... we don't care
208			SCLog(TRUE, LOG_NOTICE, CFSTR("%s port-mapping update for %s ignored: underlying interface is PPP/VPN. Public Address: %x, Protocol: %s, Private Port: %d, Public Port: %d."),
209				   sd_name,
210				   if_name,
211				   publicAddress,
212				   (protocol == 0)? "None":((protocol == kDNSServiceProtocol_UDP)? "UDP":"TCP"),
213				   privatePort,
214				   publicPort);
215			return 1;
216		} else {
217			/* check if address still exist */
218			if (found) {
219				return 0;
220			} else {
221				if (!publicAddress || (!publicPort && privatePort)) {
222					SCLog(TRUE, LOG_INFO, CFSTR("%s port-mapping update for %s ignored: underlying interface down. Public Address: %x, Protocol: %s, Private Port: %d, Public Port: %d."),
223						   sd_name,
224						   if_name,
225						   publicAddress,
226						   (protocol == 0)? "None":((protocol == kDNSServiceProtocol_UDP)? "UDP":"TCP"),
227						   privatePort,
228						   publicPort);
229					for (i = 0; i < serv->nat_mapping_cnt && i < MDNS_NAT_MAPPING_MAX; i++) {
230						if (serv->nat_mapping[i].mDNSRef_tmp == sdRef) {
231							serv->nat_mapping[i].up = 0;
232							SCLog(TRUE, LOG_INFO, CFSTR("%s port-mapping for %s flagged down because of no connectivity."), sd_name, if_name);
233						}
234					}
235					return 1;
236				}
237				SCLog(TRUE, LOG_INFO, CFSTR("%s port-mapping update for %s ignored: underlying interface's address changed. Public Address: %x, Protocol: %s, Private Port: %d, Public Port: %d."),
238					   sd_name,
239					   if_name,
240					   publicAddress,
241					   (protocol == 0)? "None":((protocol == kDNSServiceProtocol_UDP)? "UDP":"TCP"),
242					   privatePort,
243					   publicPort);
244				return 1;
245			}
246		}
247	} else if (publicAddress && !publicPort && !privatePort && !protocol) {
248		// an update on the NAT's public IP
249		return 0;
250	} else {
251		// public interface disappeared?
252		if (!publicAddress && !publicPort && !privatePort && !protocol) {
253			return 0;
254		}
255		/* check if address still exist */
256		if (serv->type == TYPE_IPSEC && serv->u.ipsec.our_address.sin_addr.s_addr == htonl(publicAddress) && found) {
257			return 0;
258		}
259		// change due to another interface, ignore for now
260		SCLog(TRUE, LOG_INFO, CFSTR("%s port-mapping update for %s ignored: not for interface %s. Public Address: %x, Protocol: %s, Private Port: %d, Public Port: %d."),
261			   sd_name,
262			   interfaceName,
263			   if_name,
264			   publicAddress,
265			   (protocol == 0)? "None":((protocol == kDNSServiceProtocol_UDP)? "UDP":"TCP"),
266			   privatePort,
267			   publicPort);
268		return 1;
269	}
270}
271
272#define FAR_FUTURE          (60.0 * 60.0 * 24.0 * 365.0 * 1000.0)
273#define PUBLIC_NAT_PORT_MAPPING_TIMEOUT 20
274
275static void
276stop_public_nat_port_mapping_timer (struct service *serv)
277{
278	if (serv->type == TYPE_IPSEC) {
279		if (serv->u.ipsec.port_mapping_timerref) {
280			CFRunLoopRemoveTimer(serv->u.ipsec.port_mapping_timerrun, serv->u.ipsec.port_mapping_timerref, kCFRunLoopCommonModes);
281			my_CFRelease(&serv->u.ipsec.port_mapping_timerref);
282		}
283	}
284}
285
286static void
287public_port_mapping_timeout (CFRunLoopTimerRef timer, void *info)
288{
289	struct service *serv = info;
290
291	if (serv->type == TYPE_IPSEC) {
292		SCLog(TRUE, LOG_ERR, CFSTR("NAT's public interface down for more than %d secs... starting faster probe."),
293			   PUBLIC_NAT_PORT_MAPPING_TIMEOUT);
294		startProbe(serv);
295	}
296}
297
298static void
299start_public_nat_port_mapping_timer (struct service *serv)
300{
301    CFRunLoopTimerContext	context = { 0, serv, NULL, NULL, NULL };
302
303	if (serv->type == TYPE_IPSEC) {
304		if (serv->u.ipsec.interface_timerref || serv->u.ipsec.port_mapping_timerref) {
305			return;
306		}
307
308		SCLog(TRUE, LOG_INFO, CFSTR("starting wait-port-mapping timer for IPSec: %d secs"), PUBLIC_NAT_PORT_MAPPING_TIMEOUT);
309		serv->u.ipsec.port_mapping_timerref = CFRunLoopTimerCreate(NULL, CFAbsoluteTimeGetCurrent() + PUBLIC_NAT_PORT_MAPPING_TIMEOUT, FAR_FUTURE, 0, 0, public_port_mapping_timeout, &context);
310		if (!serv->u.ipsec.port_mapping_timerref) {
311			SCLog(TRUE, LOG_ERR, CFSTR("IPSec Controller: public interface down, cannot create RunLoop timer... starting faster probe."));
312			startProbe(serv);
313			return;
314		}
315		CFRunLoopAddTimer(serv->u.ipsec.port_mapping_timerrun, serv->u.ipsec.port_mapping_timerref, kCFRunLoopCommonModes);
316	}
317}
318
319static void clearPortMapping (struct service *serv);
320
321static void
322setPortMappingCallback (DNSServiceRef        sdRef,
323						DNSServiceFlags      flags,
324						uint32_t             interfaceIndex,
325						DNSServiceErrorType  errorCode,
326						uint32_t             nPublicAddress,	   /* four byte IPv4 address in network byte order */
327						DNSServiceProtocol   protocol,
328						uint16_t             nPrivatePort,
329						uint16_t             nPublicPort,	   /* may be different than the requested port */
330						uint32_t             ttl,			   /* may be different than the requested ttl */
331						void                *context)
332{
333	uint32_t publicAddress = ntohl(nPublicAddress);
334	uint16_t privatePort = ntohs(nPrivatePort);
335	uint16_t publicPort = ntohs(nPublicPort);
336	int i;
337	struct service *serv = (__typeof__(serv))context;
338	const char *sd_name = getPortMappingType(serv);
339	int is_connected = isServiceConnected(serv);
340	const char *if_name = getInterfaceName(serv);
341	u_int32_t if_name_siz = getInterfaceNameSize(serv);
342
343	if (serv->u.ipsec.modecfg_defaultroute) {
344		SCLog(TRUE, LOG_NOTICE, CFSTR("%s port-mapping update for %s ignored: VPN is the Primary interface. Public Address: %x, Protocol: %s, Private Port: %d, Public Port: %d"),
345			  sd_name,
346			  if_name,
347			  publicAddress,
348			  (protocol == 0)? "None":((protocol == kDNSServiceProtocol_UDP)? "UDP":"TCP"),
349			  privatePort,
350			  publicPort);
351		clearPortMapping(serv);
352		return;
353	}
354
355	if (errorCode != kDNSServiceErr_NoError && errorCode != kDNSServiceErr_DoubleNAT) {
356		SCLog(TRUE, LOG_ERR, CFSTR("%s failed to set port-mapping for %s, errorCode: %d."), sd_name, if_name, errorCode);
357		if (errorCode == kDNSServiceErr_NATPortMappingUnsupported || errorCode == kDNSServiceErr_NATPortMappingDisabled) {
358			for (i = 0; i < serv->nat_mapping_cnt && i < MDNS_NAT_MAPPING_MAX; i++) {
359				if (serv->nat_mapping[i].mDNSRef_tmp == sdRef) {
360					SCLog(TRUE, LOG_ERR, CFSTR("%s port-mapping for %s became invalid. is Connected: %d, Protocol: %s, Private Port: %d, Previous publicAddress: (%x), Previous publicPort: (%d)."),
361						   sd_name,
362						   if_name,
363						   is_connected,
364						   (protocol == 0)? "None":((protocol == kDNSServiceProtocol_UDP)? "UDP":"TCP"),
365						   privatePort,
366						   serv->nat_mapping[i].reflexive.addr,
367						   serv->nat_mapping[i].reflexive.port);
368					if (serv->nat_mapping[i].up && is_connected) {
369						SCLog(TRUE, LOG_NOTICE, CFSTR("%s public port-mapping for %s changed... starting faster probe."), sd_name, if_name);
370						startProbe(serv);
371					} else {
372						clearPortMapping(serv);
373					}
374					return;
375				}
376			}
377		} else if (errorCode == kDNSServiceErr_ServiceNotRunning) {
378			clearPortMapping(serv);
379		}
380		return;
381	}
382
383	if (ignorePortMappingUpdate(sdRef, serv, (char *)sd_name, (char *)if_name, if_name_siz, interfaceIndex, publicAddress, protocol, privatePort, publicPort)) {
384		return;
385	}
386
387	SCLog(TRUE, LOG_INFO, CFSTR("%s port-mapping for %s, Protocol: %s, Private Port: %d, Public Address: %x, Public Port: %d, TTL: %d%s."),
388		   sd_name,
389		   if_name,
390		   (protocol == 0)? "None":((protocol == kDNSServiceProtocol_UDP)? "UDP":"TCP"),
391		   privatePort,
392		   publicAddress,
393		   publicPort,
394		   ttl,
395		   (errorCode == kDNSServiceErr_DoubleNAT)? " (Double NAT)" : ".");
396
397	// generate a disconnect if we were already connected and we just detected a change in publicAddress or publicPort
398	for (i = 0; i < serv->nat_mapping_cnt && i < MDNS_NAT_MAPPING_MAX; i++) {
399		if (serv->nat_mapping[i].mDNSRef_tmp == sdRef) {
400			if (serv->nat_mapping[i].up && !publicAddress && !publicPort) {
401				SCLog(TRUE, LOG_NOTICE, CFSTR("%s port-mapping for %s indicates public interface down. Public Address: %x, Protocol: %s, Private Port: %d, Public Port: %d."),
402					   sd_name,
403					   if_name,
404					   publicAddress,
405					   (protocol == 0)? "None":((protocol == kDNSServiceProtocol_UDP)? "UDP":"TCP"),
406					   privatePort,
407					   publicPort);
408				start_public_nat_port_mapping_timer(serv);
409				return;
410			} else if (serv->nat_mapping[i].up) {
411				stop_public_nat_port_mapping_timer(serv);
412			}
413
414			if (serv->type == TYPE_IPSEC && serv->u.ipsec.our_address.sin_addr.s_addr == htonl(publicAddress) &&
415				privatePort == publicPort) {
416				SCLog(TRUE, LOG_NOTICE, CFSTR("%s port-mapping update for %s indicates no NAT. Public Address: %x, Protocol: %s, Private Port: %d, Public Port: %d."),
417					   sd_name,
418					   if_name,
419					   publicAddress,
420					   (protocol == 0)? "None":((protocol == kDNSServiceProtocol_UDP)? "UDP":"TCP"),
421					   privatePort,
422					   publicPort);
423			}
424
425			if (serv->nat_mapping[i].interfaceIndex == interfaceIndex &&
426				serv->nat_mapping[i].protocol == protocol &&
427				serv->nat_mapping[i].privatePort == privatePort) {
428				SCLog(TRUE, LOG_INFO, CFSTR("%s port-mapping for %s consistent. is Connected: %d, interface: %d, protocol: %d, privatePort: %d."),
429					   sd_name, if_name, is_connected, interfaceIndex, protocol, privatePort);
430			} else {
431				// inconsistency (mostly because of mdns api only works for the primary interface): TODO revise
432				if (serv->nat_mapping[i].interfaceIndex != interfaceIndex) {
433					SCLog(TRUE, LOG_INFO, CFSTR("%s port-mapping for %s inconsistent. is Connected: %d, Previous interface: %d, Current interface %d."),
434						   sd_name, if_name, is_connected, serv->nat_mapping[i].interfaceIndex, interfaceIndex);
435					serv->nat_mapping[i].interfaceIndex = interfaceIndex;
436				}
437				if (serv->nat_mapping[i].protocol != protocol) {
438					SCLog(TRUE, LOG_INFO, CFSTR("%s port-mapping for %s inconsistent. is Connected: %d, Previous protocol: %x, Current protocol %x."),
439						   sd_name, if_name, is_connected, serv->nat_mapping[i].protocol, protocol);
440					serv->nat_mapping[i].protocol = protocol;
441				} else if (serv->nat_mapping[i].privatePort != privatePort) {
442					SCLog(TRUE, LOG_INFO, CFSTR("%s port-mapping for %s inconsistent. is Connected: %d, Previous privatePort: %d, Current privatePort %d."),
443						   sd_name, if_name, serv->nat_mapping[i].privatePort, privatePort);
444					serv->nat_mapping[i].privatePort = privatePort;
445				}
446			}
447			// is mapping up?
448			if (!serv->nat_mapping[i].up) {
449				if (serv->nat_mapping[i].reflexive.addr != publicAddress) {
450					SCLog(TRUE, LOG_INFO, CFSTR("%s port-mapping for %s initialized. is Connected: %d, Previous publicAddress: (%x), Current publicAddress %x."),
451						   sd_name, if_name, is_connected, serv->nat_mapping[i].reflexive.addr, publicAddress);
452					serv->nat_mapping[i].reflexive.addr = publicAddress;
453				}
454				if (serv->nat_mapping[i].reflexive.port != publicPort) {
455					SCLog(TRUE, LOG_INFO, CFSTR("%s port-mapping for %s initialized. is Connected: %d, Previous publicPort: (%d), Current publicPort %d."),
456						   sd_name, if_name, is_connected, serv->nat_mapping[i].reflexive.port, publicPort);
457					serv->nat_mapping[i].reflexive.port = publicPort;
458				}
459				if (serv->nat_mapping[i].reflexive.addr &&
460				    ((!privatePort && !serv->nat_mapping[i].reflexive.port) || (serv->nat_mapping[i].reflexive.port))) {
461					// flag up mapping
462					serv->nat_mapping[i].up = 1;
463					SCLog(TRUE, LOG_INFO, CFSTR("%s port-mapping for %s fully initialized. Flagging up."), sd_name, if_name);
464				}
465				return;
466			}
467
468			if (serv->nat_mapping[i].reflexive.addr != publicAddress) {
469				SCLog(TRUE, LOG_ERR, CFSTR("%s port-mapping for %s changed. is Connected: %d, Previous publicAddress: (%x), Current publicAddress %x."),
470					   sd_name, if_name, is_connected, serv->nat_mapping[i].reflexive.addr, publicAddress);
471				if (is_connected) {
472					if (!privatePort || publicAddress) {
473						SCLog(TRUE, LOG_ERR, CFSTR("NAT's public address down or changed... starting faster probe."));
474						startProbe(serv);
475						return;
476					}
477					// let function that handles (KEV_INET_NEW_ADDR || KEV_INET_CHANGED_ADDR || KEV_INET_ADDR_DELETED) deal with the connection
478					return;
479				}
480				serv->nat_mapping[i].reflexive.addr = publicAddress;
481				return;
482			}
483			if (serv->nat_mapping[i].reflexive.port != publicPort) {
484				SCLog(TRUE, LOG_ERR, CFSTR("%s port-mapping for %s changed. is Connected: %d, Previous publicPort: (%d), Current publicPort %d."),
485					   sd_name, if_name, is_connected, serv->nat_mapping[i].reflexive.port, publicPort);
486				if (is_connected) {
487					if (!privatePort || publicPort) {
488						SCLog(TRUE, LOG_ERR, CFSTR("NAT's public port down or changed... starting faster probe."));
489						startProbe(serv);
490						return;
491					}
492					// let function that handles (KEV_INET_NEW_ADDR || KEV_INET_CHANGED_ADDR || KEV_INET_ADDR_DELETED) deal with the connection
493					return;
494				}
495				serv->nat_mapping[i].reflexive.port = publicPort;
496				return;
497			}
498			if (errorCode == kDNSServiceErr_DoubleNAT) {
499				SCLog(TRUE, LOG_NOTICE, CFSTR("%s port-mapping for %s hasn't changed, however there's a Double NAT.  is Connected: %d."),
500					   sd_name, if_name, is_connected);
501			}
502			return;
503		}
504	}
505	return;
506}
507
508static void
509clearPortMapping (struct service *serv)
510{
511	int i;
512	const char *sd_name = getPortMappingType(serv);
513	const char *if_name = getInterfaceName(serv);
514
515	stop_public_nat_port_mapping_timer(serv);
516
517	if (!serv->nat_mapping_cnt)
518		return;
519
520	SCLog(TRUE, LOG_INFO, CFSTR("%s clearing port-mapping for %s."), sd_name, if_name);
521
522	for (i = 0; i < serv->nat_mapping_cnt && i < MDNS_NAT_MAPPING_MAX; i++) {
523		clearOnePortMapping(&serv->nat_mapping[i]);
524	}
525	serv->nat_mapping_cnt = 0;
526}
527
528static int
529setPortMapping (struct service     *serv,
530				mdns_nat_mapping_t *mapping,
531				uint32_t            interfaceIndex,
532				DNSServiceProtocol  protocol,
533				uint16_t            privatePort,
534				int                 probeOnly)
535{
536	DNSServiceErrorType err = kDNSServiceErr_NoError;
537	uint16_t publicPort;
538	uint32_t ttl;
539	const char *sd_name = getPortMappingType(serv);
540	const char *if_name = getInterfaceName(serv);
541
542	if (mapping == NULL) {
543		SCLog(TRUE, LOG_ERR, CFSTR("%s invalid mapping pointer for %s."), sd_name, if_name);
544		return -1;
545	}
546
547	if (!probeOnly) {
548		publicPort = 0;
549		ttl = 2 * 3600; // 2 hours
550	} else {
551		publicPort = 0;
552		ttl = 0;
553		protocol = 0;
554		privatePort = 0;
555		interfaceIndex = 0;
556	}
557
558	if (mapping->mDNSRef == NULL) {
559		err = DNSServiceCreateConnection(&mapping->mDNSRef);
560		if (err != kDNSServiceErr_NoError || mapping->mDNSRef == NULL) {
561			SCLog(TRUE, LOG_ERR, CFSTR("%s Error calling DNSServiceCreateConnection for %s, error: %d."), sd_name, if_name, err);
562			clearOnePortMapping(mapping);
563			return -1;
564		}
565		err = DNSServiceSetDispatchQueue(mapping->mDNSRef, dispatch_get_current_queue());
566		if (err != kDNSServiceErr_NoError) {
567			SCLog(TRUE, LOG_ERR, CFSTR("%s Error calling DNSServiceSetDispatchQueue for %s, error: %d."), sd_name, if_name, err);
568			clearOnePortMapping(mapping);
569			return -1;
570		}
571		if (!serv->u.ipsec.port_mapping_timerrun) {
572			serv->u.ipsec.port_mapping_timerrun = (__typeof__(serv->u.ipsec.port_mapping_timerrun))my_CFRetain(CFRunLoopGetCurrent());
573		}
574	}
575	mapping->mDNSRef_tmp = mapping->mDNSRef;
576	err = DNSServiceNATPortMappingCreate(&mapping->mDNSRef_tmp, kDNSServiceFlagsShareConnection, interfaceIndex, protocol, htons(privatePort), publicPort, ttl, setPortMappingCallback, serv);
577	if (err != kDNSServiceErr_NoError) {
578		SCLog(TRUE, LOG_ERR, CFSTR("%s Error calling DNSServiceNATPortMappingCreate for %s, error: %d."), sd_name, if_name, err);
579		clearOnePortMapping(mapping);
580		return -1;
581	}
582	mapping->interfaceIndex = interfaceIndex;
583	mapping->protocol = protocol;
584	mapping->privatePort = privatePort;
585	bzero(&mapping->reflexive, sizeof(mapping->reflexive));
586
587	SCLog(TRUE, LOG_INFO, CFSTR("%s set port-mapping for %s, interface: %d, protocol: %d, privatePort: %d."), sd_name, if_name, interfaceIndex, protocol, privatePort);
588	return 0;
589}
590
591static void
592ipsecSetPortMapping (struct service *serv)
593{
594	const char *if_name = getInterfaceName(serv);
595	u_int32_t interfaceIndex = getInterfaceIndex(serv);
596
597	// exit early if interface is PPP/VPN
598	if (strstr(if_name, "ppp") || strstr(if_name, "utun")) {
599		return;
600	}
601
602	if (setPortMapping(serv, &serv->nat_mapping[0], interfaceIndex, 0, 0, 1) == 0) {
603		serv->nat_mapping_cnt++;
604	}
605#if 0 // <rdar://problem/8001582>
606	if (setPortMapping(serv, &serv->nat_mapping[1], interfaceIndex, kDNSServiceProtocol_UDP, (u_int16_t)500, 0) == 0) {
607		serv->nat_mapping_cnt++;
608	}
609	if (setPortMapping(serv, &serv->nat_mapping[2], interfaceIndex, kDNSServiceProtocol_UDP, (u_int16_t)4500, 0) == 0) {
610		serv->nat_mapping_cnt++;
611	}
612#endif
613}
614
615void
616nat_port_mapping_set (struct service *serv)
617{
618	if (!serv)
619		return;
620
621	if (serv->u.ipsec.modecfg_defaultroute) {
622		const char *sd_name = getPortMappingType(serv);
623		const char *if_name = getInterfaceName(serv);
624
625		SCLog(TRUE, LOG_NOTICE, CFSTR("%s port-mapping API for %s ignored: VPN is the primary interface."),
626			  sd_name,
627			  if_name);
628		return;
629	}
630
631	if (serv->nat_mapping_cnt) {
632		clearPortMapping(serv);
633	}
634
635	switch (serv->type) {
636		case TYPE_PPP: break;
637		case TYPE_IPSEC: ipsecSetPortMapping(serv); break;
638	}
639}
640
641void
642nat_port_mapping_clear (struct service *serv)
643{
644	if (!serv)
645		return;
646
647	clearPortMapping(serv);
648}
649