contrib: fwd - initial C implementation of the uci firewall
This commit is contained in:
parent
e8220d96a5
commit
2e9ac3b342
11 changed files with 2220 additions and 0 deletions
14
contrib/fwd/src/Makefile
Normal file
14
contrib/fwd/src/Makefile
Normal file
|
@ -0,0 +1,14 @@
|
|||
CFLAGS := -g -Wall -I./uci -I./iptables-1.4.5/include
|
||||
LDFLAGS := -luci -liptc -L./iptables-1.4.5/libiptc/.libs
|
||||
|
||||
fwd:
|
||||
$(CC) $(CFLAGS) -c -o ucix.o ucix.c
|
||||
$(CC) $(CFLAGS) -c -o fwd_addr.o fwd_addr.c
|
||||
$(CC) $(CFLAGS) -c -o fwd_rules.o fwd_rules.c
|
||||
$(CC) $(CFLAGS) -c -o fwd_config.o fwd_config.c
|
||||
$(CC) $(CFLAGS) -c -o fwd.o fwd.c
|
||||
$(CC) $(LDFLAGS) -o fwd fwd.o fwd_addr.o fwd_rules.o fwd_config.o ucix.o
|
||||
|
||||
clean:
|
||||
rm -f *~ fwd *.o
|
||||
|
57
contrib/fwd/src/fwd.c
Normal file
57
contrib/fwd/src/fwd.c
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* fwd - OpenWrt firewall daemon - main part
|
||||
*
|
||||
* Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org>
|
||||
*
|
||||
* The fwd program is free software: you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* The fwd program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with the fwd program. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
|
||||
#include "fwd.h"
|
||||
#include "fwd_addr.h"
|
||||
#include "fwd_rules.h"
|
||||
#include "fwd_config.h"
|
||||
|
||||
#define IPT "iptables"
|
||||
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
struct fwd_handle *h;
|
||||
|
||||
if( !(h = fwd_alloc_ptr(struct fwd_handle)) )
|
||||
fwd_fatal("Out of memory");
|
||||
|
||||
if( !(h->conf = fwd_read_config()) )
|
||||
fwd_fatal("Failed to read configuration");
|
||||
|
||||
if( (h->rtnl_socket = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1 )
|
||||
fwd_fatal("Failed to create AF_NETLINK socket (%m)");
|
||||
|
||||
if( !(h->addrs = fwd_get_addrs(h->rtnl_socket, AF_INET)) )
|
||||
fwd_fatal("Failed to issue RTM_GETADDR (%m)");
|
||||
|
||||
|
||||
fwd_ipt_build_ruleset(h);
|
||||
|
||||
fwd_ipt_addif(h, "lan");
|
||||
fwd_ipt_addif(h, "wan");
|
||||
|
||||
|
||||
close(h->rtnl_socket);
|
||||
fwd_free_config(h->conf);
|
||||
fwd_free_addrs(h->addrs);
|
||||
fwd_free_ptr(h);
|
||||
|
||||
return 0;
|
||||
}
|
201
contrib/fwd/src/fwd.h
Normal file
201
contrib/fwd/src/fwd.h
Normal file
|
@ -0,0 +1,201 @@
|
|||
/*
|
||||
* fwd - OpenWrt firewall daemon - data structures
|
||||
*
|
||||
* Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org>
|
||||
*
|
||||
* The fwd program is free software: you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* The fwd program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with the fwd program. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#ifndef __FWD_H__
|
||||
#define __FWD_H__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#if 0
|
||||
#include "fwd_addr.h"
|
||||
#include "fwd_rules.h"
|
||||
#include "fwd_config.h"
|
||||
#endif
|
||||
|
||||
enum fwd_policy {
|
||||
FWD_P_UNSPEC = 0,
|
||||
FWD_P_DROP = 1,
|
||||
FWD_P_REJECT = 2,
|
||||
FWD_P_ACCEPT = 3
|
||||
};
|
||||
|
||||
enum fwd_stype {
|
||||
FWD_S_DEFAULTS = 0,
|
||||
FWD_S_ZONE = 1,
|
||||
FWD_S_FORWARD = 2,
|
||||
FWD_S_REDIRECT = 3,
|
||||
FWD_S_RULE = 4,
|
||||
FWD_S_INCLUDE = 5
|
||||
};
|
||||
|
||||
enum fwd_ptype {
|
||||
FWD_PR_CUSTOM = 0,
|
||||
FWD_PR_TCP = 1,
|
||||
FWD_PR_UDP = 2,
|
||||
FWD_PR_TCPUDP = 3,
|
||||
FWD_PR_ICMP = 4,
|
||||
FWD_PR_ALL = 5
|
||||
};
|
||||
|
||||
struct fwd_portrange {
|
||||
unsigned short min;
|
||||
unsigned short max;
|
||||
};
|
||||
|
||||
struct fwd_cidr {
|
||||
struct in_addr addr;
|
||||
int prefix;
|
||||
};
|
||||
|
||||
struct fwd_mac {
|
||||
unsigned char mac[6];
|
||||
};
|
||||
|
||||
struct fwd_proto {
|
||||
enum fwd_ptype type;
|
||||
int proto;
|
||||
};
|
||||
|
||||
struct fwd_icmptype {
|
||||
char name[32];
|
||||
int type;
|
||||
int code;
|
||||
};
|
||||
|
||||
struct fwd_network_list {
|
||||
char *name;
|
||||
char *ifname;
|
||||
int isalias;
|
||||
struct fwd_cidr *addr;
|
||||
struct fwd_network_list *next;
|
||||
};
|
||||
|
||||
struct fwd_defaults {
|
||||
enum fwd_policy input;
|
||||
enum fwd_policy forward;
|
||||
enum fwd_policy output;
|
||||
int syn_flood;
|
||||
int syn_rate;
|
||||
int syn_burst;
|
||||
int drop_invalid;
|
||||
};
|
||||
|
||||
struct fwd_zone {
|
||||
char *name;
|
||||
struct fwd_network_list *networks;
|
||||
enum fwd_policy input;
|
||||
enum fwd_policy forward;
|
||||
enum fwd_policy output;
|
||||
int masq;
|
||||
int mtu_fix;
|
||||
int conntrack;
|
||||
};
|
||||
|
||||
struct fwd_forwarding {
|
||||
struct fwd_zone *src;
|
||||
struct fwd_zone *dest;
|
||||
int mtu_fix; /* legacy */
|
||||
int masq; /* new */
|
||||
};
|
||||
|
||||
struct fwd_redirect {
|
||||
struct fwd_zone *src;
|
||||
struct fwd_cidr *src_ip;
|
||||
struct fwd_mac *src_mac;
|
||||
struct fwd_portrange *src_port;
|
||||
struct fwd_portrange *src_dport;
|
||||
struct fwd_cidr *dest_ip;
|
||||
struct fwd_portrange *dest_port;
|
||||
struct fwd_proto *proto;
|
||||
};
|
||||
|
||||
struct fwd_rule {
|
||||
struct fwd_zone *src;
|
||||
struct fwd_zone *dest;
|
||||
struct fwd_cidr *src_ip;
|
||||
struct fwd_mac *src_mac;
|
||||
struct fwd_portrange *src_port;
|
||||
struct fwd_cidr *dest_ip;
|
||||
struct fwd_portrange *dest_port;
|
||||
struct fwd_proto *proto;
|
||||
struct fwd_icmptype *icmp_type;
|
||||
enum fwd_policy target;
|
||||
};
|
||||
|
||||
struct fwd_include {
|
||||
char *path;
|
||||
};
|
||||
|
||||
struct fwd_data {
|
||||
enum fwd_stype type;
|
||||
struct fwd_data *next;
|
||||
union {
|
||||
struct fwd_defaults defaults;
|
||||
struct fwd_zone zone;
|
||||
struct fwd_forwarding forwarding;
|
||||
struct fwd_redirect redirect;
|
||||
struct fwd_rule rule;
|
||||
struct fwd_include include;
|
||||
} section;
|
||||
};
|
||||
|
||||
|
||||
struct fwd_handle {
|
||||
int rtnl_socket;
|
||||
struct fwd_data *conf;
|
||||
struct fwd_addr_list *addrs;
|
||||
};
|
||||
|
||||
|
||||
/* fwd_zmalloc(size_t)
|
||||
* Allocates a zeroed buffer of the given size. */
|
||||
static void * fwd_zmalloc(size_t s)
|
||||
{
|
||||
void *b = malloc(s);
|
||||
|
||||
if( b != NULL )
|
||||
memset(b, 0, s);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
/* fwd_fatal(fmt, ...)
|
||||
* Prints message to stderr and termintes program. */
|
||||
#define fwd_fatal(...) do { \
|
||||
fprintf(stderr, "ERROR: "); \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
fprintf(stderr, "\n"); \
|
||||
exit(1); \
|
||||
} while(0)
|
||||
|
||||
/* fwd_alloc_ptr(type)
|
||||
* Allocates a buffer with the size of the given datatype
|
||||
* and returns a pointer to it. */
|
||||
#define fwd_alloc_ptr(t) (t *) fwd_zmalloc(sizeof(t))
|
||||
|
||||
/* fwd_free_ptr(void *)
|
||||
* Frees the given pointer and sets it to NULL.
|
||||
* Safe for NULL values. */
|
||||
#define fwd_free_ptr(x) do { if(x != NULL) free(x); x = NULL; } while(0)
|
||||
|
||||
#endif
|
150
contrib/fwd/src/fwd_addr.c
Normal file
150
contrib/fwd/src/fwd_addr.c
Normal file
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
* fwd - OpenWrt firewall daemon - rtnetlink communication
|
||||
*
|
||||
* Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org>
|
||||
*
|
||||
* The fwd program is free software: you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* The fwd program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with the fwd program. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
|
||||
#include "fwd.h"
|
||||
#include "fwd_addr.h"
|
||||
|
||||
struct fwd_addr_list * fwd_get_addrs(int fd, int family)
|
||||
{
|
||||
struct {
|
||||
struct nlmsghdr n;
|
||||
struct ifaddrmsg r;
|
||||
} req;
|
||||
|
||||
int offlen;
|
||||
int rtattrlen;
|
||||
int dump_done;
|
||||
char buf[16384];
|
||||
|
||||
struct rtattr *rta;
|
||||
struct rtattr *rtatp;
|
||||
struct nlmsghdr *nlmp;
|
||||
struct ifaddrmsg *rtmp;
|
||||
|
||||
struct fwd_addr_list *head, *entry;
|
||||
|
||||
/* Build request */
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
|
||||
req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
|
||||
req.n.nlmsg_type = RTM_GETADDR;
|
||||
req.r.ifa_family = family;
|
||||
|
||||
rta = (struct rtattr *)(((char *)&req) + NLMSG_ALIGN(req.n.nlmsg_len));
|
||||
rta->rta_len = RTA_LENGTH(family == AF_INET ? 4 : 16);
|
||||
|
||||
head = entry = NULL;
|
||||
|
||||
/* Send request */
|
||||
if( send(fd, &req, sizeof(req), 0) <= 0 )
|
||||
goto error;
|
||||
|
||||
/* Receive responses */
|
||||
for( dump_done = 0; !dump_done; )
|
||||
{
|
||||
if( (offlen = recv(fd, buf, sizeof(buf), 0)) <= 0 )
|
||||
goto error;
|
||||
|
||||
/* Parse message */
|
||||
for(nlmp = (struct nlmsghdr *)buf; offlen > sizeof(*nlmp);)
|
||||
{
|
||||
/* Dump finished? */
|
||||
if( nlmp->nlmsg_type == NLMSG_DONE )
|
||||
{
|
||||
dump_done = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
int len = nlmp->nlmsg_len;
|
||||
int req_len = len - sizeof(*nlmp);
|
||||
|
||||
if( req_len<0 || len>offlen )
|
||||
goto error;
|
||||
|
||||
if( !NLMSG_OK(nlmp, offlen) )
|
||||
goto error;
|
||||
|
||||
rtmp = (struct ifaddrmsg *) NLMSG_DATA(nlmp);
|
||||
rtatp = (struct rtattr *) IFA_RTA(rtmp);
|
||||
|
||||
if( !(entry = fwd_alloc_ptr(struct fwd_addr_list)) )
|
||||
goto error;
|
||||
|
||||
entry->index = rtmp->ifa_index;
|
||||
if_indextoname(rtmp->ifa_index, (char *)&entry->ifname);
|
||||
|
||||
rtattrlen = IFA_PAYLOAD(nlmp);
|
||||
|
||||
for( ; RTA_OK(rtatp, rtattrlen); rtatp = RTA_NEXT(rtatp, rtattrlen) )
|
||||
{
|
||||
if( rtatp->rta_type == IFA_ADDRESS )
|
||||
{
|
||||
memcpy(&entry->ipaddr, (char *) RTA_DATA(rtatp), rtatp->rta_len);
|
||||
entry->prefix = rtmp->ifa_prefixlen;
|
||||
entry->family = family;
|
||||
}
|
||||
else if( rtatp->rta_type == IFA_LABEL)
|
||||
{
|
||||
memcpy(&entry->label, (char *) RTA_DATA(rtatp), rtatp->rta_len);
|
||||
}
|
||||
}
|
||||
|
||||
entry->next = head;
|
||||
head = entry;
|
||||
|
||||
offlen -= NLMSG_ALIGN(len);
|
||||
nlmp = (struct nlmsghdr*)((char*)nlmp + NLMSG_ALIGN(len));
|
||||
}
|
||||
}
|
||||
|
||||
return head;
|
||||
|
||||
|
||||
error:
|
||||
|
||||
fwd_free_addrs(head);
|
||||
head = entry = NULL;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void fwd_free_addrs(struct fwd_addr_list *head)
|
||||
{
|
||||
struct fwd_addr_list *entry = head;
|
||||
|
||||
while( entry != NULL )
|
||||
{
|
||||
head = entry->next;
|
||||
free(entry);
|
||||
entry = head;
|
||||
}
|
||||
|
||||
head = entry = NULL;
|
||||
}
|
||||
|
||||
struct fwd_addr_list * fwd_append_addrs(struct fwd_addr_list *head, struct fwd_addr_list *add)
|
||||
{
|
||||
struct fwd_addr_list *entry = head;
|
||||
|
||||
while( entry->next != NULL )
|
||||
entry = entry->next;
|
||||
|
||||
return (entry->next = add);
|
||||
}
|
||||
|
52
contrib/fwd/src/fwd_addr.h
Normal file
52
contrib/fwd/src/fwd_addr.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* fwd - OpenWrt firewall daemon - header for rtnetlink communication
|
||||
*
|
||||
* Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org>
|
||||
*
|
||||
* The fwd program is free software: you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* The fwd program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with the fwd program. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#ifndef __FWD_ADDR_H__
|
||||
#define __FWD_ADDR_H__
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
|
||||
struct fwd_addr_list {
|
||||
char ifname[IFNAMSIZ];
|
||||
char label[IFNAMSIZ];
|
||||
int family;
|
||||
int index;
|
||||
unsigned int prefix;
|
||||
union {
|
||||
struct in_addr v4;
|
||||
struct in6_addr v6;
|
||||
} ipaddr;
|
||||
struct fwd_addr_list *next;
|
||||
};
|
||||
|
||||
|
||||
struct fwd_addr_list * fwd_get_addrs(int, int);
|
||||
struct fwd_addr_list * fwd_append_addrs(struct fwd_addr_list *, struct fwd_addr_list *);
|
||||
void fwd_free_addrs(struct fwd_addr_list *);
|
||||
|
||||
#define fwd_foreach_addrs(head, entry) for(entry = head; entry; entry = entry->next)
|
||||
|
||||
#endif
|
||||
|
870
contrib/fwd/src/fwd_config.c
Normal file
870
contrib/fwd/src/fwd_config.c
Normal file
|
@ -0,0 +1,870 @@
|
|||
/*
|
||||
* fwd - OpenWrt firewall daemon - config parsing
|
||||
*
|
||||
* Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org>
|
||||
*
|
||||
* The fwd program is free software: you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* The fwd program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with the fwd program. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
|
||||
#include "fwd.h"
|
||||
#include "fwd_addr.h"
|
||||
#include "fwd_config.h"
|
||||
|
||||
#include "ucix.h"
|
||||
|
||||
|
||||
#define fwd_read_error(...) do { \
|
||||
fprintf(stderr, "ERROR: "); \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
fprintf(stderr, "\n"); \
|
||||
return; \
|
||||
} while(0)
|
||||
|
||||
|
||||
/*
|
||||
* Parse helpers
|
||||
*/
|
||||
static int
|
||||
fwd_read_policy(struct uci_context *uci, const char *s, const char *o)
|
||||
{
|
||||
const char *val = ucix_get_option(uci, "firewall", s, o);
|
||||
|
||||
if( val != NULL )
|
||||
{
|
||||
switch( val[0] )
|
||||
{
|
||||
case 'D':
|
||||
case 'd':
|
||||
return FWD_P_DROP;
|
||||
|
||||
case 'R':
|
||||
case 'r':
|
||||
return FWD_P_REJECT;
|
||||
|
||||
case 'A':
|
||||
case 'a':
|
||||
return FWD_P_ACCEPT;
|
||||
}
|
||||
}
|
||||
|
||||
return FWD_P_UNSPEC;
|
||||
}
|
||||
|
||||
static int
|
||||
fwd_read_bool(struct uci_context *uci, const char *s, const char *o, int d)
|
||||
{
|
||||
const char *val = ucix_get_option(uci, "firewall", s, o);
|
||||
|
||||
if( val != NULL )
|
||||
{
|
||||
if( !strcmp(val, "yes") || !strcmp(val, "true") || !strcmp(val, "1") )
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
fwd_read_uint(struct uci_context *uci, const char *s, const char *o, unsigned int d)
|
||||
{
|
||||
const char *val = ucix_get_option(uci, "firewall", s, o);
|
||||
|
||||
if( val != NULL )
|
||||
{
|
||||
return atoi(val);
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
static int
|
||||
fwd_read_cidr(struct uci_context *uci, const char *s, const char *o, struct fwd_cidr **c)
|
||||
{
|
||||
const char *val = ucix_get_option(uci, "firewall", s, o);
|
||||
char ip[32], prefix[32];
|
||||
struct in_addr ina;
|
||||
|
||||
memset(ip, 0, 32);
|
||||
memset(prefix, 0, 32);
|
||||
|
||||
if( val == NULL )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if( (strlen(val) < 32) && (sscanf(val, "%[^/]/%s", ip, prefix) > 0) )
|
||||
{
|
||||
if( !(*c = fwd_alloc_ptr(struct fwd_cidr)) )
|
||||
goto inval;
|
||||
|
||||
if( inet_aton(ip, &ina) )
|
||||
{
|
||||
(*c)->addr.s_addr = ina.s_addr;
|
||||
|
||||
if( strchr(prefix, '.') )
|
||||
{
|
||||
if( inet_aton(prefix, &ina) )
|
||||
{
|
||||
(*c)->prefix = 32;
|
||||
ina.s_addr = ntohl(ina.s_addr);
|
||||
|
||||
while( !(ina.s_addr & 1) )
|
||||
{
|
||||
ina.s_addr >>= 1;
|
||||
(*c)->prefix--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
goto inval;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
(*c)->prefix = prefix[0] ? atoi(prefix) : 32;
|
||||
|
||||
if( ((*c)->prefix < 0) || ((*c)->prefix > 32) )
|
||||
{
|
||||
goto inval;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
inval:
|
||||
fwd_free_ptr(*c);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
fwd_read_mac(struct uci_context *uci, const char *s, const char *o, struct fwd_mac **m)
|
||||
{
|
||||
const char *val = ucix_get_option(uci, "firewall", s, o);
|
||||
|
||||
if( val == NULL )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( (*m = fwd_alloc_ptr(struct fwd_mac)) != NULL )
|
||||
{
|
||||
if( sscanf(val, "%2x:%2x:%2x:%2x:%2x:%2x",
|
||||
(unsigned int *)&(*m)->mac[0], (unsigned int *)&(*m)->mac[1],
|
||||
(unsigned int *)&(*m)->mac[2], (unsigned int *)&(*m)->mac[3],
|
||||
(unsigned int *)&(*m)->mac[4], (unsigned int *)&(*m)->mac[5]) == 6
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fwd_free_ptr(*m);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
fwd_read_portrange(struct uci_context *uci, const char *s, const char *o, struct fwd_portrange **p)
|
||||
{
|
||||
const char *val = ucix_get_option(uci, "firewall", s, o);
|
||||
int min = -1;
|
||||
int max = -1;
|
||||
unsigned int tmp;
|
||||
|
||||
if( val == NULL )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if( sscanf(val, "%u%*[:-]%u", &min, &max) > 0 )
|
||||
{
|
||||
if( max == -1 )
|
||||
{
|
||||
max = min;
|
||||
}
|
||||
else if( min > max )
|
||||
{
|
||||
tmp = max;
|
||||
max = min;
|
||||
min = tmp;
|
||||
}
|
||||
|
||||
if( (min >= 0) && (min <= 65535) && (max >= 0) && (max <= 65535) )
|
||||
{
|
||||
if( (*p = fwd_alloc_ptr(struct fwd_portrange)) != NULL )
|
||||
{
|
||||
(*p)->min = min;
|
||||
(*p)->max = max;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fwd_free_ptr(*p);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
fwd_read_proto(struct uci_context *uci, const char *s, const char *o, struct fwd_proto **p)
|
||||
{
|
||||
const char *val = ucix_get_option(uci, "firewall", s, o);
|
||||
int proto;
|
||||
|
||||
if( val == NULL )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( (*p = fwd_alloc_ptr(struct fwd_proto)) != NULL )
|
||||
{
|
||||
proto = atoi(val);
|
||||
|
||||
if( !strcasecmp(val, "all") )
|
||||
{
|
||||
(*p)->type = FWD_PR_ALL;
|
||||
(*p)->proto = 0;
|
||||
}
|
||||
else if( !strcasecmp(val, "icmp") )
|
||||
{
|
||||
(*p)->type = FWD_PR_ICMP;
|
||||
(*p)->proto = 0;
|
||||
}
|
||||
else if( !strcasecmp(val, "udp") )
|
||||
{
|
||||
(*p)->type = FWD_PR_UDP;
|
||||
(*p)->proto = 0;
|
||||
}
|
||||
else if( !strcasecmp(val, "tcp") )
|
||||
{
|
||||
(*p)->type = FWD_PR_TCP;
|
||||
(*p)->proto = 0;
|
||||
}
|
||||
else if( !strcasecmp(val, "tcpudp") )
|
||||
{
|
||||
(*p)->type = FWD_PR_TCPUDP;
|
||||
(*p)->proto = 0;
|
||||
}
|
||||
else if( proto > 0 )
|
||||
{
|
||||
(*p)->type = FWD_PR_CUSTOM;
|
||||
(*p)->proto = proto;
|
||||
}
|
||||
else
|
||||
{
|
||||
goto inval;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
inval:
|
||||
fwd_free_ptr(*p);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
fwd_read_icmptype(struct uci_context *uci, const char *s, const char *o, struct fwd_icmptype **i)
|
||||
{
|
||||
const char *val = ucix_get_option(uci, "firewall", s, o);
|
||||
unsigned int type, code;
|
||||
|
||||
if( val == NULL )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( (*i = fwd_alloc_ptr(struct fwd_icmptype)) != NULL )
|
||||
{
|
||||
if( sscanf(val, "%u/%u", &type, &code) == 2 )
|
||||
{
|
||||
if( (type > 255) || (code > 255) )
|
||||
goto inval;
|
||||
|
||||
(*i)->type = type;
|
||||
(*i)->code = code;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
else if( sscanf(val, "%u", &type) == 1 )
|
||||
{
|
||||
if( type > 255 )
|
||||
goto inval;
|
||||
|
||||
(*i)->type = type;
|
||||
(*i)->code = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* XXX: no validity check here but I do not want to
|
||||
duplicate libipt_icmp.c ... */
|
||||
else if( sscanf(val, "%31s", (*i)->name) == 1 )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inval:
|
||||
fwd_free_ptr(*i);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static const char *
|
||||
fwd_read_string(struct uci_context *uci, const char *s, const char *o)
|
||||
{
|
||||
return ucix_get_option(uci, "firewall", s, o);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
fwd_append_config(struct fwd_data *h, struct fwd_data *a)
|
||||
{
|
||||
while( h->next )
|
||||
h = h->next;
|
||||
|
||||
h->next = a;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* config defaults
|
||||
*/
|
||||
static void fwd_read_defaults_cb(
|
||||
struct uci_context *uci,
|
||||
const char *s, struct fwd_defaults *d
|
||||
) {
|
||||
d->input = fwd_read_policy(uci, s, "input");
|
||||
d->forward = fwd_read_policy(uci, s, "forward");
|
||||
d->output = fwd_read_policy(uci, s, "output");
|
||||
d->syn_flood = fwd_read_bool(uci, s, "syn_flood", 1);
|
||||
d->syn_rate = fwd_read_uint(uci, s, "syn_rate", 25);
|
||||
d->syn_burst = fwd_read_uint(uci, s, "syn_burst", 50);
|
||||
d->drop_invalid = fwd_read_bool(uci, s, "drop_invalid", 1);
|
||||
}
|
||||
|
||||
static struct fwd_data *
|
||||
fwd_read_defaults(struct uci_context *uci)
|
||||
{
|
||||
struct fwd_data *dt;
|
||||
struct fwd_defaults d;
|
||||
|
||||
if( (dt = fwd_alloc_ptr(struct fwd_data)) != NULL )
|
||||
{
|
||||
memset(&d, 0, sizeof(d));
|
||||
|
||||
ucix_for_each_section_type(uci, "firewall", "defaults",
|
||||
(void *)fwd_read_defaults_cb, &d);
|
||||
|
||||
memcpy(&dt->section.defaults, &d, sizeof(d));
|
||||
|
||||
dt->type = FWD_S_DEFAULTS;
|
||||
dt->next = NULL;
|
||||
|
||||
return dt;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* config zone
|
||||
*/
|
||||
static void fwd_read_zone_networks_cb(
|
||||
const char *net, struct fwd_network_list **np
|
||||
) {
|
||||
struct fwd_network_list *nn;
|
||||
|
||||
if( (nn = fwd_alloc_ptr(struct fwd_network_list)) != NULL )
|
||||
{
|
||||
nn->name = strdup(net);
|
||||
nn->next = *np;
|
||||
*np = nn;
|
||||
}
|
||||
}
|
||||
|
||||
static void fwd_read_zones_cb(
|
||||
struct uci_context *uci,
|
||||
const char *s, struct fwd_data_conveyor *cv
|
||||
) {
|
||||
struct fwd_data *dtn;
|
||||
struct fwd_network_list *net = NULL;
|
||||
const char *name;
|
||||
|
||||
if( !(name = fwd_read_string(uci, s, "name")) )
|
||||
fwd_read_error("section '%s' is missing 'name' option!", s);
|
||||
|
||||
if( (dtn = fwd_alloc_ptr(struct fwd_data)) != NULL )
|
||||
{
|
||||
dtn->section.zone.name = strdup(name);
|
||||
dtn->section.zone.masq = fwd_read_bool(uci, s, "masq", 0);
|
||||
dtn->section.zone.mtu_fix = fwd_read_bool(uci, s, "mtu_fix", 0);
|
||||
dtn->section.zone.conntrack = fwd_read_bool(uci, s, "conntrack", 0);
|
||||
|
||||
dtn->section.zone.input = fwd_read_policy(uci, s, "input")
|
||||
?: cv->head->section.defaults.input ?: FWD_P_DROP;
|
||||
|
||||
dtn->section.zone.forward = fwd_read_policy(uci, s, "forward")
|
||||
?: cv->head->section.defaults.forward ?: FWD_P_DROP;
|
||||
|
||||
dtn->section.zone.output = fwd_read_policy(uci, s, "output")
|
||||
?: cv->head->section.defaults.output ?: FWD_P_DROP;
|
||||
|
||||
/* try to parse option/list network ... */
|
||||
if( ucix_for_each_list(uci, "firewall", s, "network",
|
||||
(void *)&fwd_read_zone_networks_cb, &net) < 0 )
|
||||
{
|
||||
/* ... didn't work, fallback to option name */
|
||||
fwd_read_zone_networks_cb(name, &net);
|
||||
}
|
||||
|
||||
dtn->section.zone.networks = net;
|
||||
dtn->type = FWD_S_ZONE;
|
||||
dtn->next = cv->cursor;
|
||||
cv->cursor = dtn;
|
||||
}
|
||||
}
|
||||
|
||||
static struct fwd_data *
|
||||
fwd_read_zones(struct uci_context *uci, struct fwd_data *def)
|
||||
{
|
||||
struct fwd_data_conveyor cv;
|
||||
|
||||
cv.cursor = NULL;
|
||||
cv.head = def;
|
||||
|
||||
ucix_for_each_section_type(uci, "firewall", "zone",
|
||||
(void *)fwd_read_zones_cb, &cv);
|
||||
|
||||
return cv.cursor;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* config forwarding
|
||||
*/
|
||||
static void fwd_read_forwards_cb(
|
||||
struct uci_context *uci,
|
||||
const char *s, struct fwd_data_conveyor *cv
|
||||
) {
|
||||
const char *src, *dest;
|
||||
struct fwd_data *dtn;
|
||||
struct fwd_zone *zsrc = NULL;
|
||||
struct fwd_zone *zdest = NULL;
|
||||
|
||||
if( (src = fwd_read_string(uci, s, "src")) != NULL )
|
||||
{
|
||||
if( !(zsrc = fwd_lookup_zone(cv->head, src)) )
|
||||
fwd_read_error("section '%s' references unknown src zone '%s'!", s, src);
|
||||
}
|
||||
|
||||
if( (dest = fwd_read_string(uci, s, "dest")) != NULL )
|
||||
{
|
||||
if( !(zdest = fwd_lookup_zone(cv->head, dest)) )
|
||||
fwd_read_error("section '%s' references unknown dest zone '%s'!", s, dest);
|
||||
}
|
||||
|
||||
if( (dtn = fwd_alloc_ptr(struct fwd_data)) != NULL )
|
||||
{
|
||||
dtn->section.forwarding.src = zsrc;
|
||||
dtn->section.forwarding.dest = zdest;
|
||||
dtn->section.forwarding.mtu_fix = fwd_read_bool(uci, s, "mtu_fix", 0);
|
||||
dtn->section.forwarding.masq = fwd_read_bool(uci, s, "masq", 0);
|
||||
|
||||
dtn->type = FWD_S_FORWARD;
|
||||
dtn->next = cv->cursor;
|
||||
cv->cursor = dtn;
|
||||
}
|
||||
else
|
||||
{
|
||||
fwd_read_error("out of memory while parsing config!");
|
||||
}
|
||||
}
|
||||
|
||||
static struct fwd_data *
|
||||
fwd_read_forwards(struct uci_context *uci, struct fwd_data *zones)
|
||||
{
|
||||
struct fwd_data_conveyor cv;
|
||||
|
||||
cv.cursor = NULL;
|
||||
cv.head = zones;
|
||||
|
||||
ucix_for_each_section_type(uci, "firewall", "forwarding",
|
||||
(void *)fwd_read_forwards_cb, &cv);
|
||||
|
||||
return cv.cursor;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* config redirect
|
||||
*/
|
||||
static void fwd_read_redirects_cb(
|
||||
struct uci_context *uci,
|
||||
const char *s, struct fwd_data_conveyor *cv
|
||||
) {
|
||||
const char *src;
|
||||
struct fwd_data *dtn = NULL;
|
||||
struct fwd_zone *zsrc = NULL;
|
||||
|
||||
/* check zone */
|
||||
if( !(src = fwd_read_string(uci, s, "src")) )
|
||||
fwd_read_error(
|
||||
"section '%s' is missing 'src' option!",
|
||||
s
|
||||
);
|
||||
|
||||
else if( !(zsrc = fwd_lookup_zone(cv->head, src)) )
|
||||
fwd_read_error(
|
||||
"section '%s' references unknown src zone '%s'!",
|
||||
s, src
|
||||
);
|
||||
|
||||
/* uci context, section, name, type */
|
||||
fwd_check_option(uci, s, src_ip, cidr);
|
||||
fwd_check_option(uci, s, src_mac, mac);
|
||||
fwd_check_option(uci, s, src_port, portrange);
|
||||
fwd_check_option(uci, s, src_dport, portrange);
|
||||
fwd_check_option(uci, s, dest_ip, cidr);
|
||||
fwd_check_option(uci, s, dest_port, portrange);
|
||||
fwd_check_option(uci, s, proto, proto);
|
||||
|
||||
if( (dtn = fwd_alloc_ptr(struct fwd_data)) != NULL )
|
||||
{
|
||||
dtn->section.redirect.proto = proto;
|
||||
dtn->section.redirect.src = zsrc;
|
||||
dtn->section.redirect.src_ip = src_ip;
|
||||
dtn->section.redirect.src_mac = src_mac;
|
||||
dtn->section.redirect.src_port = src_port;
|
||||
dtn->section.redirect.src_dport = src_dport;
|
||||
dtn->section.redirect.dest_ip = dest_ip;
|
||||
dtn->section.redirect.dest_port = dest_port;
|
||||
|
||||
dtn->type = FWD_S_REDIRECT;
|
||||
dtn->next = cv->cursor;
|
||||
cv->cursor = dtn;
|
||||
}
|
||||
else
|
||||
{
|
||||
fwd_read_error("out of memory while parsing config!");
|
||||
}
|
||||
}
|
||||
|
||||
static struct fwd_data *
|
||||
fwd_read_redirects(struct uci_context *uci, struct fwd_data *zones)
|
||||
{
|
||||
struct fwd_data_conveyor cv;
|
||||
|
||||
cv.cursor = NULL;
|
||||
cv.head = zones;
|
||||
|
||||
ucix_for_each_section_type(uci, "firewall", "redirect",
|
||||
(void *)fwd_read_redirects_cb, &cv);
|
||||
|
||||
return cv.cursor;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* config rule
|
||||
*/
|
||||
static void fwd_read_rules_cb(
|
||||
struct uci_context *uci,
|
||||
const char *s, struct fwd_data_conveyor *cv
|
||||
) {
|
||||
const char *src, *dest;
|
||||
struct fwd_data *dtn = NULL;
|
||||
struct fwd_zone *zsrc = NULL;
|
||||
struct fwd_zone *zdest = NULL;
|
||||
|
||||
/* check zones */
|
||||
if( !(src = fwd_read_string(uci, s, "src")) )
|
||||
fwd_read_error(
|
||||
"section '%s' is missing 'src' option!",
|
||||
s
|
||||
);
|
||||
|
||||
else if( !(zsrc = fwd_lookup_zone(cv->head, src)) )
|
||||
fwd_read_error(
|
||||
"section '%s' references unknown src zone '%s'!",
|
||||
s, src
|
||||
);
|
||||
|
||||
if( (dest = fwd_read_string(uci, s, "dest")) != NULL )
|
||||
if( !(zdest = fwd_lookup_zone(cv->head, dest)) )
|
||||
fwd_read_error(
|
||||
"section '%s' references unknown dest zone '%s'!",
|
||||
s, dest
|
||||
);
|
||||
|
||||
/* uci context, section, name, type */
|
||||
fwd_check_option(uci, s, src_ip, cidr);
|
||||
fwd_check_option(uci, s, src_mac, mac);
|
||||
fwd_check_option(uci, s, src_port, portrange);
|
||||
fwd_check_option(uci, s, dest_ip, cidr);
|
||||
fwd_check_option(uci, s, dest_port, portrange);
|
||||
fwd_check_option(uci, s, proto, proto);
|
||||
fwd_check_option(uci, s, icmptype, icmptype);
|
||||
|
||||
if( (dtn = fwd_alloc_ptr(struct fwd_data)) != NULL )
|
||||
{
|
||||
dtn->section.rule.proto = proto;
|
||||
dtn->section.rule.icmp_type = icmptype;
|
||||
dtn->section.rule.src = zsrc;
|
||||
dtn->section.rule.src_ip = src_ip;
|
||||
dtn->section.rule.src_mac = src_mac;
|
||||
dtn->section.rule.src_port = src_port;
|
||||
dtn->section.rule.dest = zdest;
|
||||
dtn->section.rule.dest_ip = dest_ip;
|
||||
dtn->section.rule.dest_port = dest_port;
|
||||
dtn->section.rule.target = fwd_read_policy(uci, s, "target");
|
||||
|
||||
dtn->type = FWD_S_RULE;
|
||||
dtn->next = cv->cursor;
|
||||
cv->cursor = dtn;
|
||||
}
|
||||
else
|
||||
{
|
||||
fwd_read_error("out of memory while parsing config!");
|
||||
}
|
||||
}
|
||||
|
||||
static struct fwd_data *
|
||||
fwd_read_rules(struct uci_context *uci, struct fwd_data *zones)
|
||||
{
|
||||
struct fwd_data_conveyor cv;
|
||||
|
||||
cv.cursor = NULL;
|
||||
cv.head = zones;
|
||||
|
||||
ucix_for_each_section_type(uci, "firewall", "rule",
|
||||
(void *)fwd_read_rules_cb, &cv);
|
||||
|
||||
return cv.cursor;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* config include
|
||||
*/
|
||||
static void fwd_read_includes_cb(
|
||||
struct uci_context *uci,
|
||||
const char *s, struct fwd_data_conveyor *cv
|
||||
) {
|
||||
const char *path = fwd_read_string(uci, s, "path");
|
||||
struct fwd_data *dtn = NULL;
|
||||
|
||||
if( path != NULL )
|
||||
{
|
||||
if( (dtn = fwd_alloc_ptr(struct fwd_data)) != NULL )
|
||||
{
|
||||
dtn->section.include.path = strdup(path);
|
||||
|
||||
dtn->type = FWD_S_INCLUDE;
|
||||
dtn->next = cv->cursor;
|
||||
cv->cursor = dtn;
|
||||
}
|
||||
else
|
||||
{
|
||||
fwd_read_error("out of memory while parsing config!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static struct fwd_data *
|
||||
fwd_read_includes(struct uci_context *uci)
|
||||
{
|
||||
struct fwd_data_conveyor cv;
|
||||
|
||||
cv.cursor = NULL;
|
||||
cv.head = NULL;
|
||||
|
||||
ucix_for_each_section_type(uci, "firewall", "include",
|
||||
(void *)fwd_read_includes_cb, &cv);
|
||||
|
||||
return cv.cursor;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* config interface
|
||||
*/
|
||||
static void fwd_read_network_data(
|
||||
struct uci_context *uci, struct fwd_network_list *net
|
||||
) {
|
||||
struct fwd_network_list *e;
|
||||
const char *type, *ifname;
|
||||
|
||||
for( e = net; e; e = e->next )
|
||||
{
|
||||
if( (type = ucix_get_option(uci, "network", e->name, NULL)) != NULL )
|
||||
{
|
||||
if( !(ifname = ucix_get_option(uci, "network", e->name, "ifname")) )
|
||||
fwd_read_error(
|
||||
"section '%s' is missing 'ifname' option!",
|
||||
e->name
|
||||
);
|
||||
|
||||
e->isalias = (strcmp(type, "alias") ? 0 : 1);
|
||||
e->ifname = strdup(ifname);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void fwd_read_networks(
|
||||
struct uci_context *uci, struct fwd_data *zones
|
||||
) {
|
||||
struct fwd_data *e;
|
||||
|
||||
for( e = zones; e; e = e->next )
|
||||
if( e->type == FWD_S_ZONE )
|
||||
fwd_read_network_data(uci, e->section.zone.networks);
|
||||
}
|
||||
|
||||
static void fwd_free_networks(struct fwd_network_list *h)
|
||||
{
|
||||
struct fwd_network_list *e = h;
|
||||
|
||||
while( h != NULL )
|
||||
{
|
||||
e = h->next;
|
||||
|
||||
fwd_free_ptr(h->name);
|
||||
fwd_free_ptr(h->ifname);
|
||||
fwd_free_ptr(h->addr);
|
||||
|
||||
free(h);
|
||||
h = e;
|
||||
}
|
||||
|
||||
e = h = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct fwd_data * fwd_read_config(void)
|
||||
{
|
||||
struct uci_context *ctx;
|
||||
struct fwd_data *defaults, *zones;
|
||||
|
||||
if( (ctx = ucix_init("firewall")) != NULL )
|
||||
{
|
||||
if( !(defaults = fwd_read_defaults(ctx)) )
|
||||
goto error;
|
||||
|
||||
if( !(zones = fwd_read_zones(ctx, defaults)) )
|
||||
goto error;
|
||||
|
||||
fwd_append_config(defaults, zones);
|
||||
fwd_append_config(defaults, fwd_read_forwards(ctx, zones));
|
||||
fwd_append_config(defaults, fwd_read_redirects(ctx, zones));
|
||||
fwd_append_config(defaults, fwd_read_rules(ctx, zones));
|
||||
fwd_append_config(defaults, fwd_read_includes(ctx));
|
||||
|
||||
ucix_cleanup(ctx);
|
||||
|
||||
if( (ctx = ucix_init("network")) != NULL )
|
||||
{
|
||||
fwd_read_networks(ctx, zones);
|
||||
ucix_cleanup(ctx);
|
||||
|
||||
return defaults;
|
||||
}
|
||||
}
|
||||
|
||||
error:
|
||||
if( ctx ) ucix_cleanup(ctx);
|
||||
fwd_free_config(defaults);
|
||||
fwd_free_config(zones);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void fwd_free_config(struct fwd_data *h)
|
||||
{
|
||||
struct fwd_data *e = h;
|
||||
|
||||
while( h != NULL )
|
||||
{
|
||||
e = h->next;
|
||||
|
||||
switch(h->type)
|
||||
{
|
||||
case FWD_S_INCLUDE:
|
||||
fwd_free_ptr(h->section.include.path);
|
||||
break;
|
||||
|
||||
case FWD_S_ZONE:
|
||||
fwd_free_ptr(h->section.zone.name);
|
||||
fwd_free_networks(h->section.zone.networks);
|
||||
break;
|
||||
|
||||
case FWD_S_REDIRECT:
|
||||
fwd_free_ptr(h->section.redirect.src_ip);
|
||||
fwd_free_ptr(h->section.redirect.src_mac);
|
||||
fwd_free_ptr(h->section.redirect.src_port);
|
||||
fwd_free_ptr(h->section.redirect.src_dport);
|
||||
fwd_free_ptr(h->section.redirect.dest_ip);
|
||||
fwd_free_ptr(h->section.redirect.dest_port);
|
||||
fwd_free_ptr(h->section.redirect.proto);
|
||||
break;
|
||||
|
||||
case FWD_S_RULE:
|
||||
fwd_free_ptr(h->section.rule.src_ip);
|
||||
fwd_free_ptr(h->section.rule.src_mac);
|
||||
fwd_free_ptr(h->section.rule.src_port);
|
||||
fwd_free_ptr(h->section.rule.dest_ip);
|
||||
fwd_free_ptr(h->section.rule.dest_port);
|
||||
fwd_free_ptr(h->section.rule.proto);
|
||||
fwd_free_ptr(h->section.rule.icmp_type);
|
||||
break;
|
||||
|
||||
case FWD_S_DEFAULTS:
|
||||
case FWD_S_FORWARD:
|
||||
/* Make gcc happy */
|
||||
break;
|
||||
}
|
||||
|
||||
free(h);
|
||||
h = e;
|
||||
}
|
||||
|
||||
e = h = NULL;
|
||||
}
|
||||
|
||||
|
||||
struct fwd_zone *
|
||||
fwd_lookup_zone(struct fwd_data *h, const char *n)
|
||||
{
|
||||
struct fwd_data *e;
|
||||
|
||||
if( n != NULL )
|
||||
{
|
||||
for( e = h; e; e = e->next )
|
||||
{
|
||||
if( (e->type = FWD_S_ZONE) && !strcmp(e->section.zone.name, n) )
|
||||
return &e->section.zone;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
29
contrib/fwd/src/fwd_config.h
Normal file
29
contrib/fwd/src/fwd_config.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
#ifndef __FWD_CONFIG_H__
|
||||
#define __FWD_CONFIG_H__
|
||||
|
||||
#include "fwd.h"
|
||||
#include "ucix.h"
|
||||
|
||||
/* fwd_check_option(uci_ctx, section, name, type) */
|
||||
#define fwd_check_option(uci, sct, name, type) \
|
||||
struct fwd_##type *name = NULL; \
|
||||
if( fwd_read_##type(uci, sct, #name, &name) ) \
|
||||
{ \
|
||||
printf("ERROR: section '%s' contains invalid %s in '%s'!\n", \
|
||||
sct, #type, #name); \
|
||||
return; \
|
||||
}
|
||||
|
||||
/* structure to access fwd_data* in uci iter callbacks */
|
||||
struct fwd_data_conveyor {
|
||||
struct fwd_data *head;
|
||||
struct fwd_data *cursor;
|
||||
};
|
||||
|
||||
/* api */
|
||||
struct fwd_data * fwd_read_config(void);
|
||||
struct fwd_zone * fwd_lookup_zone(struct fwd_data *, const char *);
|
||||
|
||||
void fwd_free_config(struct fwd_data *);
|
||||
|
||||
#endif
|
517
contrib/fwd/src/fwd_rules.c
Normal file
517
contrib/fwd/src/fwd_rules.c
Normal file
|
@ -0,0 +1,517 @@
|
|||
/*
|
||||
* fwd - OpenWrt firewall daemon - iptables rule set
|
||||
*
|
||||
* Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org>
|
||||
*
|
||||
* The fwd program is free software: you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* The fwd program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with the fwd program. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
|
||||
#include "fwd.h"
|
||||
#include "fwd_addr.h"
|
||||
#include "fwd_rules.h"
|
||||
|
||||
static void
|
||||
fwd_ipt_rule_append(struct fwd_ipt_rulebuf *r, const char *fmt, ...)
|
||||
{
|
||||
int len = 0;
|
||||
char buf[256]; buf[0] = 0;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
len = vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if( len > 0 )
|
||||
{
|
||||
r->buf = realloc(r->buf, r->len + len + 1);
|
||||
memcpy(&r->buf[r->len], buf, len);
|
||||
r->buf[r->len + len] = 0;
|
||||
r->len += len;
|
||||
}
|
||||
}
|
||||
|
||||
static struct fwd_ipt_rulebuf * fwd_ipt_init(const char *table)
|
||||
{
|
||||
struct fwd_ipt_rulebuf *r;
|
||||
|
||||
if( (r = fwd_alloc_ptr(struct fwd_ipt_rulebuf)) != NULL )
|
||||
{
|
||||
fwd_ipt_rule_append(r, IPT " -t %s", table);
|
||||
return r;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void fwd_ipt_add_srcport(
|
||||
struct fwd_ipt_rulebuf *r, struct fwd_portrange *p
|
||||
) {
|
||||
if( p != NULL )
|
||||
{
|
||||
if( p->min < p->max )
|
||||
fwd_ipt_rule_append(r, " --sport %u:%u", p->min, p->max);
|
||||
else
|
||||
fwd_ipt_rule_append(r, " --sport %u", p->min);
|
||||
}
|
||||
}
|
||||
|
||||
static void fwd_ipt_add_destport(
|
||||
struct fwd_ipt_rulebuf *r, struct fwd_portrange *p
|
||||
) {
|
||||
if( p != NULL )
|
||||
{
|
||||
if( p->min < p->max )
|
||||
fwd_ipt_rule_append(r, " --dport %u:%u", p->min, p->max);
|
||||
else
|
||||
fwd_ipt_rule_append(r, " --dport %u", p->min);
|
||||
}
|
||||
}
|
||||
|
||||
static void fwd_ipt_add_proto(
|
||||
struct fwd_ipt_rulebuf *r, struct fwd_proto *p
|
||||
) {
|
||||
if( p != NULL )
|
||||
{
|
||||
switch( p->type )
|
||||
{
|
||||
case FWD_PR_TCPUDP:
|
||||
fwd_ipt_rule_append(r, " -p tcp -p udp");
|
||||
break;
|
||||
|
||||
case FWD_PR_TCP:
|
||||
fwd_ipt_rule_append(r, " -p tcp");
|
||||
break;
|
||||
|
||||
case FWD_PR_UDP:
|
||||
fwd_ipt_rule_append(r, " -p udp");
|
||||
break;
|
||||
|
||||
case FWD_PR_ICMP:
|
||||
fwd_ipt_rule_append(r, " -p icmp");
|
||||
break;
|
||||
|
||||
case FWD_PR_ALL:
|
||||
fwd_ipt_rule_append(r, " -p all");
|
||||
break;
|
||||
|
||||
case FWD_PR_CUSTOM:
|
||||
fwd_ipt_rule_append(r, " -p %u", p->proto);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void fwd_ipt_add_srcaddr(
|
||||
struct fwd_ipt_rulebuf *r, struct fwd_cidr *c
|
||||
) {
|
||||
if( c != NULL )
|
||||
{
|
||||
if( c->prefix < 32 )
|
||||
fwd_ipt_rule_append(r, " -s %s/%u",
|
||||
inet_ntoa(c->addr), c->prefix);
|
||||
else
|
||||
fwd_ipt_rule_append(r, " -s %s", inet_ntoa(c->addr));
|
||||
}
|
||||
}
|
||||
|
||||
static void fwd_ipt_add_destaddr(
|
||||
struct fwd_ipt_rulebuf *r, struct fwd_cidr *c
|
||||
) {
|
||||
if( c != NULL )
|
||||
{
|
||||
if( c->prefix < 32 )
|
||||
fwd_ipt_rule_append(r, " -d %s/%u",
|
||||
inet_ntoa(c->addr), c->prefix);
|
||||
else
|
||||
fwd_ipt_rule_append(r, " -d %s", inet_ntoa(c->addr));
|
||||
}
|
||||
}
|
||||
|
||||
static void fwd_ipt_add_srcmac(
|
||||
struct fwd_ipt_rulebuf *r, struct fwd_mac *m
|
||||
) {
|
||||
if( m != NULL )
|
||||
{
|
||||
fwd_ipt_rule_append(r,
|
||||
" -m mac --mac-source %02x:%02x:%02x:%02x:%02x:%02x",
|
||||
m->mac[0], m->mac[1], m->mac[2],
|
||||
m->mac[3], m->mac[4], m->mac[5]);
|
||||
}
|
||||
}
|
||||
|
||||
static void fwd_ipt_add_icmptype(
|
||||
struct fwd_ipt_rulebuf *r, struct fwd_icmptype *i
|
||||
) {
|
||||
if( i != NULL )
|
||||
{
|
||||
if( i->name )
|
||||
fwd_ipt_rule_append(r, " --icmp-type %s", i->name);
|
||||
else if( i->code > -1 )
|
||||
fwd_ipt_rule_append(r, " --icmp-type %u/%u", i->type, i->code);
|
||||
else
|
||||
fwd_ipt_rule_append(r, " --icmp-type %u", i->type);
|
||||
}
|
||||
}
|
||||
|
||||
static void fwd_ipt_add_dnat_target(
|
||||
struct fwd_ipt_rulebuf *r, struct fwd_cidr *c, struct fwd_portrange *p
|
||||
) {
|
||||
if( c != NULL )
|
||||
{
|
||||
fwd_ipt_rule_append(r, " -j DNAT --to-destination %s",
|
||||
inet_ntoa(c->addr));
|
||||
|
||||
if( (p != NULL) && (p->min < p->max) )
|
||||
fwd_ipt_rule_append(r, ":%u-%u", p->min, p->max);
|
||||
else if( p != NULL )
|
||||
fwd_ipt_rule_append(r, ":%u", p->min);
|
||||
}
|
||||
}
|
||||
|
||||
static void fwd_ipt_exec(struct fwd_ipt_rulebuf *r)
|
||||
{
|
||||
if( r->len )
|
||||
printf("%s\n", r->buf);
|
||||
|
||||
fwd_free_ptr(r->buf);
|
||||
fwd_free_ptr(r);
|
||||
}
|
||||
|
||||
static const char * fwd_str_policy(enum fwd_policy pol)
|
||||
{
|
||||
return (pol == FWD_P_ACCEPT ? "ACCEPT" : "DROP");
|
||||
}
|
||||
|
||||
static const char * fwd_str_target(enum fwd_policy pol)
|
||||
{
|
||||
switch(pol)
|
||||
{
|
||||
case FWD_P_ACCEPT:
|
||||
return "ACCEPT";
|
||||
|
||||
case FWD_P_REJECT:
|
||||
return "REJECT";
|
||||
|
||||
default:
|
||||
return "DROP";
|
||||
}
|
||||
|
||||
return "DROP";
|
||||
}
|
||||
|
||||
|
||||
static void fwd_ipt_defaults_create(struct fwd_data *d)
|
||||
{
|
||||
struct fwd_defaults *def = &d->section.defaults;
|
||||
|
||||
/* policies */
|
||||
fwd_ipt_exec_format("filter", " -P INPUT %s", fwd_str_policy(def->input));
|
||||
fwd_ipt_exec_format("filter", " -P OUTPUT %s", fwd_str_policy(def->output));
|
||||
fwd_ipt_exec_format("filter", " -P FORWARD %s", fwd_str_policy(def->forward));
|
||||
|
||||
/* invalid state drop */
|
||||
if( def->drop_invalid )
|
||||
{
|
||||
fwd_ipt_exec_format("filter", " -A INPUT --state INVALID -j DROP");
|
||||
fwd_ipt_exec_format("filter", " -A OUTPUT --state INVALID -j DROP");
|
||||
fwd_ipt_exec_format("filter", " -A FORWARD --state INVALID -j DROP");
|
||||
}
|
||||
|
||||
/* default accept related */
|
||||
fwd_ipt_exec_format("filter", " -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT");
|
||||
fwd_ipt_exec_format("filter", " -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT");
|
||||
fwd_ipt_exec_format("filter", " -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT");
|
||||
|
||||
/* default accept on lo */
|
||||
fwd_ipt_exec_format("filter", " -A INPUT -i lo -j ACCEPT");
|
||||
fwd_ipt_exec_format("filter", " -A OUTPUT -o lo -j ACCEPT");
|
||||
|
||||
/* syn flood protection */
|
||||
if( def->syn_flood )
|
||||
{
|
||||
fwd_ipt_exec_format("filter", " -N syn_flood");
|
||||
|
||||
fwd_ipt_exec_format("filter",
|
||||
" -A syn_flood -p tcp --syn -m limit --limit %i/second"
|
||||
" --limit-burst %i -j RETURN",
|
||||
def->syn_rate, def->syn_burst);
|
||||
|
||||
fwd_ipt_exec_format("filter", " -A syn_flood -j DROP");
|
||||
fwd_ipt_exec_format("filter", " -A INPUT -p tcp --syn -j syn_flood");
|
||||
}
|
||||
|
||||
/* standard input/output/forward chain */
|
||||
fwd_ipt_exec_format("filter", " -N input");
|
||||
fwd_ipt_exec_format("filter", " -N output");
|
||||
fwd_ipt_exec_format("filter", " -N forward");
|
||||
fwd_ipt_exec_format("filter", " -A INPUT -j input");
|
||||
fwd_ipt_exec_format("filter", " -A OUTPUT -j output");
|
||||
fwd_ipt_exec_format("filter", " -A FORWARD -j forward");
|
||||
|
||||
/* standard reject chain */
|
||||
fwd_ipt_exec_format("filter", " -N reject");
|
||||
fwd_ipt_exec_format("filter", " -A reject -p tcp -j REJECT --reject-with tcp-reset");
|
||||
fwd_ipt_exec_format("filter", " -A reject -j REJECT --reject-with icmp-port-unreachable");
|
||||
}
|
||||
|
||||
static void fwd_ipt_zone_create(struct fwd_data *d)
|
||||
{
|
||||
struct fwd_zone *z = &d->section.zone;
|
||||
|
||||
if( !strcmp(z->name, "loopback") )
|
||||
return;
|
||||
|
||||
fwd_ipt_exec_format("filter", " -N zone_%s", z->name);
|
||||
fwd_ipt_exec_format("filter", " -N zone_%s_forward", z->name);
|
||||
fwd_ipt_exec_format("filter", " -N zone_%s_ACCEPT", z->name);
|
||||
fwd_ipt_exec_format("filter", " -N zone_%s_REJECT", z->name);
|
||||
fwd_ipt_exec_format("filter", " -N zone_%s_DROP", z->name);
|
||||
fwd_ipt_exec_format("filter", " -N zone_%s_MSSFIX", z->name);
|
||||
|
||||
if( z->forward != FWD_P_UNSPEC )
|
||||
fwd_ipt_exec_format("filter", " -A zone_%s_forward -j zone_%s_%s",
|
||||
z->name, z->name, fwd_str_target(z->forward));
|
||||
|
||||
if( z->input != FWD_P_UNSPEC )
|
||||
fwd_ipt_exec_format("filter", " -A zone_%s -j zone_%s_%s",
|
||||
z->name, z->name, fwd_str_target(z->input));
|
||||
|
||||
if( z->output != FWD_P_UNSPEC )
|
||||
fwd_ipt_exec_format("filter", " -A output -j zone_%s_%s",
|
||||
z->name, fwd_str_target(z->output));
|
||||
|
||||
fwd_ipt_exec_format("nat", " -N zone_%s_nat", z->name);
|
||||
fwd_ipt_exec_format("nat", " -N zone_%s_prerouting", z->name);
|
||||
fwd_ipt_exec_format("raw", " -N zone_%s_notrack", z->name);
|
||||
|
||||
if( z->masq )
|
||||
fwd_ipt_exec_format("nat", " -A POSTROUTING -j zone_%s_nat",
|
||||
z->name);
|
||||
|
||||
if( z->mtu_fix )
|
||||
fwd_ipt_exec_format("filter", " -A FORWARD -j zone_%s_MSSFIX",
|
||||
z->name);
|
||||
}
|
||||
|
||||
static void fwd_ipt_forwarding_create(struct fwd_data *d)
|
||||
{
|
||||
struct fwd_forwarding *f = &d->section.forwarding;
|
||||
struct fwd_ipt_rulebuf *b;
|
||||
|
||||
b = fwd_ipt_init("filter");
|
||||
|
||||
if( f->src )
|
||||
fwd_ipt_add_format(b, " -I zone_%s_forward 1", f->src->name);
|
||||
else
|
||||
fwd_ipt_add_format(b, " -I forward 1");
|
||||
|
||||
if( f->dest )
|
||||
fwd_ipt_add_format(b, " -j zone_%s_ACCEPT", f->dest->name);
|
||||
else
|
||||
fwd_ipt_add_format(b, " -j ACCEPT");
|
||||
|
||||
fwd_ipt_exec(b);
|
||||
}
|
||||
|
||||
static void fwd_ipt_redirect_create(struct fwd_data *d)
|
||||
{
|
||||
struct fwd_redirect *r = &d->section.redirect;
|
||||
struct fwd_ipt_rulebuf *b;
|
||||
|
||||
b = fwd_ipt_init("nat");
|
||||
fwd_ipt_add_format(b, " -A zone_%s_prerouting", r->src->name);
|
||||
fwd_ipt_add_proto(b, r->proto);
|
||||
fwd_ipt_add_srcaddr(b, r->src_ip);
|
||||
fwd_ipt_add_srcport(b, r->src_port);
|
||||
fwd_ipt_add_destport(b, r->src_dport);
|
||||
fwd_ipt_add_srcmac(b, r->src_mac);
|
||||
fwd_ipt_add_dnat_target(b, r->dest_ip, r->dest_port);
|
||||
fwd_ipt_exec(b);
|
||||
|
||||
b = fwd_ipt_init("nat");
|
||||
fwd_ipt_add_format(b, " -I zone_%s_forward 1", r->src->name);
|
||||
fwd_ipt_add_proto(b, r->proto);
|
||||
fwd_ipt_add_srcmac(b, r->src_mac);
|
||||
fwd_ipt_add_srcaddr(b, r->src_ip);
|
||||
fwd_ipt_add_srcport(b, r->src_port);
|
||||
fwd_ipt_add_destaddr(b, r->dest_ip);
|
||||
fwd_ipt_add_destport(b, r->dest_port);
|
||||
fwd_ipt_add_format(b, " -j ACCEPT");
|
||||
fwd_ipt_exec(b);
|
||||
}
|
||||
|
||||
static void fwd_ipt_rule_create(struct fwd_data *d)
|
||||
{
|
||||
struct fwd_rule *r = &d->section.rule;
|
||||
struct fwd_ipt_rulebuf *b;
|
||||
|
||||
b = fwd_ipt_init("filter");
|
||||
|
||||
if( r->dest )
|
||||
fwd_ipt_add_format(b, " -A zone_%s_forward", r->src->name);
|
||||
else
|
||||
fwd_ipt_add_format(b, " -A zone_%s", r->src->name);
|
||||
|
||||
fwd_ipt_add_proto(b, r->proto);
|
||||
fwd_ipt_add_icmptype(b, r->icmp_type);
|
||||
fwd_ipt_add_srcmac(b, r->src_mac);
|
||||
fwd_ipt_add_srcaddr(b, r->src_ip);
|
||||
fwd_ipt_add_srcport(b, r->src_port);
|
||||
fwd_ipt_add_destaddr(b, r->dest_ip);
|
||||
fwd_ipt_add_destport(b, r->dest_port);
|
||||
|
||||
if( r->dest )
|
||||
fwd_ipt_add_format(b, " -j zone_%s_%s",
|
||||
r->dest->name, fwd_str_target(r->target));
|
||||
else
|
||||
fwd_ipt_add_format(b, " -j %s", fwd_str_target(r->target));
|
||||
|
||||
fwd_ipt_exec(b);
|
||||
}
|
||||
|
||||
|
||||
static struct fwd_network_list *
|
||||
fwd_lookup_network(struct fwd_network_list *n, const char *net)
|
||||
{
|
||||
struct fwd_network_list *e;
|
||||
|
||||
if( n != NULL )
|
||||
for( e = n; e; e = e->next )
|
||||
if( !strcmp(e->name, net) )
|
||||
return e;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct fwd_addr_list *
|
||||
fwd_lookup_addr(struct fwd_addr_list *a, const char *ifname)
|
||||
{
|
||||
struct fwd_addr_list *e;
|
||||
|
||||
if( a != NULL )
|
||||
for( e = a; e; e = e->next )
|
||||
if( !strcmp(e->ifname, ifname) )
|
||||
return e;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void fwd_ipt_build_ruleset(struct fwd_handle *h)
|
||||
{
|
||||
struct fwd_data *e;
|
||||
|
||||
for( e = h->conf; e; e = e->next )
|
||||
{
|
||||
switch(e->type)
|
||||
{
|
||||
case FWD_S_DEFAULTS:
|
||||
printf("\n## DEFAULTS\n");
|
||||
fwd_ipt_defaults_create(e);
|
||||
break;
|
||||
|
||||
case FWD_S_ZONE:
|
||||
printf("\n## ZONE %s\n", e->section.zone.name);
|
||||
fwd_ipt_zone_create(e);
|
||||
break;
|
||||
|
||||
case FWD_S_FORWARD:
|
||||
printf("\n## FORWARD %s -> %s\n",
|
||||
e->section.forwarding.src
|
||||
? e->section.forwarding.src->name : "(all)",
|
||||
e->section.forwarding.dest
|
||||
? e->section.forwarding.dest->name : "(all)");
|
||||
fwd_ipt_forwarding_create(e);
|
||||
break;
|
||||
|
||||
case FWD_S_REDIRECT:
|
||||
printf("\n## REDIRECT %s\n", e->section.forwarding.src->name);
|
||||
fwd_ipt_redirect_create(e);
|
||||
break;
|
||||
|
||||
case FWD_S_RULE:
|
||||
printf("\n## RULE %s\n", e->section.rule.src->name);
|
||||
fwd_ipt_rule_create(e);
|
||||
break;
|
||||
|
||||
case FWD_S_INCLUDE:
|
||||
printf("\n## INCLUDE %s\n", e->section.include.path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void fwd_ipt_addif(struct fwd_handle *h, const char *net)
|
||||
{
|
||||
struct fwd_data *e;
|
||||
struct fwd_zone *z;
|
||||
struct fwd_addr_list *a;
|
||||
struct fwd_network_list *n;
|
||||
|
||||
for( e = h->conf; e; e = e->next )
|
||||
{
|
||||
if( (e->type != FWD_S_ZONE) ||
|
||||
!(n = fwd_lookup_network(e->section.zone.networks, net)) ||
|
||||
!(a = fwd_lookup_addr(h->addrs, n->ifname)) )
|
||||
continue;
|
||||
|
||||
z = &e->section.zone;
|
||||
|
||||
printf("\n## NETWORK %s (%s - %s/%u)\n",
|
||||
n->name, n->ifname,
|
||||
inet_ntoa(a->ipaddr.v4), a->prefix
|
||||
);
|
||||
|
||||
fwd_ipt_exec_format("filter", " -A input -i %s -j zone_%s",
|
||||
n->ifname, z->name);
|
||||
|
||||
fwd_ipt_exec_format("filter",
|
||||
" -I zone_%s_MSSFIX 1 -o %s -p tcp --tcp-flags SYN,RST SYN"
|
||||
" -j TCPMSS --clamp-mss-to-pmtu",
|
||||
z->name, n->ifname);
|
||||
|
||||
fwd_ipt_exec_format("filter", " -I zone_%s_ACCEPT 1 -o %s -j ACCEPT",
|
||||
z->name, n->ifname);
|
||||
|
||||
fwd_ipt_exec_format("filter", " -I zone_%s_DROP 1 -o %s -j DROP",
|
||||
z->name, n->ifname);
|
||||
|
||||
fwd_ipt_exec_format("filter", " -I zone_%s_REJECT 1 -o %s -j reject",
|
||||
z->name, n->ifname);
|
||||
|
||||
fwd_ipt_exec_format("filter", " -I zone_%s_ACCEPT 1 -i %s -j ACCEPT",
|
||||
z->name, n->ifname);
|
||||
|
||||
fwd_ipt_exec_format("filter", " -I zone_%s_DROP 1 -i %s -j DROP",
|
||||
z->name, n->ifname);
|
||||
|
||||
fwd_ipt_exec_format("filter", " -I zone_%s_REJECT 1 -i %s -j reject",
|
||||
z->name, n->ifname);
|
||||
|
||||
fwd_ipt_exec_format("filter",
|
||||
" -I zone_%s_nat 1 -t nat -o %s -j MASQUERADE",
|
||||
z->name, n->ifname);
|
||||
|
||||
fwd_ipt_exec_format("filter",
|
||||
" -I PREROUTING 1 -t nat -i %s -j zone_%s_prerouting",
|
||||
n->ifname, z->name);
|
||||
|
||||
fwd_ipt_exec_format("filter", " -A forward -i %s -j zone_%s_forward",
|
||||
n->ifname, z->name);
|
||||
|
||||
fwd_ipt_exec_format("raw", " -I PREROUTING 1 -i %s -j zone_%s_notrack",
|
||||
n->ifname, z->name);
|
||||
}
|
||||
}
|
||||
|
44
contrib/fwd/src/fwd_rules.h
Normal file
44
contrib/fwd/src/fwd_rules.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* fwd - OpenWrt firewall daemon - header for iptables rule set
|
||||
*
|
||||
* Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org>
|
||||
*
|
||||
* The fwd program is free software: you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* The fwd program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with the fwd program. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#ifndef __FWD_RULES_H__
|
||||
#define __FWD_RULES_H__
|
||||
|
||||
#include "fwd.h"
|
||||
|
||||
#define IPT "iptables"
|
||||
|
||||
struct fwd_ipt_rulebuf {
|
||||
char *buf;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
|
||||
#define fwd_ipt_add_format fwd_ipt_rule_append
|
||||
|
||||
#define fwd_ipt_exec_format(t, ...) do { \
|
||||
struct fwd_ipt_rulebuf *r = fwd_ipt_init(t); \
|
||||
fwd_ipt_add_format(r, __VA_ARGS__); \
|
||||
fwd_ipt_exec(r); \
|
||||
} while(0)
|
||||
|
||||
void fwd_ipt_build_ruleset(struct fwd_handle *h);
|
||||
void fwd_ipt_addif(struct fwd_handle *h, const char *net);
|
||||
|
||||
#endif
|
||||
|
236
contrib/fwd/src/ucix.c
Normal file
236
contrib/fwd/src/ucix.c
Normal file
|
@ -0,0 +1,236 @@
|
|||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Copyright (C) 2008 John Crispin <blogic@openwrt.org>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <uci_config.h>
|
||||
#include <uci.h>
|
||||
#include "ucix.h"
|
||||
|
||||
static struct uci_ptr ptr;
|
||||
|
||||
static inline int ucix_get_ptr(struct uci_context *ctx, const char *p, const char *s, const char *o, const char *t)
|
||||
{
|
||||
memset(&ptr, 0, sizeof(ptr));
|
||||
ptr.package = p;
|
||||
ptr.section = s;
|
||||
ptr.option = o;
|
||||
ptr.value = t;
|
||||
return uci_lookup_ptr(ctx, &ptr, NULL, true);
|
||||
}
|
||||
|
||||
struct uci_context* ucix_init(const char *config_file)
|
||||
{
|
||||
struct uci_context *ctx = uci_alloc_context();
|
||||
uci_add_history_path(ctx, "/var/state");
|
||||
if(uci_load(ctx, config_file, NULL) != UCI_OK)
|
||||
{
|
||||
printf("%s/%s is missing or corrupt\n", ctx->savedir, config_file);
|
||||
return NULL;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
struct uci_context* ucix_init_path(const char *path, const char *config_file)
|
||||
{
|
||||
struct uci_context *ctx = uci_alloc_context();
|
||||
if(path)
|
||||
uci_set_confdir(ctx, path);
|
||||
if(uci_load(ctx, config_file, NULL) != UCI_OK)
|
||||
{
|
||||
printf("%s/%s is missing or corrupt\n", ctx->savedir, config_file);
|
||||
return NULL;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
int ucix_load(struct uci_context *ctx, const char *config_file)
|
||||
{
|
||||
if(uci_load(ctx, config_file, NULL) != UCI_OK)
|
||||
{
|
||||
printf("%s/%s is missing or corrupt\n", ctx->savedir, config_file);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ucix_cleanup(struct uci_context *ctx)
|
||||
{
|
||||
uci_free_context(ctx);
|
||||
}
|
||||
|
||||
void ucix_save(struct uci_context *ctx)
|
||||
{
|
||||
uci_set_savedir(ctx, "/tmp/.uci/");
|
||||
uci_save(ctx, NULL);
|
||||
}
|
||||
|
||||
void ucix_save_state(struct uci_context *ctx)
|
||||
{
|
||||
uci_set_savedir(ctx, "/var/state/");
|
||||
uci_save(ctx, NULL);
|
||||
}
|
||||
|
||||
const char* ucix_get_option(struct uci_context *ctx, const char *p, const char *s, const char *o)
|
||||
{
|
||||
struct uci_element *e = NULL;
|
||||
const char *value = NULL;
|
||||
if(ucix_get_ptr(ctx, p, s, o, NULL))
|
||||
return NULL;
|
||||
if (!(ptr.flags & UCI_LOOKUP_COMPLETE))
|
||||
return NULL;
|
||||
e = ptr.last;
|
||||
switch (e->type)
|
||||
{
|
||||
case UCI_TYPE_SECTION:
|
||||
value = uci_to_section(e)->type;
|
||||
break;
|
||||
|
||||
case UCI_TYPE_OPTION:
|
||||
switch(ptr.o->type) {
|
||||
case UCI_TYPE_STRING:
|
||||
value = ptr.o->v.string;
|
||||
break;
|
||||
default:
|
||||
value = NULL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
int ucix_for_each_list(
|
||||
struct uci_context *ctx, const char *p, const char *s, const char *o,
|
||||
void (*cb)(const char*, void*), void *priv)
|
||||
{
|
||||
struct uci_element *e = NULL;
|
||||
char *value = NULL;
|
||||
int count = 0;
|
||||
if(ucix_get_ptr(ctx, p, s, o, NULL))
|
||||
return -1;
|
||||
if (!(ptr.flags & UCI_LOOKUP_COMPLETE))
|
||||
return -1;
|
||||
e = ptr.last;
|
||||
if(e->type == UCI_TYPE_OPTION)
|
||||
{
|
||||
switch(ptr.o->type)
|
||||
{
|
||||
case UCI_TYPE_LIST:
|
||||
uci_foreach_element(&ptr.o->v.list, e) {
|
||||
cb(e->name, priv);
|
||||
count++;
|
||||
}
|
||||
break;
|
||||
|
||||
case UCI_TYPE_STRING:
|
||||
if( (value = strdup(ptr.o->v.string)) != NULL )
|
||||
{
|
||||
char *ts, *tt, *tp;
|
||||
for( ts = value; 1; ts = NULL )
|
||||
{
|
||||
if( (tt = strtok_r(ts, " \t", &tp)) != NULL )
|
||||
{
|
||||
cb(tt, priv);
|
||||
count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ucix_get_option_int(struct uci_context *ctx, const char *p, const char *s, const char *o, int def)
|
||||
{
|
||||
const char *tmp = ucix_get_option(ctx, p, s, o);
|
||||
int ret = def;
|
||||
|
||||
if (tmp)
|
||||
ret = atoi(tmp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ucix_add_section(struct uci_context *ctx, const char *p, const char *s, const char *t)
|
||||
{
|
||||
if(ucix_get_ptr(ctx, p, s, NULL, t))
|
||||
return;
|
||||
uci_set(ctx, &ptr);
|
||||
}
|
||||
|
||||
void ucix_add_option(struct uci_context *ctx, const char *p, const char *s, const char *o, const char *t)
|
||||
{
|
||||
if(ucix_get_ptr(ctx, p, s, o, (t)?(t):("")))
|
||||
return;
|
||||
uci_set(ctx, &ptr);
|
||||
}
|
||||
|
||||
void ucix_add_option_int(struct uci_context *ctx, const char *p, const char *s, const char *o, int t)
|
||||
{
|
||||
char tmp[64];
|
||||
snprintf(tmp, 64, "%d", t);
|
||||
ucix_add_option(ctx, p, s, o, tmp);
|
||||
}
|
||||
|
||||
void ucix_del(struct uci_context *ctx, const char *p, const char *s, const char *o)
|
||||
{
|
||||
if(!ucix_get_ptr(ctx, p, s, o, NULL))
|
||||
uci_delete(ctx, &ptr);
|
||||
}
|
||||
|
||||
void ucix_revert(struct uci_context *ctx, const char *p, const char *s, const char *o)
|
||||
{
|
||||
if(!ucix_get_ptr(ctx, p, s, o, NULL))
|
||||
uci_revert(ctx, &ptr);
|
||||
}
|
||||
|
||||
void ucix_for_each_section_type(struct uci_context *ctx,
|
||||
const char *p, const char *t,
|
||||
void (*cb)(struct uci_context *, const char*, void*), void *priv)
|
||||
{
|
||||
struct uci_element *e;
|
||||
if(ucix_get_ptr(ctx, p, NULL, NULL, NULL))
|
||||
return;
|
||||
uci_foreach_element(&ptr.p->sections, e)
|
||||
if (!strcmp(t, uci_to_section(e)->type))
|
||||
cb(ctx, e->name, priv);
|
||||
}
|
||||
|
||||
int ucix_commit(struct uci_context *ctx, const char *p)
|
||||
{
|
||||
if(ucix_get_ptr(ctx, p, NULL, NULL, NULL))
|
||||
return 1;
|
||||
return uci_commit(ctx, &ptr.p, false);
|
||||
}
|
||||
|
||||
|
50
contrib/fwd/src/ucix.h
Normal file
50
contrib/fwd/src/ucix.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Copyright (C) 2008 John Crispin <blogic@openwrt.org>
|
||||
*/
|
||||
|
||||
#ifndef __UCIX_H__
|
||||
#define __UCIX_H_
|
||||
|
||||
struct uci_context* ucix_init(const char *config_file);
|
||||
struct uci_context* ucix_init_path(const char *path, const char *config_file);
|
||||
int ucix_load(struct uci_context *ctx, const char *config_file);
|
||||
void ucix_cleanup(struct uci_context *ctx);
|
||||
void ucix_save(struct uci_context *ctx);
|
||||
void ucix_save_state(struct uci_context *ctx);
|
||||
const char* ucix_get_option(struct uci_context *ctx,
|
||||
const char *p, const char *s, const char *o);
|
||||
int ucix_for_each_list(struct uci_context *ctx,
|
||||
const char *p, const char *s, const char *o,
|
||||
void (*cb)(const char*, void*), void *priv);
|
||||
int ucix_get_option_int(struct uci_context *ctx,
|
||||
const char *p, const char *s, const char *o, int def);
|
||||
void ucix_add_section(struct uci_context *ctx,
|
||||
const char *p, const char *s, const char *t);
|
||||
void ucix_add_option(struct uci_context *ctx,
|
||||
const char *p, const char *s, const char *o, const char *t);
|
||||
void ucix_add_option_int(struct uci_context *ctx,
|
||||
const char *p, const char *s, const char *o, int t);
|
||||
void ucix_for_each_section_type(struct uci_context *ctx,
|
||||
const char *p, const char *t,
|
||||
void (*cb)(struct uci_context *, const char*, void*), void *priv);
|
||||
int ucix_commit(struct uci_context *ctx, const char *p);
|
||||
void ucix_revert(struct uci_context *ctx,
|
||||
const char *p, const char *s, const char *o);
|
||||
void ucix_del(struct uci_context *ctx, const char *p,
|
||||
const char *s, const char *o);
|
||||
#endif
|
||||
|
Loading…
Reference in a new issue