2012-04-20 14:49:04 +00:00
|
|
|
/* $Id: pfpinhole.c,v 1.7 2012/04/20 14:48:03 nanard Exp $ */
|
2012-04-18 20:53:51 +00:00
|
|
|
/* MiniUPnP project
|
|
|
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
|
|
|
* (c) 2006-2012 Thomas Bernard
|
|
|
|
* This software is subject to the conditions detailed
|
|
|
|
* in the LICENCE file provided within the distribution */
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <net/if.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <netinet/tcp.h>
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
#ifdef __DragonFly__
|
|
|
|
#include <net/pf/pfvar.h>
|
|
|
|
#else
|
|
|
|
#include <net/pfvar.h>
|
|
|
|
#endif
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <syslog.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
#include "../config.h"
|
2012-04-18 23:43:50 +00:00
|
|
|
#include "pfpinhole.h"
|
2012-04-18 20:53:51 +00:00
|
|
|
#include "../upnpglobalvars.h"
|
|
|
|
|
2012-04-20 14:49:04 +00:00
|
|
|
/* the pass rules created by add_pinhole() are as follow :
|
|
|
|
*
|
|
|
|
* pass in quick on ep0 inet6 proto udp
|
|
|
|
* from any to dead:beef::42:42 port = 8080
|
|
|
|
* flags S/SA keep state
|
|
|
|
* label "pinhole-2 ts-4321000"
|
|
|
|
*
|
|
|
|
* with the label "pinhole-$uid ts-$timestamp"
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef ENABLE_IPV6
|
2012-04-18 20:53:51 +00:00
|
|
|
/* /dev/pf when opened */
|
|
|
|
extern int dev;
|
|
|
|
|
2012-04-19 22:07:13 +00:00
|
|
|
static int uid = 1;
|
|
|
|
|
2012-04-20 14:49:04 +00:00
|
|
|
int add_pinhole(const char * ifname,
|
|
|
|
const char * rem_host, unsigned short rem_port,
|
|
|
|
const char * int_client, unsigned short int_port,
|
|
|
|
int proto, unsigned int timestamp)
|
2012-04-18 20:53:51 +00:00
|
|
|
{
|
|
|
|
struct pfioc_rule pcr;
|
2012-04-18 23:43:50 +00:00
|
|
|
#ifndef PF_NEWSTYLE
|
|
|
|
struct pfioc_pooladdr pp;
|
|
|
|
#endif
|
2012-04-18 20:53:51 +00:00
|
|
|
|
|
|
|
if(dev<0) {
|
|
|
|
syslog(LOG_ERR, "pf device is not open");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
memset(&pcr, 0, sizeof(pcr));
|
2012-04-18 23:43:50 +00:00
|
|
|
strlcpy(pcr.anchor, anchor_name, MAXPATHLEN);
|
|
|
|
|
|
|
|
#ifndef PF_NEWSTYLE
|
|
|
|
memset(&pp, 0, sizeof(pp));
|
|
|
|
strlcpy(pp.anchor, anchor_name, MAXPATHLEN);
|
|
|
|
if(ioctl(dev, DIOCBEGINADDRS, &pp) < 0) {
|
|
|
|
syslog(LOG_ERR, "ioctl(dev, DIOCBEGINADDRS, ...): %m");
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
pcr.pool_ticket = pp.ticket;
|
|
|
|
#else
|
2012-04-18 20:53:51 +00:00
|
|
|
{
|
2012-04-18 23:43:50 +00:00
|
|
|
#endif
|
2012-04-18 20:53:51 +00:00
|
|
|
pcr.rule.direction = PF_IN;
|
|
|
|
pcr.rule.action = PF_PASS;
|
|
|
|
pcr.rule.af = AF_INET6;
|
2012-04-18 23:43:50 +00:00
|
|
|
#ifdef PF_NEWSTYLE
|
|
|
|
pcr.rule.nat.addr.type = PF_ADDR_NONE;
|
|
|
|
pcr.rule.rdr.addr.type = PF_ADDR_NONE;
|
|
|
|
#endif
|
2012-04-18 20:53:51 +00:00
|
|
|
#ifdef USE_IFNAME_IN_RULES
|
|
|
|
if(ifname)
|
|
|
|
strlcpy(pcr.rule.ifname, ifname, IFNAMSIZ);
|
|
|
|
#endif
|
|
|
|
pcr.rule.proto = proto;
|
|
|
|
|
|
|
|
pcr.rule.quick = 1;/*(GETFLAG(PFNOQUICKRULESMASK))?0:1;*/
|
|
|
|
pcr.rule.log = (GETFLAG(LOGPACKETSMASK))?1:0; /*logpackets;*/
|
|
|
|
/* see the discussion on the forum :
|
|
|
|
* http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=638 */
|
|
|
|
pcr.rule.flags = TH_SYN;
|
|
|
|
pcr.rule.flagset = (TH_SYN|TH_ACK);
|
|
|
|
#ifdef PFRULE_HAS_RTABLEID
|
|
|
|
pcr.rule.rtableid = -1; /* first appeared in OpenBSD 4.0 */
|
|
|
|
#endif
|
|
|
|
#ifdef PFRULE_HAS_ONRDOMAIN
|
|
|
|
pcr.rule.onrdomain = -1; /* first appeared in OpenBSD 5.0 */
|
|
|
|
#endif
|
|
|
|
pcr.rule.keep_state = 1;
|
2012-04-19 22:07:13 +00:00
|
|
|
snprintf(pcr.rule.label, PF_RULE_LABEL_SIZE,
|
2012-04-20 14:49:04 +00:00
|
|
|
"pinhole-%d ts-%u", uid, timestamp);
|
2012-04-18 20:53:51 +00:00
|
|
|
if(queue)
|
|
|
|
strlcpy(pcr.rule.qname, queue, PF_QNAME_SIZE);
|
|
|
|
if(tag)
|
|
|
|
strlcpy(pcr.rule.tagname, tag, PF_TAG_NAME_SIZE);
|
|
|
|
|
2012-04-18 23:43:50 +00:00
|
|
|
if(rem_port) {
|
|
|
|
pcr.rule.src.port_op = PF_OP_EQ;
|
|
|
|
pcr.rule.src.port[0] = htons(rem_port);
|
|
|
|
}
|
|
|
|
if(rem_host && rem_host[0] != '\0' && rem_host[0] != '*') {
|
|
|
|
pcr.rule.src.addr.type = PF_ADDR_ADDRMASK;
|
|
|
|
if(inet_pton(AF_INET6, rem_host, &pcr.rule.src.addr.v.a.addr.v6) != 1) {
|
|
|
|
syslog(LOG_ERR, "inet_pton(%s) failed", rem_host);
|
|
|
|
}
|
2012-04-18 20:53:51 +00:00
|
|
|
memset(&pcr.rule.src.addr.v.a.mask.addr8, 255, 16);
|
|
|
|
}
|
|
|
|
|
|
|
|
pcr.rule.dst.port_op = PF_OP_EQ;
|
|
|
|
pcr.rule.dst.port[0] = htons(int_port);
|
2012-04-18 23:43:50 +00:00
|
|
|
pcr.rule.dst.addr.type = PF_ADDR_ADDRMASK;
|
2012-04-18 20:53:51 +00:00
|
|
|
if(inet_pton(AF_INET6, int_client, &pcr.rule.dst.addr.v.a.addr.v6) != 1) {
|
|
|
|
syslog(LOG_ERR, "inet_pton(%s) failed", int_client);
|
|
|
|
}
|
|
|
|
memset(&pcr.rule.dst.addr.v.a.mask.addr8, 255, 16);
|
|
|
|
|
|
|
|
if(ifname)
|
|
|
|
strlcpy(pcr.rule.ifname, ifname, IFNAMSIZ);
|
|
|
|
|
|
|
|
pcr.action = PF_CHANGE_GET_TICKET;
|
|
|
|
if(ioctl(dev, DIOCCHANGERULE, &pcr) < 0) {
|
|
|
|
syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_GET_TICKET: %m");
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
pcr.action = PF_CHANGE_ADD_TAIL;
|
|
|
|
if(ioctl(dev, DIOCCHANGERULE, &pcr) < 0) {
|
|
|
|
syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_ADD_TAIL: %m");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-19 22:07:13 +00:00
|
|
|
return (uid++);
|
|
|
|
}
|
|
|
|
|
2012-04-20 14:49:04 +00:00
|
|
|
int delete_pinhole(unsigned short uid)
|
2012-04-19 22:07:13 +00:00
|
|
|
{
|
|
|
|
int i, n;
|
|
|
|
struct pfioc_rule pr;
|
2012-04-20 14:49:04 +00:00
|
|
|
char label_start[PF_RULE_LABEL_SIZE];
|
|
|
|
char tmp_label[PF_RULE_LABEL_SIZE];
|
2012-04-19 22:07:13 +00:00
|
|
|
|
|
|
|
if(dev<0) {
|
|
|
|
syslog(LOG_ERR, "pf device is not open");
|
|
|
|
return -1;
|
|
|
|
}
|
2012-04-20 14:49:04 +00:00
|
|
|
snprintf(label_start, sizeof(label_start),
|
2012-04-19 22:07:13 +00:00
|
|
|
"pinhole-%hu", uid);
|
|
|
|
memset(&pr, 0, sizeof(pr));
|
|
|
|
strlcpy(pr.anchor, anchor_name, MAXPATHLEN);
|
|
|
|
#ifndef PF_NEWSTYLE
|
|
|
|
pr.rule.action = PF_PASS;
|
|
|
|
#endif
|
|
|
|
if(ioctl(dev, DIOCGETRULES, &pr) < 0) {
|
|
|
|
syslog(LOG_ERR, "ioctl(dev, DIOCGETRULES, ...): %m");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
n = pr.nr;
|
|
|
|
for(i=0; i<n; i++) {
|
|
|
|
pr.nr = i;
|
|
|
|
if(ioctl(dev, DIOCGETRULE, &pr) < 0) {
|
|
|
|
syslog(LOG_ERR, "ioctl(dev, DIOCGETRULE): %m");
|
|
|
|
return -1;
|
|
|
|
}
|
2012-04-20 14:49:04 +00:00
|
|
|
strlcpy(tmp_label, pr.rule.label, sizeof(tmp_label));
|
|
|
|
strtok(tmp_label, " ");
|
|
|
|
if(0 == strcmp(tmp_label, label_start)) {
|
2012-04-19 22:07:13 +00:00
|
|
|
pr.action = PF_CHANGE_GET_TICKET;
|
|
|
|
if(ioctl(dev, DIOCCHANGERULE, &pr) < 0) {
|
|
|
|
syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_GET_TICKET: %m");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
pr.action = PF_CHANGE_REMOVE;
|
|
|
|
pr.nr = i;
|
|
|
|
if(ioctl(dev, DIOCCHANGERULE, &pr) < 0) {
|
|
|
|
syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_REMOVE: %m");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* not found */
|
|
|
|
return -1;
|
2012-04-18 20:53:51 +00:00
|
|
|
}
|
|
|
|
|
2012-04-20 14:49:04 +00:00
|
|
|
#endif /* ENABLE_IPV6 */
|
2012-04-19 22:07:13 +00:00
|
|
|
|