contrib: remove abandonned projects
Signed-off-by: Jo-Philipp Wich <jow@openwrt.org>
This commit is contained in:
parent
d82b889a7b
commit
7e4fff2514
27 changed files with 0 additions and 6926 deletions
|
@ -1,2 +0,0 @@
|
|||
include ../../build/config.mk
|
||||
include ../../build/module.mk
|
|
@ -1,18 +0,0 @@
|
|||
CFLAGS := -ggdb3 -O0 -Wall -I./uci -I./iptables-1.4.5/include
|
||||
LDFLAGS := -luci -liptc -lxtables -ldl -L./iptables-1.4.5/libiptc/.libs -L./iptables-1.4.5/.libs -Wl,--export-dynamic
|
||||
|
||||
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_xtables.o fwd_xtables.c
|
||||
$(CC) $(CFLAGS) -c -o fwd_ipc.o fwd_ipc.c
|
||||
$(CC) $(CFLAGS) -c -o fwd_utils.o fwd_utils.c
|
||||
$(CC) $(CFLAGS) -c -o fwd.o fwd.c
|
||||
$(CC) $(LDFLAGS) -o fwd fwd.o fwd_addr.o fwd_rules.o fwd_config.o fwd_xtables.o fwd_ipc.o fwd_utils.o ucix.o
|
||||
ln -s fwd fw
|
||||
|
||||
clean:
|
||||
rm -f *~ fwd fw *.o
|
||||
|
|
@ -1,320 +0,0 @@
|
|||
/*
|
||||
* 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"
|
||||
#include "fwd_xtables.h"
|
||||
#include "fwd_ipc.h"
|
||||
#include "fwd_utils.h"
|
||||
|
||||
|
||||
static void fwd_foreach_network(
|
||||
struct fwd_handle *h,
|
||||
void (*cb)(struct fwd_handle *h, struct fwd_network *net)
|
||||
) {
|
||||
struct fwd_data *data;
|
||||
struct fwd_network *net;
|
||||
|
||||
for( data = h->conf; data; data = data->next )
|
||||
{
|
||||
if( data->type != FWD_S_ZONE )
|
||||
continue;
|
||||
|
||||
for( net = data->section.zone.networks; net; net = net->next )
|
||||
cb(h, net);
|
||||
}
|
||||
}
|
||||
|
||||
static void fwd_addif_all_cb(struct fwd_handle *h, struct fwd_network *net)
|
||||
{
|
||||
fwd_ipt_addif(h, net->name);
|
||||
}
|
||||
|
||||
static void fwd_delif_all_cb(struct fwd_handle *h, struct fwd_network *net)
|
||||
{
|
||||
fwd_ipt_delif(h, net->name);
|
||||
}
|
||||
|
||||
#define fwd_addif_all(h) fwd_foreach_network(h, fwd_addif_all_cb)
|
||||
#define fwd_delif_all(h) fwd_foreach_network(h, fwd_delif_all_cb)
|
||||
|
||||
|
||||
static int fwd_server_main(int argc, const char *argv[])
|
||||
{
|
||||
struct fwd_handle *h;
|
||||
struct fwd_network *net;
|
||||
struct fwd_addr *addrs;
|
||||
struct fwd_data *data;
|
||||
struct fwd_cidr *addr_old, *addr_new;
|
||||
struct sigaction sa;
|
||||
int unix_client;
|
||||
|
||||
sa.sa_handler = SIG_IGN;
|
||||
sigaction(SIGPIPE, &sa, NULL);
|
||||
|
||||
if( getuid() > 0 )
|
||||
fwd_fatal("Need root permissions!");
|
||||
|
||||
if( !(h = fwd_alloc_ptr(struct fwd_handle)) )
|
||||
fwd_fatal("Out of memory");
|
||||
|
||||
if( (h->rtnl_socket = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1 )
|
||||
fwd_fatal("Failed to create AF_NETLINK socket (%m)");
|
||||
|
||||
if( (h->unix_socket = fwd_ipc_listen()) == -1 )
|
||||
fwd_fatal("Failed to create AF_UNIX socket (%m)");
|
||||
|
||||
if( !(h->conf = fwd_read_config(h)) )
|
||||
fwd_fatal("Failed to read configuration");
|
||||
|
||||
fwd_log_init();
|
||||
|
||||
fwd_ipt_build_ruleset(h);
|
||||
fwd_addif_all(h);
|
||||
|
||||
while(1)
|
||||
{
|
||||
if( (addrs = fwd_get_addrs(h->rtnl_socket, AF_INET)) != NULL )
|
||||
{
|
||||
for( data = h->conf; data; data = data->next )
|
||||
{
|
||||
if( data->type != FWD_S_ZONE )
|
||||
continue;
|
||||
|
||||
for( net = data->section.zone.networks; net; net = net->next )
|
||||
{
|
||||
addr_new = fwd_lookup_addr(addrs, net->ifname);
|
||||
addr_old = net->addr;
|
||||
|
||||
if( !fwd_empty_cidr(addr_new) && fwd_empty_cidr(addr_old) )
|
||||
{
|
||||
fwd_log_info(
|
||||
"Interface %s brought up - adding rules",
|
||||
net->ifname
|
||||
);
|
||||
|
||||
fwd_update_cidr(addr_old, addr_new);
|
||||
fwd_ipt_addif(h, net->name);
|
||||
}
|
||||
else if( fwd_empty_cidr(addr_new) && !fwd_empty_cidr(addr_old) )
|
||||
{
|
||||
fwd_log_info(
|
||||
"Interface %s went down - removing rules",
|
||||
net->ifname
|
||||
);
|
||||
|
||||
fwd_update_cidr(addr_old, NULL);
|
||||
fwd_ipt_delif(h, net->name);
|
||||
}
|
||||
else if( ! fwd_equal_cidr(addr_old, addr_new) )
|
||||
{
|
||||
fwd_log_info(
|
||||
"Interface %s changed IP - rebuilding rules",
|
||||
net->ifname
|
||||
);
|
||||
|
||||
fwd_update_cidr(addr_old, addr_new);
|
||||
fwd_ipt_chgif(h, net->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fwd_free_addrs(addrs);
|
||||
}
|
||||
|
||||
|
||||
if( (unix_client = fwd_ipc_accept(h->unix_socket)) > -1 )
|
||||
{
|
||||
struct fwd_ipc_msg msg;
|
||||
memset(&msg, 0, sizeof(struct fwd_ipc_msg));
|
||||
|
||||
while( fwd_ipc_recvmsg(unix_client, &msg, sizeof(struct fwd_ipc_msg)) > 0 )
|
||||
{
|
||||
fwd_log_info("Got message [%i]", msg.type);
|
||||
|
||||
switch(msg.type)
|
||||
{
|
||||
case FWD_IPC_FLUSH:
|
||||
fwd_log_info("Flushing rules ...");
|
||||
fwd_ipt_clear_ruleset(h);
|
||||
fwd_ipc_sendtype(unix_client, FWD_IPC_OK);
|
||||
break;
|
||||
|
||||
case FWD_IPC_BUILD:
|
||||
fwd_log_info("Building rules ...");
|
||||
fwd_ipt_clear_ruleset(h);
|
||||
fwd_ipt_build_ruleset(h);
|
||||
fwd_addif_all(h);
|
||||
fwd_ipc_sendtype(unix_client, FWD_IPC_OK);
|
||||
break;
|
||||
|
||||
case FWD_IPC_RELOAD:
|
||||
if( (data = fwd_read_config(h)) != NULL )
|
||||
{
|
||||
fwd_log_info("Flushing rules ...");
|
||||
fwd_ipt_clear_ruleset(h);
|
||||
fwd_free_config(h->conf);
|
||||
h->conf = data;
|
||||
fwd_log_info("Building rules ...");
|
||||
fwd_ipt_build_ruleset(h);
|
||||
fwd_addif_all(h);
|
||||
fwd_ipc_sendtype(unix_client, FWD_IPC_OK);
|
||||
}
|
||||
else
|
||||
{
|
||||
fwd_log_err("Cannot reload configuration!");
|
||||
fwd_ipc_sendtype(unix_client, FWD_IPC_ERROR);
|
||||
}
|
||||
break;
|
||||
|
||||
case FWD_IPC_ADDIF:
|
||||
case FWD_IPC_DELIF:
|
||||
if( strlen(msg.data.network) > 0 )
|
||||
{
|
||||
fwd_ipt_delif(h, msg.data.network);
|
||||
|
||||
if( msg.type == FWD_IPC_ADDIF )
|
||||
fwd_ipt_addif(h, msg.data.network);
|
||||
|
||||
fwd_ipc_sendtype(unix_client, FWD_IPC_OK);
|
||||
}
|
||||
else
|
||||
{
|
||||
fwd_log_err("No network name provided!");
|
||||
fwd_ipc_sendtype(unix_client, FWD_IPC_ERROR);
|
||||
}
|
||||
break;
|
||||
|
||||
case FWD_IPC_OK:
|
||||
case FWD_IPC_ERROR:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fwd_ipc_shutdown(unix_client);
|
||||
}
|
||||
|
||||
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
fwd_delif_all(h);
|
||||
fwd_ipt_clear_ruleset(h);
|
||||
|
||||
close(h->rtnl_socket);
|
||||
fwd_free_config(h->conf);
|
||||
fwd_free_ptr(h);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fwd_client_usage(const char *msg)
|
||||
{
|
||||
printf(
|
||||
"%s\n\n"
|
||||
"Usage:\n"
|
||||
" fw flush\n"
|
||||
" Flush all rules in the firewall and reset policy\n\n"
|
||||
" fw build\n"
|
||||
" Rebuild firewall rules\n\n"
|
||||
" fw reload\n"
|
||||
" Reload configuration and rebuild firewall rules\n\n"
|
||||
" fw addif {network}\n"
|
||||
" Add rules for given network\n\n"
|
||||
" fw delif {network}\n"
|
||||
" Remove rules for given network\n\n"
|
||||
"", msg
|
||||
);
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static int fwd_client_main(int argc, const char *argv[])
|
||||
{
|
||||
int unix_server;
|
||||
struct fwd_ipc_msg msg;
|
||||
enum fwd_ipc_msgtype type;
|
||||
|
||||
if( argc < 2 )
|
||||
fwd_client_usage("Command required");
|
||||
|
||||
if( (unix_server = fwd_ipc_connect()) < 0 )
|
||||
fwd_fatal("Cannot connect to server instance (%m)");
|
||||
|
||||
|
||||
memset(&msg, 0, sizeof(struct fwd_ipc_msg));
|
||||
|
||||
if( !strcmp(argv[1], "flush") )
|
||||
type = FWD_IPC_FLUSH;
|
||||
|
||||
else if( !strcmp(argv[1], "build") )
|
||||
type = FWD_IPC_BUILD;
|
||||
|
||||
else if( !strcmp(argv[1], "reload") )
|
||||
type = FWD_IPC_RELOAD;
|
||||
|
||||
else if( !strcmp(argv[1], "addif") || !strcmp(argv[1], "delif") )
|
||||
{
|
||||
if( argc < 3 )
|
||||
fwd_client_usage("The command requires a parameter.");
|
||||
|
||||
type = strcmp(argv[1], "addif") ? FWD_IPC_DELIF : FWD_IPC_ADDIF;
|
||||
strncpy(msg.data.network, argv[2], sizeof(msg.data.network));
|
||||
}
|
||||
|
||||
else
|
||||
fwd_client_usage("Invalid command given.");
|
||||
|
||||
msg.type = type;
|
||||
fwd_ipc_sendmsg(unix_server, &msg, sizeof(struct fwd_ipc_msg));
|
||||
|
||||
memset(&msg, 0, sizeof(struct fwd_ipc_msg));
|
||||
|
||||
while( fwd_ipc_recvmsg(unix_server, &msg, sizeof(struct fwd_ipc_msg)) == 0 )
|
||||
continue;
|
||||
|
||||
switch(msg.type)
|
||||
{
|
||||
case FWD_IPC_OK:
|
||||
printf("Success\n");
|
||||
break;
|
||||
|
||||
case FWD_IPC_ERROR:
|
||||
printf("The server reported an error, check logread!\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
fwd_fatal("Unexpected response type %i", msg.type);
|
||||
}
|
||||
|
||||
fwd_ipc_shutdown(unix_server);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
if( strstr(argv[0], "fwd") )
|
||||
return fwd_server_main(argc, argv);
|
||||
else
|
||||
return fwd_client_main(argc, argv);
|
||||
}
|
||||
|
|
@ -1,182 +0,0 @@
|
|||
/*
|
||||
* 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 <getopt.h>
|
||||
#include <signal.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
|
||||
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 {
|
||||
char *name;
|
||||
char *ifname;
|
||||
int isalias;
|
||||
struct fwd_cidr *addr;
|
||||
struct fwd_network *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 *networks;
|
||||
struct fwd_data *forwardings;
|
||||
struct fwd_data *redirects;
|
||||
struct fwd_data *rules;
|
||||
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;
|
||||
int clone; /* true if rule is cloned (tcpudp -> tcp + udp) */
|
||||
};
|
||||
|
||||
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;
|
||||
int clone; /* true if rule is cloned (tcpudp -> tcp + udp) */
|
||||
};
|
||||
|
||||
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;
|
||||
int unix_socket;
|
||||
struct fwd_data *conf;
|
||||
};
|
||||
|
||||
|
||||
/* 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)
|
||||
|
||||
|
||||
#endif
|
|
@ -1,162 +0,0 @@
|
|||
/*
|
||||
* 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"
|
||||
#include "fwd_utils.h"
|
||||
|
||||
struct fwd_addr * 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 *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)) )
|
||||
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.addr, (char *) RTA_DATA(rtatp), rtatp->rta_len);
|
||||
entry->ipaddr.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;
|
||||
}
|
||||
|
||||
struct fwd_cidr * fwd_lookup_addr(struct fwd_addr *head, const char *ifname)
|
||||
{
|
||||
struct fwd_addr *entry;
|
||||
|
||||
for( entry = head; entry; entry = entry->next )
|
||||
if( !strncmp(entry->ifname, ifname, IFNAMSIZ) )
|
||||
return &entry->ipaddr;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void fwd_free_addrs(struct fwd_addr *head)
|
||||
{
|
||||
struct fwd_addr *entry = head;
|
||||
|
||||
while( entry != NULL )
|
||||
{
|
||||
head = entry->next;
|
||||
free(entry);
|
||||
entry = head;
|
||||
}
|
||||
|
||||
head = entry = NULL;
|
||||
}
|
||||
|
||||
struct fwd_addr * fwd_append_addrs(struct fwd_addr *head, struct fwd_addr *add)
|
||||
{
|
||||
struct fwd_addr *entry = head;
|
||||
|
||||
while( entry->next != NULL )
|
||||
entry = entry->next;
|
||||
|
||||
return (entry->next = add);
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
* 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 {
|
||||
char ifname[IFNAMSIZ];
|
||||
char label[IFNAMSIZ];
|
||||
int family;
|
||||
int index;
|
||||
struct fwd_cidr ipaddr;
|
||||
struct fwd_addr *next;
|
||||
};
|
||||
|
||||
|
||||
struct fwd_addr * fwd_get_addrs(int, int);
|
||||
struct fwd_addr * fwd_append_addrs(struct fwd_addr *, struct fwd_addr *);
|
||||
void fwd_free_addrs(struct fwd_addr *);
|
||||
|
||||
struct fwd_cidr * fwd_lookup_addr(struct fwd_addr *, const char *);
|
||||
|
||||
#define fwd_foreach_addrs(head, entry) for(entry = head; entry; entry = entry->next)
|
||||
|
||||
#endif
|
||||
|
|
@ -1,987 +0,0 @@
|
|||
/*
|
||||
* 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 "fwd_utils.h"
|
||||
|
||||
#include "ucix.h"
|
||||
|
||||
|
||||
#define fwd_read_error(...) do { \
|
||||
fwd_log_err(__VA_ARGS__); \
|
||||
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 )
|
||||
{
|
||||
unsigned int i1, i2, i3, i4, i5, i6;
|
||||
|
||||
if( sscanf(val, "%2x:%2x:%2x:%2x:%2x:%2x",
|
||||
&i1, &i2, &i3, &i4, &i5, &i6) == 6
|
||||
) {
|
||||
(*m)->mac[0] = (unsigned char)i1;
|
||||
(*m)->mac[1] = (unsigned char)i2;
|
||||
(*m)->mac[2] = (unsigned char)i3;
|
||||
(*m)->mac[3] = (unsigned char)i4;
|
||||
(*m)->mac[4] = (unsigned char)i5;
|
||||
(*m)->mac[5] = (unsigned char)i6;
|
||||
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 **np
|
||||
) {
|
||||
struct fwd_network *nn;
|
||||
|
||||
if( (nn = fwd_alloc_ptr(struct fwd_network)) != 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 *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")) )
|
||||
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);
|
||||
else if( !(dest = fwd_read_string(uci, s, "dest")) )
|
||||
fwd_read_error("section '%s' is missing 'dest' option!", s);
|
||||
else 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;
|
||||
|
||||
if( zsrc )
|
||||
{
|
||||
dtn->next = zsrc->forwardings;
|
||||
zsrc->forwardings = dtn;
|
||||
}
|
||||
else
|
||||
{
|
||||
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_data *dtn2 = 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 = zsrc->redirects;
|
||||
zsrc->redirects = dtn;
|
||||
|
||||
if( (proto != NULL) && (proto->type == FWD_PR_TCPUDP) )
|
||||
{
|
||||
if( !(dtn2 = fwd_alloc_ptr(struct fwd_data)) ||
|
||||
!(dtn2->section.redirect.proto = fwd_alloc_ptr(struct fwd_proto))
|
||||
) {
|
||||
fwd_free_ptr(dtn2);
|
||||
fwd_read_error("out of memory while parsing config!");
|
||||
}
|
||||
|
||||
dtn->section.redirect.proto->type = FWD_PR_UDP;
|
||||
dtn2->section.redirect.proto->type = FWD_PR_TCP;
|
||||
|
||||
dtn2->section.redirect.src = zsrc;
|
||||
dtn2->section.redirect.src_ip = src_ip;
|
||||
dtn2->section.redirect.src_mac = src_mac;
|
||||
dtn2->section.redirect.src_port = src_port;
|
||||
dtn2->section.redirect.src_dport = src_dport;
|
||||
dtn2->section.redirect.dest_ip = dest_ip;
|
||||
dtn2->section.redirect.dest_port = dest_port;
|
||||
dtn2->section.redirect.clone = 1;
|
||||
|
||||
dtn2->type = FWD_S_REDIRECT;
|
||||
dtn2->next = zsrc->redirects;
|
||||
zsrc->redirects = dtn2;
|
||||
}
|
||||
}
|
||||
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_data *dtn2 = 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 = zsrc->rules;
|
||||
zsrc->rules = dtn;
|
||||
|
||||
if( (proto != NULL) && (proto->type == FWD_PR_TCPUDP) )
|
||||
{
|
||||
if( !(dtn2 = fwd_alloc_ptr(struct fwd_data)) ||
|
||||
!(dtn2->section.rule.proto = fwd_alloc_ptr(struct fwd_proto))
|
||||
) {
|
||||
fwd_free_ptr(dtn2);
|
||||
fwd_read_error("out of memory while parsing config!");
|
||||
}
|
||||
|
||||
dtn->section.rule.proto->type = FWD_PR_UDP;
|
||||
dtn2->section.rule.proto->type = FWD_PR_TCP;
|
||||
|
||||
dtn2->section.rule.src = zsrc;
|
||||
dtn2->section.rule.src_ip = src_ip;
|
||||
dtn2->section.rule.src_mac = src_mac;
|
||||
dtn2->section.rule.src_port = src_port;
|
||||
dtn2->section.rule.dest = zdest;
|
||||
dtn2->section.rule.dest_ip = dest_ip;
|
||||
dtn2->section.rule.dest_port = dest_port;
|
||||
dtn2->section.rule.target = dtn->section.rule.target;
|
||||
dtn2->section.rule.clone = 1;
|
||||
|
||||
dtn2->type = FWD_S_RULE;
|
||||
dtn2->next = zsrc->rules;
|
||||
zsrc->rules = dtn2;
|
||||
}
|
||||
}
|
||||
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 *net
|
||||
) {
|
||||
struct fwd_network *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 *h)
|
||||
{
|
||||
struct fwd_network *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;
|
||||
}
|
||||
|
||||
static struct fwd_cidr * fwd_alloc_cidr(struct fwd_cidr *addr)
|
||||
{
|
||||
struct fwd_cidr *cidr;
|
||||
|
||||
if( (cidr = fwd_alloc_ptr(struct fwd_cidr)) != NULL )
|
||||
{
|
||||
if( addr != NULL )
|
||||
{
|
||||
cidr->addr.s_addr = addr->addr.s_addr;
|
||||
cidr->prefix = addr->prefix;
|
||||
}
|
||||
|
||||
return cidr;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct fwd_data * fwd_read_config(struct fwd_handle *h)
|
||||
{
|
||||
struct uci_context *ctx;
|
||||
struct fwd_data *defaults, *zones, *e;
|
||||
struct fwd_addr *addrs;
|
||||
struct fwd_network *net;
|
||||
struct fwd_zone *zone;
|
||||
|
||||
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);
|
||||
|
||||
if( !(addrs = fwd_get_addrs(h->rtnl_socket, AF_INET)) )
|
||||
goto error;
|
||||
|
||||
for( e = zones; e && (zone = &e->section.zone); e = e->next )
|
||||
{
|
||||
if( e->type != FWD_S_ZONE )
|
||||
break;
|
||||
|
||||
for( net = zone->networks; net; net = net->next )
|
||||
{
|
||||
net->addr = fwd_alloc_cidr(
|
||||
fwd_lookup_addr(addrs, net->ifname)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fwd_free_addrs(addrs);
|
||||
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);
|
||||
fwd_free_config(h->section.zone.rules);
|
||||
fwd_free_config(h->section.zone.redirects);
|
||||
fwd_free_config(h->section.zone.forwardings);
|
||||
break;
|
||||
|
||||
case FWD_S_REDIRECT:
|
||||
/* Clone rules share all pointers except proto.
|
||||
Prevent a double-free here */
|
||||
if( ! h->section.redirect.clone )
|
||||
{
|
||||
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:
|
||||
/* Clone rules share all pointers except proto.
|
||||
Prevent a double-free here */
|
||||
if( ! h->section.rule.clone )
|
||||
{
|
||||
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.icmp_type);
|
||||
}
|
||||
fwd_free_ptr(h->section.rule.proto);
|
||||
break;
|
||||
|
||||
case FWD_S_DEFAULTS:
|
||||
case FWD_S_FORWARD:
|
||||
/* Make gcc happy */
|
||||
break;
|
||||
}
|
||||
|
||||
fwd_free_ptr(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;
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
#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(struct fwd_handle *);
|
||||
struct fwd_zone * fwd_lookup_zone(struct fwd_data *, const char *);
|
||||
|
||||
void fwd_free_config(struct fwd_data *);
|
||||
|
||||
#endif
|
|
@ -1,98 +0,0 @@
|
|||
/*
|
||||
* fwd - OpenWrt firewall daemon - unix domain socket parts
|
||||
*
|
||||
* 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_ipc.h"
|
||||
|
||||
|
||||
int fwd_ipc_listen(void)
|
||||
{
|
||||
int fd;
|
||||
struct sockaddr_un addr;
|
||||
|
||||
if( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0 )
|
||||
fwd_fatal("Cannot create AF_UNIX socket: %m");
|
||||
|
||||
memset(&addr, 0, sizeof(struct sockaddr_un));
|
||||
strcpy(addr.sun_path, FWD_SOCKET_PATH);
|
||||
addr.sun_family = AF_UNIX;
|
||||
|
||||
unlink(FWD_SOCKET_PATH);
|
||||
|
||||
if( bind(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0 )
|
||||
fwd_fatal("Cannot bind AF_UNIX socket: %m");
|
||||
|
||||
if( listen(fd, 1) < 0 )
|
||||
fwd_fatal("Cannot listen on AF_UNIX socket: %m");
|
||||
|
||||
//fcntl(fd, F_SETFL, O_NONBLOCK);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int fwd_ipc_accept(int fd)
|
||||
{
|
||||
return accept(fd, NULL, NULL);
|
||||
}
|
||||
|
||||
int fwd_ipc_connect(void)
|
||||
{
|
||||
int fd;
|
||||
struct sockaddr_un addr;
|
||||
|
||||
if( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0 )
|
||||
fwd_fatal("Cannot create AF_UNIX socket: %m");
|
||||
|
||||
memset(&addr, 0, sizeof(struct sockaddr_un));
|
||||
strcpy(addr.sun_path, FWD_SOCKET_PATH);
|
||||
addr.sun_family = AF_UNIX;
|
||||
|
||||
if( connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0 )
|
||||
fwd_fatal("Cannot connect AF_UNIX socket: %m");
|
||||
|
||||
fcntl(fd, F_SETFL, O_NONBLOCK);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int fwd_ipc_recvmsg(int fd, void *buf, int len)
|
||||
{
|
||||
return recv(fd, buf, len, 0);
|
||||
}
|
||||
|
||||
int fwd_ipc_sendmsg(int fd, void *buf, int len)
|
||||
{
|
||||
return send(fd, buf, len, 0);
|
||||
}
|
||||
|
||||
void fwd_ipc_shutdown(int fd)
|
||||
{
|
||||
shutdown(fd, SHUT_RDWR);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
int fwd_ipc_sendtype(int fd, enum fwd_ipc_msgtype type)
|
||||
{
|
||||
struct fwd_ipc_msg msg;
|
||||
|
||||
memset(&msg, 0, sizeof(struct fwd_ipc_msg));
|
||||
msg.type = type;
|
||||
|
||||
return fwd_ipc_sendmsg(fd, &msg, sizeof(struct fwd_ipc_msg));
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
/*
|
||||
* fwd - OpenWrt firewall daemon - unix domain socket headers
|
||||
*
|
||||
* 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_IPC_H__
|
||||
#define __FWD_IPC_H__
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#define FWD_SOCKET_PATH "/var/run/fwd.sock"
|
||||
|
||||
|
||||
enum fwd_ipc_msgtype {
|
||||
FWD_IPC_OK = 0,
|
||||
FWD_IPC_ERROR = 1,
|
||||
FWD_IPC_FLUSH = 2,
|
||||
FWD_IPC_BUILD = 3,
|
||||
FWD_IPC_RELOAD = 4,
|
||||
FWD_IPC_ADDIF = 5,
|
||||
FWD_IPC_DELIF = 6
|
||||
};
|
||||
|
||||
struct fwd_ipc_msg {
|
||||
enum fwd_ipc_msgtype type;
|
||||
union {
|
||||
char network[256];
|
||||
} data;
|
||||
};
|
||||
|
||||
int fwd_ipc_listen(void);
|
||||
int fwd_ipc_accept(int);
|
||||
|
||||
int fwd_ipc_connect(void);
|
||||
|
||||
int fwd_ipc_recvmsg(int, void *, int);
|
||||
int fwd_ipc_sendmsg(int, void *, int);
|
||||
|
||||
void fwd_ipc_shutdown(int);
|
||||
|
||||
int fwd_ipc_sendtype(int, enum fwd_ipc_msgtype);
|
||||
|
||||
#endif
|
|
@ -1,886 +0,0 @@
|
|||
/*
|
||||
* 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"
|
||||
#include "fwd_xtables.h"
|
||||
#include "fwd_utils.h"
|
||||
|
||||
|
||||
/* -P <chain> <policy> */
|
||||
static void fwd_r_set_policy(
|
||||
struct iptc_handle *h, const char *chain, const char *policy
|
||||
) {
|
||||
iptc_set_policy(chain, policy, NULL, h);
|
||||
}
|
||||
|
||||
/* -N <chain> */
|
||||
static void fwd_r_new_chain(struct iptc_handle *h, const char *chain)
|
||||
{
|
||||
iptc_create_chain(chain, h);
|
||||
}
|
||||
|
||||
/* -A <chain1> -j <chain2> */
|
||||
static void fwd_r_jump_chain(
|
||||
struct iptc_handle *h, const char *chain1, const char *chain2
|
||||
) {
|
||||
struct fwd_xt_rule *r;
|
||||
|
||||
if( (r = fwd_xt_init_rule(h)) != NULL )
|
||||
{
|
||||
fwd_xt_get_target(r, chain2);
|
||||
fwd_xt_append_rule(r, chain1);
|
||||
}
|
||||
}
|
||||
|
||||
/* -A <chain> -m state --state INVALID -j DROP */
|
||||
static void fwd_r_drop_invalid(struct iptc_handle *h, const char *chain)
|
||||
{
|
||||
struct fwd_xt_rule *r;
|
||||
struct xtables_match *m;
|
||||
|
||||
if( (r = fwd_xt_init_rule(h)) != NULL )
|
||||
{
|
||||
if( (m = fwd_xt_get_match(r, "state")) != NULL )
|
||||
{
|
||||
fwd_xt_parse_match(r, m, "--state", "INVALID");
|
||||
fwd_xt_get_target(r, "DROP");
|
||||
fwd_xt_append_rule(r, chain);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* -A <chain> -m state --state RELATED,ESTABLISHED -j ACCEPT */
|
||||
static void fwd_r_accept_related(struct iptc_handle *h, const char *chain)
|
||||
{
|
||||
struct fwd_xt_rule *r;
|
||||
struct xtables_match *m;
|
||||
|
||||
if( (r = fwd_xt_init_rule(h)) != NULL )
|
||||
{
|
||||
if( (m = fwd_xt_get_match(r, "state")) != NULL )
|
||||
{
|
||||
fwd_xt_parse_match(r, m, "--state", "RELATED,ESTABLISHED");
|
||||
fwd_xt_get_target(r, "ACCEPT");
|
||||
fwd_xt_append_rule(r, chain);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* -A INPUT -i lo -j ACCEPT; -A OUTPUT -o lo -j ACCEPT */
|
||||
static void fwd_r_accept_lo(struct iptc_handle *h)
|
||||
{
|
||||
struct fwd_network n;
|
||||
struct fwd_xt_rule *r;
|
||||
|
||||
n.ifname = "lo";
|
||||
|
||||
if( (r = fwd_xt_init_rule(h)) != NULL )
|
||||
{
|
||||
fwd_xt_parse_in(r, &n, 0);
|
||||
fwd_xt_get_target(r, "ACCEPT");
|
||||
fwd_xt_append_rule(r, "INPUT");
|
||||
}
|
||||
|
||||
if( (r = fwd_xt_init_rule(h)) != NULL )
|
||||
{
|
||||
fwd_xt_parse_out(r, &n, 0);
|
||||
fwd_xt_get_target(r, "ACCEPT");
|
||||
fwd_xt_append_rule(r, "OUTPUT");
|
||||
}
|
||||
}
|
||||
|
||||
/* build syn_flood chain and jump rule */
|
||||
static void fwd_r_add_synflood(struct iptc_handle *h, struct fwd_defaults *def)
|
||||
{
|
||||
struct fwd_proto p;
|
||||
struct fwd_xt_rule *r;
|
||||
struct xtables_match *m;
|
||||
char buf[32];
|
||||
|
||||
/* -N syn_flood */
|
||||
fwd_r_new_chain(h, "syn_flood");
|
||||
|
||||
/* return rule */
|
||||
if( (r = fwd_xt_init_rule(h)) != NULL )
|
||||
{
|
||||
/* -p tcp */
|
||||
p.type = FWD_PR_TCP;
|
||||
fwd_xt_parse_proto(r, &p, 0);
|
||||
|
||||
/* -m tcp --syn */
|
||||
if( (m = fwd_xt_get_match(r, "tcp")) != NULL )
|
||||
{
|
||||
fwd_xt_parse_match(r, m, "--syn");
|
||||
}
|
||||
|
||||
/* -m limit --limit x/second --limit-burst y */
|
||||
if( (m = fwd_xt_get_match(r, "limit")) != NULL )
|
||||
{
|
||||
sprintf(buf, "%i/second", def->syn_rate);
|
||||
fwd_xt_parse_match(r, m, "--limit", buf);
|
||||
|
||||
sprintf(buf, "%i", def->syn_burst);
|
||||
fwd_xt_parse_match(r, m, "--limit-burst", buf);
|
||||
}
|
||||
|
||||
/* -j RETURN; -A syn_flood */
|
||||
fwd_xt_get_target(r, "RETURN");
|
||||
fwd_xt_append_rule(r, "syn_flood");
|
||||
}
|
||||
|
||||
/* drop rule */
|
||||
if( (r = fwd_xt_init_rule(h)) != NULL )
|
||||
{
|
||||
/* -j DROP; -A syn_flood */
|
||||
fwd_xt_get_target(r, "DROP");
|
||||
fwd_xt_append_rule(r, "syn_flood");
|
||||
}
|
||||
|
||||
/* jump to syn_flood rule */
|
||||
if( (r = fwd_xt_init_rule(h)) != NULL )
|
||||
{
|
||||
/* -p tcp */
|
||||
p.type = FWD_PR_TCP;
|
||||
fwd_xt_parse_proto(r, &p, 0);
|
||||
|
||||
/* -m tcp --syn */
|
||||
if( (m = fwd_xt_get_match(r, "tcp")) != NULL )
|
||||
{
|
||||
fwd_xt_parse_match(r, m, "--syn");
|
||||
}
|
||||
|
||||
/* -j syn_flood; -A INPUT */
|
||||
fwd_xt_get_target(r, "syn_flood");
|
||||
fwd_xt_append_rule(r, "INPUT");
|
||||
}
|
||||
}
|
||||
|
||||
/* build reject target chain */
|
||||
static void fwd_r_handle_reject(struct iptc_handle *h)
|
||||
{
|
||||
struct fwd_proto p;
|
||||
struct fwd_xt_rule *r;
|
||||
struct xtables_target *t;
|
||||
|
||||
/* -N handle_reject */
|
||||
fwd_r_new_chain(h, "handle_reject");
|
||||
|
||||
/* tcp reject rule */
|
||||
if( (r = fwd_xt_init_rule(h)) != NULL )
|
||||
{
|
||||
/* -p tcp */
|
||||
p.type = FWD_PR_TCP;
|
||||
fwd_xt_parse_proto(r, &p, 0);
|
||||
|
||||
/* -j REJECT --reject-with tcp-reset */
|
||||
if( (t = fwd_xt_get_target(r, "REJECT")) != NULL )
|
||||
{
|
||||
fwd_xt_parse_target(r, t, "--reject-with", "tcp-reset");
|
||||
}
|
||||
|
||||
/* -A handle_reject */
|
||||
fwd_xt_append_rule(r, "handle_reject");
|
||||
}
|
||||
|
||||
/* common reject rule */
|
||||
if( (r = fwd_xt_init_rule(h)) != NULL )
|
||||
{
|
||||
/* -j REJECT --reject-with icmp-port-unreachable */
|
||||
if( (t = fwd_xt_get_target(r, "REJECT")) != NULL )
|
||||
{
|
||||
fwd_xt_parse_target(r, t, "--reject-with",
|
||||
"icmp-port-unreachable");
|
||||
}
|
||||
|
||||
/* -A handle_reject */
|
||||
fwd_xt_append_rule(r, "handle_reject");
|
||||
}
|
||||
}
|
||||
|
||||
/* build drop target chain */
|
||||
static void fwd_r_handle_drop(struct iptc_handle *h)
|
||||
{
|
||||
struct fwd_xt_rule *r;
|
||||
|
||||
/* -N handle_drop */
|
||||
fwd_r_new_chain(h, "handle_drop");
|
||||
|
||||
/* common drop rule */
|
||||
if( (r = fwd_xt_init_rule(h)) != NULL )
|
||||
{
|
||||
/* -j DROP; -A handle_drop */
|
||||
fwd_xt_get_target(r, "DROP");
|
||||
fwd_xt_append_rule(r, "handle_drop");
|
||||
}
|
||||
}
|
||||
|
||||
/* build accept target chain */
|
||||
static void fwd_r_handle_accept(struct iptc_handle *h)
|
||||
{
|
||||
struct fwd_xt_rule *r;
|
||||
|
||||
/* -N handle_accept */
|
||||
fwd_r_new_chain(h, "handle_accept");
|
||||
|
||||
/* common accept rule */
|
||||
if( (r = fwd_xt_init_rule(h)) != NULL )
|
||||
{
|
||||
/* -j ACCEPT; -A handle_accept */
|
||||
fwd_xt_get_target(r, "ACCEPT");
|
||||
fwd_xt_append_rule(r, "handle_accept");
|
||||
}
|
||||
}
|
||||
|
||||
/* add comment match */
|
||||
static void fwd_r_add_comment(
|
||||
struct fwd_xt_rule *r, const char *t, struct fwd_zone *z,
|
||||
struct fwd_network *n
|
||||
) {
|
||||
struct xtables_match *m;
|
||||
char buf[256];
|
||||
|
||||
if( (m = fwd_xt_get_match(r, "comment")) != NULL )
|
||||
{
|
||||
snprintf(buf, sizeof(buf), "%s:net=%s zone=%s", t, n->name, z->name);
|
||||
fwd_xt_parse_match(r, m, "--comment", buf);
|
||||
}
|
||||
}
|
||||
|
||||
/* add --sport (if applicable) */
|
||||
static void fwd_r_add_sport(
|
||||
struct fwd_xt_rule *r, struct fwd_portrange *p
|
||||
) {
|
||||
int proto = r->entry->ip.proto;
|
||||
char buf[12];
|
||||
struct xtables_match *m;
|
||||
|
||||
/* have portrange and proto is tcp or udp ... */
|
||||
if( (p != NULL) && ((proto == 6) || (proto == 17)) )
|
||||
{
|
||||
/* get match ... */
|
||||
if( (m = fwd_xt_get_match(r, (proto == 6) ? "tcp" : "udp")) != NULL )
|
||||
{
|
||||
snprintf(buf, sizeof(buf), "%u:%u", p->min, p->max);
|
||||
fwd_xt_parse_match(r, m, "--sport", buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* add --dport (if applicable) */
|
||||
static void fwd_r_add_dport(
|
||||
struct fwd_xt_rule *r, struct fwd_portrange *p
|
||||
) {
|
||||
int proto = r->entry->ip.proto;
|
||||
char buf[12];
|
||||
struct xtables_match *m;
|
||||
|
||||
/* have portrange and proto is tcp or udp ... */
|
||||
if( (p != NULL) && ((proto == 6) || (proto == 17)) )
|
||||
{
|
||||
/* get match ... */
|
||||
if( (m = fwd_xt_get_match(r, (proto == 6) ? "tcp" : "udp")) != NULL )
|
||||
{
|
||||
snprintf(buf, sizeof(buf), "%u:%u", p->min, p->max);
|
||||
fwd_xt_parse_match(r, m, "--dport", buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* add --icmp-type (of applicable) */
|
||||
static void fwd_r_add_icmptype(
|
||||
struct fwd_xt_rule *r, struct fwd_icmptype *i
|
||||
) {
|
||||
int proto = r->entry->ip.proto;
|
||||
struct xtables_match *m;
|
||||
char buf[32];
|
||||
|
||||
/* have icmp-type and proto is icmp ... */
|
||||
if( (i != NULL) && (proto == 1) )
|
||||
{
|
||||
/* get match ... */
|
||||
if( (m = fwd_xt_get_match(r, "icmp")) != NULL )
|
||||
{
|
||||
if( i->name[0] )
|
||||
snprintf(buf, sizeof(buf), "%s", i->name);
|
||||
else
|
||||
snprintf(buf, sizeof(buf), "%u/%u", i->type, i->code);
|
||||
|
||||
fwd_xt_parse_match(r, m, "--icmp-type", buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* add -m mac --mac-source ... */
|
||||
static void fwd_r_add_srcmac(
|
||||
struct fwd_xt_rule *r, struct fwd_mac *mac
|
||||
) {
|
||||
struct xtables_match *m;
|
||||
char buf[18];
|
||||
|
||||
if( mac != NULL )
|
||||
{
|
||||
if( (m = fwd_xt_get_match(r, "mac")) != NULL )
|
||||
{
|
||||
snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
mac->mac[0], mac->mac[1], mac->mac[2],
|
||||
mac->mac[3], mac->mac[4], mac->mac[5]);
|
||||
|
||||
fwd_xt_parse_match(r, m, "--mac-source", buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* add policy target */
|
||||
static void fwd_r_add_policytarget(
|
||||
struct fwd_xt_rule *r, enum fwd_policy pol
|
||||
) {
|
||||
switch(pol)
|
||||
{
|
||||
case FWD_P_ACCEPT:
|
||||
fwd_xt_get_target(r, "handle_accept");
|
||||
break;
|
||||
|
||||
case FWD_P_REJECT:
|
||||
fwd_xt_get_target(r, "handle_reject");
|
||||
break;
|
||||
|
||||
case FWD_P_DROP:
|
||||
case FWD_P_UNSPEC:
|
||||
fwd_xt_get_target(r, "handle_drop");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* add dnat target */
|
||||
static void fwd_r_add_dnattarget(
|
||||
struct fwd_xt_rule *r, struct fwd_cidr *c, struct fwd_portrange *p
|
||||
) {
|
||||
struct xtables_target *t;
|
||||
char buf[32];
|
||||
|
||||
if( c != NULL )
|
||||
{
|
||||
if( (t = fwd_xt_get_target(r, "DNAT")) != NULL )
|
||||
{
|
||||
if( p != NULL )
|
||||
snprintf(buf, sizeof(buf), "%s:%u-%u",
|
||||
inet_ntoa(c->addr), p->min, p->max);
|
||||
else
|
||||
snprintf(buf, sizeof(buf), "%s", inet_ntoa(c->addr));
|
||||
|
||||
fwd_xt_parse_target(r, t, "--to-destination", buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* parse comment string and look for match */
|
||||
static int fwd_r_cmp(const char *what, const char *cmt, const char *cmp)
|
||||
{
|
||||
char *match;
|
||||
|
||||
if( (match = strstr(cmt, what)) == NULL )
|
||||
return 0;
|
||||
|
||||
match += strlen(what);
|
||||
|
||||
if( strncmp(match, cmp, strlen(cmp)) != 0 )
|
||||
return 0;
|
||||
|
||||
if( (match[strlen(cmp)] != ' ') && (match[strlen(cmp)] != '\0') )
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void fwd_ipt_defaults_create(struct fwd_data *d)
|
||||
{
|
||||
struct fwd_defaults *def = &d->section.defaults;
|
||||
struct iptc_handle *h_filter, *h_nat;
|
||||
|
||||
if( !(h_filter = iptc_init("filter")) || !(h_nat = iptc_init("nat")) )
|
||||
fwd_fatal("Unable to obtain libiptc handle");
|
||||
|
||||
/* policies */
|
||||
fwd_r_set_policy(h_filter, "INPUT",
|
||||
def->input == FWD_P_ACCEPT ? "ACCEPT" : "DROP");
|
||||
fwd_r_set_policy(h_filter, "OUTPUT",
|
||||
def->output == FWD_P_ACCEPT ? "ACCEPT" : "DROP");
|
||||
fwd_r_set_policy(h_filter, "FORWARD",
|
||||
def->forward == FWD_P_ACCEPT ? "ACCEPT" : "DROP");
|
||||
|
||||
/* invalid state drop */
|
||||
if( def->drop_invalid )
|
||||
{
|
||||
fwd_r_drop_invalid(h_filter, "INPUT");
|
||||
fwd_r_drop_invalid(h_filter, "OUTPUT");
|
||||
fwd_r_drop_invalid(h_filter, "FORWARD");
|
||||
}
|
||||
|
||||
/* default accept related */
|
||||
fwd_r_accept_related(h_filter, "INPUT");
|
||||
fwd_r_accept_related(h_filter, "OUTPUT");
|
||||
fwd_r_accept_related(h_filter, "FORWARD");
|
||||
|
||||
/* default accept on lo */
|
||||
fwd_r_accept_lo(h_filter);
|
||||
|
||||
/* syn flood protection */
|
||||
if( def->syn_flood )
|
||||
{
|
||||
fwd_r_add_synflood(h_filter, def);
|
||||
}
|
||||
|
||||
/* rule container chains */
|
||||
fwd_r_new_chain(h_filter, "mssfix");
|
||||
fwd_r_new_chain(h_filter, "zones");
|
||||
fwd_r_new_chain(h_filter, "rules");
|
||||
fwd_r_new_chain(h_filter, "redirects");
|
||||
fwd_r_new_chain(h_filter, "forwardings");
|
||||
fwd_r_jump_chain(h_filter, "INPUT", "rules");
|
||||
fwd_r_jump_chain(h_filter, "FORWARD", "mssfix");
|
||||
fwd_r_jump_chain(h_filter, "FORWARD", "zones");
|
||||
fwd_r_jump_chain(h_filter, "FORWARD", "rules");
|
||||
fwd_r_jump_chain(h_filter, "FORWARD", "redirects");
|
||||
fwd_r_jump_chain(h_filter, "FORWARD", "forwardings");
|
||||
fwd_r_new_chain(h_nat, "zonemasq");
|
||||
fwd_r_new_chain(h_nat, "redirects");
|
||||
fwd_r_new_chain(h_nat, "loopback");
|
||||
fwd_r_jump_chain(h_nat, "POSTROUTING", "zonemasq");
|
||||
fwd_r_jump_chain(h_nat, "PREROUTING", "redirects");
|
||||
fwd_r_jump_chain(h_nat, "POSTROUTING", "loopback");
|
||||
|
||||
/* standard drop, accept, reject chain */
|
||||
fwd_r_handle_drop(h_filter);
|
||||
fwd_r_handle_accept(h_filter);
|
||||
fwd_r_handle_reject(h_filter);
|
||||
|
||||
|
||||
if( !iptc_commit(h_nat) )
|
||||
fwd_fatal("Cannot commit nat table: %s", iptc_strerror(errno));
|
||||
|
||||
if( !iptc_commit(h_filter) )
|
||||
fwd_fatal("Cannot commit filter table: %s", iptc_strerror(errno));
|
||||
|
||||
iptc_free(h_nat);
|
||||
iptc_free(h_filter);
|
||||
}
|
||||
|
||||
|
||||
void fwd_ipt_build_ruleset(struct fwd_handle *h)
|
||||
{
|
||||
struct fwd_data *e;
|
||||
|
||||
fwd_xt_init();
|
||||
|
||||
for( e = h->conf; e; e = e->next )
|
||||
{
|
||||
switch(e->type)
|
||||
{
|
||||
case FWD_S_DEFAULTS:
|
||||
fwd_log_info("Loading defaults");
|
||||
fwd_ipt_defaults_create(e);
|
||||
break;
|
||||
|
||||
case FWD_S_INCLUDE:
|
||||
fwd_log_info("Loading include: %s",
|
||||
e->section.include.path);
|
||||
break;
|
||||
|
||||
case FWD_S_ZONE:
|
||||
case FWD_S_FORWARD:
|
||||
case FWD_S_REDIRECT:
|
||||
case FWD_S_RULE:
|
||||
/* Make gcc happy */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static struct fwd_zone *
|
||||
fwd_lookup_zone(struct fwd_handle *h, const char *net)
|
||||
{
|
||||
struct fwd_data *e;
|
||||
struct fwd_network *n;
|
||||
|
||||
for( e = h->conf; e; e = e->next )
|
||||
if( e->type == FWD_S_ZONE )
|
||||
for( n = e->section.zone.networks; n; n = n->next )
|
||||
if( !strcmp(n->name, net) )
|
||||
return &e->section.zone;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct fwd_network *
|
||||
fwd_lookup_network(struct fwd_zone *z, const char *net)
|
||||
{
|
||||
struct fwd_network *n;
|
||||
|
||||
for( n = z->networks; n; n = n->next )
|
||||
if( !strcmp(n->name, net) )
|
||||
return n;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void fwd_ipt_addif(struct fwd_handle *h, const char *net)
|
||||
{
|
||||
struct fwd_data *e;
|
||||
struct fwd_zone *z;
|
||||
struct fwd_rule *c;
|
||||
struct fwd_redirect *r;
|
||||
struct fwd_forwarding *f;
|
||||
struct fwd_cidr *a, *a2;
|
||||
struct fwd_network *n, *n2;
|
||||
struct fwd_proto p;
|
||||
|
||||
struct fwd_xt_rule *x;
|
||||
struct xtables_match *m;
|
||||
struct xtables_target *t;
|
||||
|
||||
struct iptc_handle *h_filter, *h_nat;
|
||||
|
||||
if( !(h_filter = iptc_init("filter")) || !(h_nat = iptc_init("nat")) )
|
||||
fwd_fatal("Unable to obtain libiptc handle");
|
||||
|
||||
|
||||
if( !(z = fwd_lookup_zone(h, net)) )
|
||||
return;
|
||||
|
||||
if( !(n = fwd_lookup_network(z, net)) )
|
||||
return;
|
||||
|
||||
if( !(a = n->addr) || fwd_empty_cidr(a) )
|
||||
return;
|
||||
|
||||
|
||||
fwd_log_info("Adding network %s (interface %s)",
|
||||
n->name, n->ifname);
|
||||
|
||||
/* Build masquerading rule */
|
||||
if( z->masq )
|
||||
{
|
||||
if( (x = fwd_xt_init_rule(h_nat)) != NULL )
|
||||
{
|
||||
fwd_xt_parse_out(x, n, 0); /* -o ... */
|
||||
fwd_xt_get_target(x, "MASQUERADE"); /* -j MASQUERADE */
|
||||
fwd_r_add_comment(x, "masq", z, n); /* -m comment ... */
|
||||
fwd_xt_append_rule(x, "zonemasq"); /* -A zonemasq */
|
||||
}
|
||||
}
|
||||
|
||||
/* Build MSS fix rule */
|
||||
if( z->mtu_fix )
|
||||
{
|
||||
if( (x = fwd_xt_init_rule(h_filter)) != NULL )
|
||||
{
|
||||
p.type = FWD_PR_TCP;
|
||||
fwd_xt_parse_out(x, n, 0); /* -o ... */
|
||||
fwd_xt_parse_proto(x, &p, 0); /* -p tcp */
|
||||
|
||||
/* -m tcp --tcp-flags SYN,RST SYN */
|
||||
if( (m = fwd_xt_get_match(x, "tcp")) != NULL )
|
||||
fwd_xt_parse_match(x, m, "--tcp-flags", "SYN,RST", "SYN");
|
||||
|
||||
/* -j TCPMSS --clamp-mss-to-pmtu */
|
||||
if( (t = fwd_xt_get_target(x, "TCPMSS")) != NULL )
|
||||
fwd_xt_parse_target(x, t, "--clamp-mss-to-pmtu");
|
||||
|
||||
/* -m comment ... */
|
||||
fwd_r_add_comment(x, "mssfix", z, n);
|
||||
|
||||
/* -A mssfix */
|
||||
fwd_xt_append_rule(x, "mssfix");
|
||||
}
|
||||
}
|
||||
|
||||
/* Build intra-zone forwarding rules */
|
||||
for( n2 = z->networks; n2; n2 = n2->next )
|
||||
{
|
||||
if( (a2 = n2->addr) != NULL )
|
||||
{
|
||||
if( (x = fwd_xt_init_rule(h_filter)) != NULL )
|
||||
{
|
||||
fwd_xt_parse_in(x, n, 0); /* -i ... */
|
||||
fwd_xt_parse_out(x, n2, 0); /* -o ... */
|
||||
fwd_r_add_policytarget(x, z->forward); /* -j handle_... */
|
||||
fwd_r_add_comment(x, "zone", z, n); /* -m comment ... */
|
||||
fwd_xt_append_rule(x, "zones"); /* -A zones */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Build inter-zone forwarding rules */
|
||||
for( e = z->forwardings; e && (f = &e->section.forwarding); e = e->next )
|
||||
{
|
||||
for( n2 = f->dest->networks; n2; n2 = n2->next )
|
||||
{
|
||||
/* Build forwarding rule */
|
||||
if( (x = fwd_xt_init_rule(h_filter)) != NULL )
|
||||
{
|
||||
fwd_xt_parse_in(x, n, 0); /* -i ... */
|
||||
fwd_xt_parse_out(x, n2, 0); /* -o ... */
|
||||
fwd_r_add_policytarget(x, FWD_P_ACCEPT); /* -j handle_... */
|
||||
fwd_r_add_comment(x, "forward", z, n); /* -m comment ... */
|
||||
fwd_xt_append_rule(x, "forwardings"); /* -A forwardings */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Build DNAT rules */
|
||||
for( e = z->redirects; e && (r = &e->section.redirect); e = e->next )
|
||||
{
|
||||
/* DNAT */
|
||||
if( (x = fwd_xt_init_rule(h_nat)) != NULL )
|
||||
{
|
||||
fwd_xt_parse_in(x, n, 0); /* -i ... */
|
||||
fwd_xt_parse_src(x, r->src_ip, 0); /* -s ... */
|
||||
fwd_xt_parse_dest(x, a, 0); /* -d ... */
|
||||
fwd_xt_parse_proto(x, r->proto, 0); /* -p ... */
|
||||
fwd_r_add_sport(x, r->src_port); /* --sport ... */
|
||||
fwd_r_add_dport(x, r->src_dport); /* --dport ... */
|
||||
fwd_r_add_srcmac(x, r->src_mac); /* -m mac --mac-source ... */
|
||||
fwd_r_add_dnattarget(x, r->dest_ip, r->dest_port); /* -j DNAT ... */
|
||||
fwd_r_add_comment(x, "redir", z, n); /* -m comment ... */
|
||||
fwd_xt_append_rule(x, "redirects"); /* -A redirects */
|
||||
}
|
||||
|
||||
/* Forward */
|
||||
if( (x = fwd_xt_init_rule(h_filter)) != NULL )
|
||||
{
|
||||
fwd_xt_parse_in(x, n, 0); /* -i ... */
|
||||
fwd_xt_parse_src(x, r->src_ip, 0); /* -s ... */
|
||||
fwd_xt_parse_dest(x, r->dest_ip, 0); /* -d ... */
|
||||
fwd_xt_parse_proto(x, r->proto, 0); /* -p ... */
|
||||
fwd_r_add_srcmac(x, r->src_mac); /* -m mac --mac-source ... */
|
||||
fwd_r_add_sport(x, r->src_port); /* --sport ... */
|
||||
fwd_r_add_dport(x, r->dest_port); /* --dport ... */
|
||||
fwd_r_add_policytarget(x, FWD_P_ACCEPT); /* -j handle_accept */
|
||||
fwd_r_add_comment(x, "redir", z, n); /* -m comment ... */
|
||||
fwd_xt_append_rule(x, "redirects"); /* -A redirects */
|
||||
}
|
||||
|
||||
/* Add loopback rule if neither src_ip nor src_mac are defined */
|
||||
if( !r->src_ip && !r->src_mac )
|
||||
{
|
||||
if( (x = fwd_xt_init_rule(h_nat)) != NULL )
|
||||
{
|
||||
fwd_xt_parse_in(x, n, 1); /* -i ! ... */
|
||||
fwd_xt_parse_dest(x, r->dest_ip, 0); /* -d ... */
|
||||
fwd_xt_parse_proto(x, r->proto, 0); /* -p ... */
|
||||
fwd_r_add_sport(x, r->src_port); /* --sport ... */
|
||||
fwd_r_add_dport(x, r->src_dport); /* --dport ... */
|
||||
fwd_xt_get_target(x, "MASQUERADE"); /* -j MASQUERADE */
|
||||
fwd_r_add_comment(x, "redir", z, n); /* -m comment ... */
|
||||
fwd_xt_append_rule(x, "loopback"); /* -A loopback */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Build rules */
|
||||
for( e = z->rules; e && (c = &e->section.rule); e = e->next )
|
||||
{
|
||||
/* Has destination, add forward rule for each network in target zone */
|
||||
if( c->dest )
|
||||
{
|
||||
for( n2 = c->dest->networks; n2; n2 = n2->next )
|
||||
{
|
||||
if( (x = fwd_xt_init_rule(h_filter)) != NULL )
|
||||
{
|
||||
fwd_xt_parse_in(x, n, 0); /* -i ... */
|
||||
fwd_xt_parse_out(x, n2, 0); /* -o ... */
|
||||
fwd_xt_parse_src(x, c->src_ip, 0); /* -s ... */
|
||||
fwd_xt_parse_dest(x, c->dest_ip, 0); /* -d ... */
|
||||
fwd_xt_parse_proto(x, c->proto, 0); /* -p ... */
|
||||
fwd_r_add_icmptype(x, c->icmp_type); /* --icmp-type ... */
|
||||
fwd_r_add_srcmac(x, c->src_mac); /* --mac-source ... */
|
||||
fwd_r_add_sport(x, c->src_port); /* --sport ... */
|
||||
fwd_r_add_dport(x, c->dest_port); /* --dport ... */
|
||||
fwd_r_add_policytarget(x, c->target); /* -j handle_... */
|
||||
fwd_r_add_comment(x, "rule", z, n); /* -m comment ... */
|
||||
fwd_xt_append_rule(x, "rules"); /* -A rules */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* No destination specified, treat it as input rule */
|
||||
else
|
||||
{
|
||||
if( (x = fwd_xt_init_rule(h_filter)) != NULL )
|
||||
{
|
||||
fwd_xt_parse_in(x, n, 0); /* -i ... */
|
||||
fwd_xt_parse_src(x, c->src_ip, 0); /* -s ... */
|
||||
fwd_xt_parse_dest(x, c->dest_ip, 0); /* -d ... */
|
||||
fwd_xt_parse_proto(x, c->proto, 0); /* -p ... */
|
||||
fwd_r_add_icmptype(x, c->icmp_type); /* --icmp-type ... */
|
||||
fwd_r_add_srcmac(x, c->src_mac); /* --mac-source ... */
|
||||
fwd_r_add_sport(x, c->src_port); /* --sport ... */
|
||||
fwd_r_add_dport(x, c->dest_port); /* --dport ... */
|
||||
fwd_r_add_policytarget(x, c->target); /* -j handle_... */
|
||||
fwd_r_add_comment(x, "rule", z, n); /* -m comment ... */
|
||||
fwd_xt_append_rule(x, "rules"); /* -A rules */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( !iptc_commit(h_nat) )
|
||||
fwd_fatal("Cannot commit nat table: %s", iptc_strerror(errno));
|
||||
|
||||
if( !iptc_commit(h_filter) )
|
||||
fwd_fatal("Cannot commit filter table: %s", iptc_strerror(errno));
|
||||
|
||||
iptc_free(h_nat);
|
||||
iptc_free(h_filter);
|
||||
}
|
||||
|
||||
|
||||
static void fwd_ipt_delif_table(struct iptc_handle *h, const char *net)
|
||||
{
|
||||
const struct xt_entry_match *m;
|
||||
const struct ipt_entry *e;
|
||||
const char *chain, *comment;
|
||||
size_t off = 0, num = 0;
|
||||
|
||||
/* iterate chains */
|
||||
for( chain = iptc_first_chain(h); chain;
|
||||
chain = iptc_next_chain(h)
|
||||
) {
|
||||
/* iterate rules */
|
||||
for( e = iptc_first_rule(chain, h), num = 0; e;
|
||||
e = iptc_next_rule(e, h), num++
|
||||
) {
|
||||
repeat_rule:
|
||||
|
||||
/* skip entries w/o matches */
|
||||
if( ! e->target_offset )
|
||||
continue;
|
||||
|
||||
/* iterate matches */
|
||||
for( off = sizeof(struct ipt_entry);
|
||||
off < e->target_offset;
|
||||
off += m->u.match_size
|
||||
) {
|
||||
m = (void *)e + off;
|
||||
|
||||
/* yay */
|
||||
if( ! strcmp(m->u.user.name, "comment") )
|
||||
{
|
||||
/* better use struct_xt_comment_info but well... */
|
||||
comment = (void *)m + sizeof(struct xt_entry_match);
|
||||
|
||||
if( fwd_r_cmp("net=", comment, net) )
|
||||
{
|
||||
e = iptc_next_rule(e, h);
|
||||
iptc_delete_num_entry(chain, num, h);
|
||||
|
||||
if( e != NULL )
|
||||
goto repeat_rule;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void fwd_ipt_delif(struct fwd_handle *h, const char *net)
|
||||
{
|
||||
struct iptc_handle *h_filter, *h_nat;
|
||||
|
||||
if( !(h_filter = iptc_init("filter")) || !(h_nat = iptc_init("nat")) )
|
||||
fwd_fatal("Unable to obtain libiptc handle");
|
||||
|
||||
|
||||
fwd_log_info("Removing network %s", net);
|
||||
|
||||
/* delete network related rules */
|
||||
fwd_ipt_delif_table(h_nat, net);
|
||||
fwd_ipt_delif_table(h_filter, net);
|
||||
|
||||
|
||||
if( !iptc_commit(h_nat) )
|
||||
fwd_fatal("Cannot commit nat table: %s", iptc_strerror(errno));
|
||||
|
||||
if( !iptc_commit(h_filter) )
|
||||
fwd_fatal("Cannot commit filter table: %s", iptc_strerror(errno));
|
||||
|
||||
iptc_free(h_nat);
|
||||
iptc_free(h_filter);
|
||||
}
|
||||
|
||||
void fwd_ipt_chgif(struct fwd_handle *h, const char *net)
|
||||
{
|
||||
/* XXX: should alter rules in-place, tbd */
|
||||
fwd_ipt_delif(h, net);
|
||||
fwd_ipt_addif(h, net);
|
||||
}
|
||||
|
||||
|
||||
static void fwd_ipt_clear_ruleset_table(struct iptc_handle *h)
|
||||
{
|
||||
const char *chain;
|
||||
|
||||
/* pass 1: flush all chains */
|
||||
for( chain = iptc_first_chain(h); chain;
|
||||
chain = iptc_next_chain(h)
|
||||
) {
|
||||
iptc_flush_entries(chain, h);
|
||||
}
|
||||
|
||||
/* pass 2: remove user defined chains */
|
||||
for( chain = iptc_first_chain(h); chain;
|
||||
chain = iptc_next_chain(h)
|
||||
) {
|
||||
if( ! iptc_builtin(chain, h) )
|
||||
iptc_delete_chain(chain, h);
|
||||
}
|
||||
}
|
||||
|
||||
void fwd_ipt_clear_ruleset(struct fwd_handle *h)
|
||||
{
|
||||
struct iptc_handle *h_filter, *h_nat;
|
||||
|
||||
if( !(h_filter = iptc_init("filter")) || !(h_nat = iptc_init("nat")) )
|
||||
fwd_fatal("Unable to obtain libiptc handle");
|
||||
|
||||
/* flush tables */
|
||||
fwd_ipt_clear_ruleset_table(h_nat);
|
||||
fwd_ipt_clear_ruleset_table(h_filter);
|
||||
|
||||
/* revert policies */
|
||||
fwd_r_set_policy(h_filter, "INPUT", "ACCEPT");
|
||||
fwd_r_set_policy(h_filter, "OUTPUT", "ACCEPT");
|
||||
fwd_r_set_policy(h_filter, "FORWARD", "ACCEPT");
|
||||
|
||||
|
||||
if( !iptc_commit(h_nat) )
|
||||
fwd_fatal("Cannot commit nat table: %s", iptc_strerror(errno));
|
||||
|
||||
if( !iptc_commit(h_filter) )
|
||||
fwd_fatal("Cannot commit filter table: %s", iptc_strerror(errno));
|
||||
|
||||
iptc_free(h_nat);
|
||||
iptc_free(h_filter);
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* 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"
|
||||
|
||||
void fwd_ipt_build_ruleset(struct fwd_handle *h);
|
||||
void fwd_ipt_clear_ruleset(struct fwd_handle *h);
|
||||
|
||||
void fwd_ipt_addif(struct fwd_handle *h, const char *net);
|
||||
void fwd_ipt_delif(struct fwd_handle *h, const char *net);
|
||||
void fwd_ipt_chgif(struct fwd_handle *h, const char *net);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
/*
|
||||
* fwd - OpenWrt firewall daemon - commmon utility functions
|
||||
*
|
||||
* 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_utils.h"
|
||||
|
||||
|
||||
void fwd_log_init(void)
|
||||
{
|
||||
openlog("Firewall", 0, LOG_DAEMON | LOG_PERROR);
|
||||
}
|
||||
|
||||
void __fwd_log(int prio, const char *msg, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, msg);
|
||||
vsyslog(prio, msg, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int fwd_empty_cidr(struct fwd_cidr *c)
|
||||
{
|
||||
if( (c == NULL) || ((c->addr.s_addr == 0) && (c->prefix == 0)) )
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fwd_equal_cidr(struct fwd_cidr *a, struct fwd_cidr *b)
|
||||
{
|
||||
if( fwd_empty_cidr(a) && fwd_empty_cidr(b) )
|
||||
return 1;
|
||||
else if( (a->addr.s_addr == b->addr.s_addr) && (a->prefix == b->prefix) )
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void fwd_update_cidr(struct fwd_cidr *a, struct fwd_cidr *b)
|
||||
{
|
||||
if( a != NULL )
|
||||
{
|
||||
a->addr.s_addr = b ? b->addr.s_addr : 0;
|
||||
a->prefix = b ? b->prefix : 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* fwd_zmalloc(size_t)
|
||||
* Allocates a zeroed buffer of the given size. */
|
||||
void * fwd_zmalloc(size_t s)
|
||||
{
|
||||
void *b = malloc(s);
|
||||
|
||||
if( b != NULL )
|
||||
memset(b, 0, s);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
* fwd - OpenWrt firewall daemon - commmon utility header
|
||||
*
|
||||
* 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_UTILS_H__
|
||||
#define __FWD_UTILS_H__
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
#include "fwd.h"
|
||||
|
||||
void fwd_log_init(void);
|
||||
void __fwd_log(int, const char *, ...);
|
||||
#define fwd_log_info(...) __fwd_log(LOG_INFO, __VA_ARGS__)
|
||||
#define fwd_log_err(...) __fwd_log(LOG_ERR, __VA_ARGS__)
|
||||
|
||||
int fwd_empty_cidr(struct fwd_cidr *);
|
||||
int fwd_equal_cidr(struct fwd_cidr *, struct fwd_cidr *);
|
||||
void fwd_update_cidr(struct fwd_cidr *, struct fwd_cidr *);
|
||||
|
||||
/* fwd_zmalloc(size_t)
|
||||
* Allocates a zeroed buffer of the given size. */
|
||||
void * fwd_zmalloc(size_t);
|
||||
|
||||
/* 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
|
||||
|
|
@ -1,412 +0,0 @@
|
|||
/*
|
||||
* fwd - OpenWrt firewall daemon - libiptc/libxtables interface
|
||||
*
|
||||
* 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_xtables.h"
|
||||
#include "fwd_utils.h"
|
||||
|
||||
|
||||
/* Required by certain extensions like SNAT and DNAT */
|
||||
int kernel_version;
|
||||
|
||||
extern void
|
||||
get_kernel_version(void) {
|
||||
static struct utsname uts;
|
||||
int x = 0, y = 0, z = 0;
|
||||
|
||||
if (uname(&uts) == -1) {
|
||||
fprintf(stderr, "Unable to retrieve kernel version.\n");
|
||||
xtables_free_opts(1);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
sscanf(uts.release, "%d.%d.%d", &x, &y, &z);
|
||||
kernel_version = LINUX_VERSION(x, y, z);
|
||||
}
|
||||
|
||||
|
||||
static void xt_exit_error(enum xtables_exittype status, const char *msg, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, msg);
|
||||
vprintf(msg, ap);
|
||||
va_end(ap);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void fwd_xt_init(void)
|
||||
{
|
||||
struct xtables_globals xt_globals = {
|
||||
.option_offset = 0,
|
||||
.program_version = IPTABLES_VERSION,
|
||||
.opts = 0,
|
||||
.orig_opts = 0,
|
||||
.exit_err = (void *)&xt_exit_error,
|
||||
};
|
||||
|
||||
xtables_init();
|
||||
xtables_set_nfproto(NFPROTO_IPV4);
|
||||
xtables_set_params(&xt_globals);
|
||||
}
|
||||
|
||||
|
||||
struct fwd_xt_rule * fwd_xt_init_rule(struct iptc_handle *h)
|
||||
{
|
||||
struct fwd_xt_rule *r;
|
||||
|
||||
if( (r = fwd_alloc_ptr(struct fwd_xt_rule)) != NULL )
|
||||
{
|
||||
if( (r->entry = fwd_alloc_ptr(struct ipt_entry)) != NULL )
|
||||
{
|
||||
r->iptc = h;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
fwd_free_ptr(r);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void fwd_xt_parse_frag(
|
||||
struct fwd_xt_rule *r, int frag, int inv
|
||||
) {
|
||||
if( frag )
|
||||
{
|
||||
r->entry->ip.flags |= IPT_F_FRAG;
|
||||
|
||||
if( inv )
|
||||
r->entry->ip.invflags |= IPT_INV_FRAG;
|
||||
}
|
||||
}
|
||||
|
||||
void fwd_xt_parse_proto(
|
||||
struct fwd_xt_rule *r, struct fwd_proto *p, int inv
|
||||
) {
|
||||
if( p != NULL )
|
||||
{
|
||||
switch(p->type)
|
||||
{
|
||||
case FWD_PR_TCP:
|
||||
r->entry->ip.proto = 6;
|
||||
break;
|
||||
|
||||
case FWD_PR_UDP:
|
||||
r->entry->ip.proto = 17;
|
||||
break;
|
||||
|
||||
case FWD_PR_ICMP:
|
||||
r->entry->ip.proto = 1;
|
||||
break;
|
||||
|
||||
case FWD_PR_CUSTOM:
|
||||
r->entry->ip.proto = p->proto;
|
||||
break;
|
||||
|
||||
case FWD_PR_ALL:
|
||||
case FWD_PR_TCPUDP:
|
||||
r->entry->ip.proto = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if( inv )
|
||||
r->entry->ip.invflags |= IPT_INV_PROTO;
|
||||
}
|
||||
}
|
||||
|
||||
void fwd_xt_parse_in(
|
||||
struct fwd_xt_rule *r, struct fwd_network *n, int inv
|
||||
) {
|
||||
if( n != NULL )
|
||||
{
|
||||
strncpy(r->entry->ip.iniface, n->ifname, IFNAMSIZ);
|
||||
|
||||
if( inv )
|
||||
r->entry->ip.invflags |= IPT_INV_VIA_IN;
|
||||
}
|
||||
}
|
||||
|
||||
void fwd_xt_parse_out(
|
||||
struct fwd_xt_rule *r, struct fwd_network *n, int inv
|
||||
) {
|
||||
if( n != NULL )
|
||||
{
|
||||
strncpy(r->entry->ip.outiface, n->ifname, IFNAMSIZ);
|
||||
|
||||
if( inv )
|
||||
r->entry->ip.invflags |= IPT_INV_VIA_OUT;
|
||||
}
|
||||
}
|
||||
|
||||
void fwd_xt_parse_src(
|
||||
struct fwd_xt_rule *r, struct fwd_cidr *c, int inv
|
||||
) {
|
||||
if( c != NULL )
|
||||
{
|
||||
r->entry->ip.src.s_addr = c->addr.s_addr;
|
||||
r->entry->ip.smsk.s_addr = htonl(~((1 << (32 - c->prefix)) - 1));
|
||||
|
||||
if( inv )
|
||||
r->entry->ip.invflags |= IPT_INV_SRCIP;
|
||||
}
|
||||
}
|
||||
|
||||
void fwd_xt_parse_dest(
|
||||
struct fwd_xt_rule *r, struct fwd_cidr *c, int inv
|
||||
) {
|
||||
if( c != NULL )
|
||||
{
|
||||
r->entry->ip.dst.s_addr = c->addr.s_addr;
|
||||
r->entry->ip.dmsk.s_addr = htonl(~((1 << (32 - c->prefix)) - 1));
|
||||
|
||||
if( inv )
|
||||
r->entry->ip.invflags |= IPT_INV_DSTIP;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct xtables_match * fwd_xt_get_match(
|
||||
struct fwd_xt_rule *r, const char *name
|
||||
) {
|
||||
struct xtables_match *m = xtables_find_match(name, XTF_TRY_LOAD, &r->matches);
|
||||
size_t s;
|
||||
|
||||
if( m != NULL )
|
||||
{
|
||||
s = IPT_ALIGN(sizeof(struct ipt_entry_match)) + m->size;
|
||||
|
||||
if( (m->m = malloc(s)) != NULL )
|
||||
{
|
||||
memset(m->m, 0, s);
|
||||
strcpy(m->m->u.user.name, m->name);
|
||||
m->m->u.match_size = s;
|
||||
|
||||
if( m->init )
|
||||
m->init(m->m);
|
||||
|
||||
return m;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void __fwd_xt_parse_match(
|
||||
struct fwd_xt_rule *r, struct xtables_match *m, ...
|
||||
) {
|
||||
char optc;
|
||||
char *s, **opts;
|
||||
size_t len = 1;
|
||||
int inv = 0;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, m);
|
||||
|
||||
opts = malloc(len * sizeof(*opts));
|
||||
opts[0] = "x";
|
||||
|
||||
while( (s = (char *)va_arg(ap, char *)) != NULL )
|
||||
{
|
||||
opts = realloc(opts, ++len * sizeof(*opts));
|
||||
opts[len-1] = s;
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
|
||||
if( len > 1 )
|
||||
{
|
||||
optind = 0;
|
||||
|
||||
while( (optc = getopt_long(len, opts, "", m->extra_opts, NULL)) > -1 )
|
||||
{
|
||||
if( (optc == '?') && (optarg[0] == '!') && (optarg[1] == '\0') )
|
||||
{
|
||||
inv = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
m->parse(optc, opts, inv, &m->mflags, r->entry, &m->m);
|
||||
inv = 0;
|
||||
}
|
||||
}
|
||||
|
||||
free(opts);
|
||||
}
|
||||
|
||||
|
||||
struct xtables_target * fwd_xt_get_target(
|
||||
struct fwd_xt_rule *r, const char *name
|
||||
) {
|
||||
struct xtables_target *t = xtables_find_target(name, XTF_TRY_LOAD);
|
||||
size_t s;
|
||||
|
||||
if( !t )
|
||||
t = xtables_find_target(IPT_STANDARD_TARGET, XTF_LOAD_MUST_SUCCEED);
|
||||
|
||||
if( t != NULL )
|
||||
{
|
||||
s = IPT_ALIGN(sizeof(struct ipt_entry_target)) + t->size;
|
||||
|
||||
if( (t->t = malloc(s)) != NULL )
|
||||
{
|
||||
memset(t->t, 0, s);
|
||||
strcpy(t->t->u.user.name, name);
|
||||
t->t->u.target_size = s;
|
||||
xtables_set_revision(t->t->u.user.name, t->revision);
|
||||
|
||||
if( t->init )
|
||||
t->init(t->t);
|
||||
|
||||
r->target = t;
|
||||
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void __fwd_xt_parse_target(
|
||||
struct fwd_xt_rule *r, struct xtables_target *t, ...
|
||||
) {
|
||||
char optc;
|
||||
char *s, **opts;
|
||||
size_t len = 1;
|
||||
int inv = 0;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, t);
|
||||
|
||||
opts = malloc(len * sizeof(*opts));
|
||||
opts[0] = "x";
|
||||
|
||||
while( (s = (char *)va_arg(ap, char *)) != NULL )
|
||||
{
|
||||
opts = realloc(opts, ++len * sizeof(*opts));
|
||||
opts[len-1] = s;
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
|
||||
if( len > 1 )
|
||||
{
|
||||
optind = 0;
|
||||
|
||||
while( (optc = getopt_long(len, opts, "", t->extra_opts, NULL)) > -1 )
|
||||
{
|
||||
if( (optc == '?') && (optarg[0] == '!') && (optarg[1] == '\0') )
|
||||
{
|
||||
inv = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
t->parse(optc, opts, inv, &t->tflags, r->entry, &t->t);
|
||||
inv = 0;
|
||||
}
|
||||
}
|
||||
|
||||
free(opts);
|
||||
}
|
||||
|
||||
|
||||
static int fwd_xt_exec_rule(struct fwd_xt_rule *r, const char *chain, int pos)
|
||||
{
|
||||
size_t s;
|
||||
struct xtables_rule_match *m, *next;
|
||||
struct xtables_match *em;
|
||||
struct xtables_target *et;
|
||||
struct ipt_entry *e;
|
||||
int rv = 0;
|
||||
|
||||
s = IPT_ALIGN(sizeof(struct ipt_entry));
|
||||
|
||||
for( m = r->matches; m; m = m->next )
|
||||
s += m->match->m->u.match_size;
|
||||
|
||||
if( (e = malloc(s + r->target->t->u.target_size)) != NULL )
|
||||
{
|
||||
memset(e, 0, s + r->target->t->u.target_size);
|
||||
memcpy(e, r->entry, sizeof(struct ipt_entry));
|
||||
|
||||
e->target_offset = s;
|
||||
e->next_offset = s + r->target->t->u.target_size;
|
||||
|
||||
s = 0;
|
||||
|
||||
for( m = r->matches; m; m = m->next )
|
||||
{
|
||||
memcpy(e->elems + s, m->match->m, m->match->m->u.match_size);
|
||||
s += m->match->m->u.match_size;
|
||||
}
|
||||
|
||||
memcpy(e->elems + s, r->target->t, r->target->t->u.target_size);
|
||||
|
||||
rv = (pos > -1)
|
||||
? iptc_insert_entry(chain, e, (unsigned int) pos, r->iptc)
|
||||
: iptc_append_entry(chain, e, r->iptc)
|
||||
;
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = ENOMEM;
|
||||
}
|
||||
|
||||
|
||||
fwd_free_ptr(e);
|
||||
fwd_free_ptr(r->entry);
|
||||
fwd_free_ptr(r->target->t);
|
||||
|
||||
for( m = r->matches; m; )
|
||||
{
|
||||
next = m->next;
|
||||
fwd_free_ptr(m->match->m);
|
||||
|
||||
if( m->match == m->match->next )
|
||||
fwd_free_ptr(m->match);
|
||||
|
||||
fwd_free_ptr(m);
|
||||
m = next;
|
||||
}
|
||||
|
||||
fwd_free_ptr(r);
|
||||
|
||||
/* reset all targets and matches */
|
||||
for (em = xtables_matches; em; em = em->next)
|
||||
em->mflags = 0;
|
||||
|
||||
for (et = xtables_targets; et; et = et->next)
|
||||
{
|
||||
et->tflags = 0;
|
||||
et->used = 0;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int fwd_xt_insert_rule(
|
||||
struct fwd_xt_rule *r, const char *chain, unsigned int pos
|
||||
) {
|
||||
return fwd_xt_exec_rule(r, chain, pos);
|
||||
}
|
||||
|
||||
int fwd_xt_append_rule(
|
||||
struct fwd_xt_rule *r, const char *chain
|
||||
) {
|
||||
return fwd_xt_exec_rule(r, chain, -1);
|
||||
}
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
/*
|
||||
* fwd - OpenWrt firewall daemon - libiptc/libxtables interface headers
|
||||
*
|
||||
* 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_XTABLES_H__
|
||||
#define __FWD_XTABLES_H__
|
||||
|
||||
#include <iptables.h>
|
||||
#include <xtables.h>
|
||||
#include <libiptc/libxtc.h>
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
|
||||
|
||||
struct fwd_xt_rule {
|
||||
struct iptc_handle *iptc;
|
||||
struct ipt_entry *entry;
|
||||
struct xtables_rule_match *matches;
|
||||
struct xtables_target *target;
|
||||
};
|
||||
|
||||
|
||||
/* Required by certain extensions like SNAT and DNAT */
|
||||
extern int kernel_version;
|
||||
extern void get_kernel_version(void);
|
||||
|
||||
|
||||
void fwd_xt_init(void);
|
||||
|
||||
struct fwd_xt_rule * fwd_xt_init_rule(struct iptc_handle *h);
|
||||
|
||||
void fwd_xt_parse_proto(struct fwd_xt_rule *r, struct fwd_proto *p, int inv);
|
||||
void fwd_xt_parse_in(struct fwd_xt_rule *r, struct fwd_network *n, int inv);
|
||||
void fwd_xt_parse_out(struct fwd_xt_rule *r, struct fwd_network *n, int inv);
|
||||
void fwd_xt_parse_src(struct fwd_xt_rule *r, struct fwd_cidr *c, int inv);
|
||||
void fwd_xt_parse_dest(struct fwd_xt_rule *r, struct fwd_cidr *c, int inv);
|
||||
void fwd_xt_parse_frag(struct fwd_xt_rule *r, int frag, int inv);
|
||||
|
||||
struct xtables_match * fwd_xt_get_match(struct fwd_xt_rule *r, const char *name);
|
||||
void __fwd_xt_parse_match(struct fwd_xt_rule *r, struct xtables_match *m, ...);
|
||||
#define fwd_xt_parse_match(r, m, ...) __fwd_xt_parse_match(r, m, __VA_ARGS__, NULL)
|
||||
|
||||
struct xtables_target * fwd_xt_get_target(struct fwd_xt_rule *r, const char *name);
|
||||
void __fwd_xt_parse_target(struct fwd_xt_rule *r, struct xtables_target *t, ...);
|
||||
#define fwd_xt_parse_target(r, t, ...) __fwd_xt_parse_target(r, t, __VA_ARGS__, NULL)
|
||||
|
||||
int fwd_xt_append_rule(struct fwd_xt_rule *r, const char *chain);
|
||||
int fwd_xt_insert_rule(struct fwd_xt_rule *r, const char *chain, unsigned int pos);
|
||||
|
||||
#endif
|
|
@ -1,236 +0,0 @@
|
|||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
GCC := gcc
|
||||
CFLAGS := -Wall
|
||||
LDFLAGS :=
|
||||
|
||||
OBJ = cli.o lar.o md5.o
|
||||
BIN = lar
|
||||
|
||||
compile:
|
||||
cli: $(OBJ)
|
||||
$(GCC) $(CFLAGS) -o $(BIN) $(OBJ) $(LDFLAGS)
|
||||
|
||||
clean:
|
||||
rm -f $(OBJ) $(BIN)
|
|
@ -1,131 +0,0 @@
|
|||
#include "lar.h"
|
||||
|
||||
int do_print_member( lar_archive *ar, const char *name )
|
||||
{
|
||||
lar_member *member;
|
||||
|
||||
if( (member = lar_open_member(ar, name)) != NULL )
|
||||
{
|
||||
write(fileno(stdout), member->data, member->length);
|
||||
lar_close_member(member);
|
||||
}
|
||||
else
|
||||
LAR_DIE("Unable to locate archive member");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_print_index( lar_archive *ar )
|
||||
{
|
||||
lar_index *index = ar->index;
|
||||
|
||||
if( ar->has_filenames )
|
||||
{
|
||||
while(index)
|
||||
{
|
||||
if( index->type == LAR_TYPE_REGULAR )
|
||||
{
|
||||
printf("%s\n", index->filename);
|
||||
}
|
||||
|
||||
index = index->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LAR_DIE("The archive contains no file list");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int do_require( const char *package, const char *path )
|
||||
{
|
||||
int stat = 1;
|
||||
lar_archive *ar;
|
||||
lar_member *mb;
|
||||
|
||||
if( (ar = lar_find_archive(package, path, 1)) != NULL )
|
||||
{
|
||||
if( (mb = lar_find_member(ar, package)) != NULL )
|
||||
{
|
||||
write(fileno(stdout), mb->data, mb->length);
|
||||
lar_close_member(mb);
|
||||
stat = 0;
|
||||
}
|
||||
|
||||
lar_close(ar);
|
||||
}
|
||||
|
||||
return stat;
|
||||
}
|
||||
|
||||
int do_findfile( const char *filename, const char *path )
|
||||
{
|
||||
int stat = 1;
|
||||
lar_archive *ar;
|
||||
lar_member *mb;
|
||||
|
||||
if( (ar = lar_find_archive(filename, path, 0)) != NULL )
|
||||
{
|
||||
if( (mb = lar_open_member(ar, filename)) != NULL )
|
||||
{
|
||||
write(fileno(stdout), mb->data, mb->length);
|
||||
lar_close_member(mb);
|
||||
stat = 0;
|
||||
}
|
||||
|
||||
lar_close(ar);
|
||||
}
|
||||
|
||||
return stat;
|
||||
}
|
||||
|
||||
int main( int argc, const char* argv[] )
|
||||
{
|
||||
lar_archive *ar;
|
||||
int stat = 0;
|
||||
|
||||
if( argv[1] != NULL && argv[2] != NULL )
|
||||
{
|
||||
switch(argv[1][0])
|
||||
{
|
||||
case 's':
|
||||
if( (ar = lar_open(argv[2])) != NULL )
|
||||
{
|
||||
if( argv[3] != NULL )
|
||||
stat = do_print_member(ar, argv[3]);
|
||||
else
|
||||
stat = do_print_index(ar);
|
||||
|
||||
lar_close(ar);
|
||||
}
|
||||
else
|
||||
{
|
||||
LAR_DIE("Failed to open archive");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
stat = do_require(argv[2], argv[3]);
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
stat = do_findfile(argv[2], argv[3]);
|
||||
break;
|
||||
}
|
||||
|
||||
return stat;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Usage:\n");
|
||||
printf("\tlar show <archive> [<member>]\n");
|
||||
printf("\tlar require <package> [<path>]\n");
|
||||
printf("\tlar find <filename> [<path>]\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,328 +0,0 @@
|
|||
/*
|
||||
* lar - Lua Archive Library
|
||||
*
|
||||
* Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#include "lar.h"
|
||||
|
||||
static int lar_read32( int fd, uint32_t *val )
|
||||
{
|
||||
uint8_t buffer[5];
|
||||
|
||||
if( read(fd, buffer, 4) < 4 )
|
||||
LAR_DIE("Unexpected EOF while reading data");
|
||||
|
||||
buffer[4] = 0;
|
||||
*val = ntohl(*((uint32_t *) buffer));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lar_read16( int fd, uint16_t *val )
|
||||
{
|
||||
uint8_t buffer[3];
|
||||
|
||||
if( read(fd, buffer, 2) < 2 )
|
||||
LAR_DIE("Unexpected EOF while reading data");
|
||||
|
||||
buffer[2] = 0;
|
||||
*val = ntohs(*((uint16_t *) buffer));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lar_md5( char *md5, const char *data, int len )
|
||||
{
|
||||
md5_state_t state;
|
||||
|
||||
md5_init(&state);
|
||||
md5_append(&state, (const md5_byte_t *)data, len);
|
||||
md5_finish(&state, (md5_byte_t *)md5);
|
||||
}
|
||||
|
||||
static int lar_read_filenames( lar_archive *ar )
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
char *filelist;
|
||||
size_t pgof;
|
||||
size_t pgsz = getpagesize();
|
||||
lar_index *idx_ptr;
|
||||
lar_index *idx_filelist = ar->index;
|
||||
|
||||
while(idx_filelist)
|
||||
{
|
||||
if( idx_filelist->type == LAR_TYPE_FILELIST )
|
||||
break;
|
||||
|
||||
idx_filelist = idx_filelist->next;
|
||||
}
|
||||
|
||||
if( idx_filelist != NULL )
|
||||
{
|
||||
pgof = ( idx_filelist->offset % pgsz );
|
||||
|
||||
filelist = mmap(
|
||||
0, idx_filelist->length + pgof, PROT_READ, MAP_PRIVATE,
|
||||
ar->fd, idx_filelist->offset - pgof
|
||||
);
|
||||
|
||||
if( filelist == MAP_FAILED )
|
||||
LAR_DIE("Failed to mmap() file list");
|
||||
|
||||
|
||||
idx_ptr = ar->index;
|
||||
i = pgof;
|
||||
|
||||
while(idx_ptr)
|
||||
{
|
||||
if( idx_ptr->type == LAR_TYPE_REGULAR )
|
||||
{
|
||||
j = strlen(&filelist[i]) + 1;
|
||||
|
||||
if( (j >= LAR_FNAME_BUFFER) ||
|
||||
((i+j) > (idx_filelist->length+pgof)) )
|
||||
LAR_DIE("Filename exceeds maximum allowed length");
|
||||
|
||||
idx_ptr->filename = (char *)malloc(j);
|
||||
memcpy(idx_ptr->filename, &filelist[i], j);
|
||||
|
||||
i += j;
|
||||
}
|
||||
|
||||
idx_ptr = idx_ptr->next;
|
||||
}
|
||||
|
||||
munmap(filelist, idx_filelist->length + pgof);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
lar_index * lar_get_index( lar_archive *ar )
|
||||
{
|
||||
uint32_t i;
|
||||
uint32_t idx_offset;
|
||||
uint32_t idx_length;
|
||||
lar_index *idx_map;
|
||||
lar_index *idx_ptr;
|
||||
|
||||
if( lseek(ar->fd, -(sizeof(idx_offset)), SEEK_END) == -1 )
|
||||
LAR_DIE("Unable to seek to end of archive");
|
||||
|
||||
lar_read32(ar->fd, &idx_offset);
|
||||
idx_length = ( ar->length - idx_offset - sizeof(idx_offset) );
|
||||
|
||||
if( lseek(ar->fd, idx_offset, SEEK_SET) == -1 )
|
||||
LAR_DIE("Unable to seek to archive index");
|
||||
|
||||
|
||||
idx_map = NULL;
|
||||
|
||||
for( i = 0; i < idx_length; i += (sizeof(lar_index) - 2 * sizeof(char *)) )
|
||||
{
|
||||
idx_ptr = (lar_index *)malloc(sizeof(lar_index));
|
||||
idx_ptr->filename = NULL;
|
||||
|
||||
lar_read32(ar->fd, &idx_ptr->offset);
|
||||
lar_read32(ar->fd, &idx_ptr->length);
|
||||
lar_read16(ar->fd, &idx_ptr->type);
|
||||
lar_read16(ar->fd, &idx_ptr->flags);
|
||||
|
||||
if(read(ar->fd,&idx_ptr->id,sizeof(idx_ptr->id)) < sizeof(idx_ptr->id))
|
||||
LAR_DIE("Unexpected EOF while reading member id");
|
||||
|
||||
idx_ptr->next = idx_map;
|
||||
idx_map = idx_ptr;
|
||||
}
|
||||
|
||||
return idx_map;
|
||||
}
|
||||
|
||||
lar_member * lar_mmap_member( lar_archive *ar, lar_index *idx_ptr )
|
||||
{
|
||||
lar_member *member;
|
||||
size_t pgsz = getpagesize();
|
||||
size_t pgof = ( idx_ptr->offset % pgsz );
|
||||
|
||||
char *memberdata = mmap(
|
||||
0, idx_ptr->length + pgof, PROT_READ, MAP_PRIVATE,
|
||||
ar->fd, idx_ptr->offset - pgof
|
||||
);
|
||||
|
||||
if( memberdata == MAP_FAILED )
|
||||
LAR_DIE("Failed to mmap() member data");
|
||||
|
||||
member = (lar_member *)malloc(sizeof(lar_member));
|
||||
member->type = idx_ptr->type;
|
||||
member->flags = idx_ptr->flags;
|
||||
member->length = idx_ptr->length;
|
||||
member->data = &memberdata[pgof];
|
||||
|
||||
member->mmap = memberdata;
|
||||
member->mlen = idx_ptr->length + pgof;
|
||||
|
||||
return member;
|
||||
}
|
||||
|
||||
lar_member * lar_open_member( lar_archive *ar, const char *name )
|
||||
{
|
||||
lar_index *idx_ptr = ar->index;
|
||||
char mbid[sizeof(idx_ptr->id)];
|
||||
|
||||
lar_md5(mbid, name, strlen(name));
|
||||
|
||||
while(idx_ptr)
|
||||
{
|
||||
if( !strncmp(mbid, idx_ptr->id, sizeof(mbid)) )
|
||||
return lar_mmap_member(ar, idx_ptr);
|
||||
|
||||
idx_ptr = idx_ptr->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int lar_close_member( lar_member *member )
|
||||
{
|
||||
int stat = munmap(member->mmap, member->mlen);
|
||||
free(member);
|
||||
member = NULL;
|
||||
|
||||
return stat;
|
||||
}
|
||||
|
||||
lar_archive * lar_open( const char *filename )
|
||||
{
|
||||
int fd;
|
||||
struct stat as;
|
||||
lar_archive *ar;
|
||||
|
||||
if( stat(filename, &as) == -1 )
|
||||
return NULL;
|
||||
|
||||
if( !(as.st_mode & S_IFREG) )
|
||||
return NULL;
|
||||
|
||||
if( (fd = open(filename, O_RDONLY)) != -1 )
|
||||
{
|
||||
ar = (lar_archive *)malloc(sizeof(lar_archive));
|
||||
ar->fd = fd;
|
||||
ar->length = as.st_size;
|
||||
ar->index = lar_get_index(ar);
|
||||
strncpy(ar->filename, filename, sizeof(ar->filename));
|
||||
|
||||
ar->has_filenames = lar_read_filenames(ar);
|
||||
|
||||
return ar;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int lar_close( lar_archive *ar )
|
||||
{
|
||||
lar_index *idx_head;
|
||||
lar_index *idx_next;
|
||||
|
||||
close(ar->fd);
|
||||
|
||||
idx_head = ar->index;
|
||||
do {
|
||||
idx_next = idx_head->next;
|
||||
free(idx_head->filename);
|
||||
free(idx_head);
|
||||
} while( (idx_head = idx_next) != NULL );
|
||||
|
||||
free(ar);
|
||||
ar = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
lar_archive * lar_find_archive( const char *package, const char *path, int pkg )
|
||||
{
|
||||
uint32_t i;
|
||||
uint32_t j;
|
||||
uint32_t seg = 1;
|
||||
uint32_t len = 0;
|
||||
uint32_t pln = 0;
|
||||
char sep = ( pkg ? '.' : '/' );
|
||||
struct stat s;
|
||||
LAR_FNAME(buffer);
|
||||
|
||||
if( path )
|
||||
{
|
||||
for( pln = 0; path[pln] != '\0'; pln++ )
|
||||
if( pln >= (sizeof(buffer) - 5) )
|
||||
LAR_DIE("Library path exceeds maximum allowed length");
|
||||
|
||||
memcpy(buffer, path, pln);
|
||||
}
|
||||
|
||||
if( buffer[pln-1] != '/' )
|
||||
buffer[pln++] = '/';
|
||||
|
||||
for( len = 0; package[len] != '\0'; len++ )
|
||||
{
|
||||
if( len >= (sizeof(buffer) - 5 - pln) )
|
||||
LAR_DIE("Package name exceeds maximum allowed length");
|
||||
|
||||
if( package[len] == sep ) seg++;
|
||||
}
|
||||
|
||||
while( seg > 0 )
|
||||
{
|
||||
for( i = 0, j = 1; (i < len) && (j <= seg); i++ )
|
||||
{
|
||||
if( package[i] == sep ) {
|
||||
if( j < seg ) j++; else break;
|
||||
}
|
||||
|
||||
buffer[pln+i] = ( package[i] == sep ) ? LAR_DIRSEP : package[i];
|
||||
}
|
||||
|
||||
strcpy(&buffer[pln+i], ".lar");
|
||||
|
||||
if( (stat(buffer, &s) > -1) && (s.st_mode & S_IFREG) )
|
||||
return lar_open(buffer);
|
||||
|
||||
seg--;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lar_member * lar_find_member( lar_archive *ar, const char *package )
|
||||
{
|
||||
int len;
|
||||
LAR_FNAME(buffer);
|
||||
|
||||
for( len = 0; package[len] != '\0'; len++ )
|
||||
{
|
||||
if( len >= (sizeof(buffer) - 5) )
|
||||
LAR_DIE("Package name exceeds maximum allowed length");
|
||||
|
||||
buffer[len] = ( package[len] == '.' ) ? '/' : package[len];
|
||||
}
|
||||
|
||||
strcpy(&buffer[len], ".lua");
|
||||
|
||||
return lar_open_member(ar, buffer);
|
||||
}
|
|
@ -1,108 +0,0 @@
|
|||
/*
|
||||
* lar - Lua Archive Library
|
||||
*
|
||||
* Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __LAR_H
|
||||
#define __LAR_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "md5.h"
|
||||
|
||||
#define LAR_DIE(s) \
|
||||
do { \
|
||||
fprintf(stderr, "%s(%i): %s(): %s\n", \
|
||||
__FILE__, __LINE__, __FUNCTION__, s); \
|
||||
if( errno ) fprintf(stderr, "%s(%i): %s\n", \
|
||||
__FILE__, __LINE__, strerror(errno) ); \
|
||||
exit(1); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LAR_FNAME_BUFFER 1024
|
||||
#define LAR_FNAME(s) char s[LAR_FNAME_BUFFER]
|
||||
|
||||
#define LAR_TYPE_REGULAR 0x0000
|
||||
#define LAR_TYPE_FILELIST 0xFFFF
|
||||
|
||||
#ifdef __WIN32__
|
||||
#define LAR_DIRSEP '\\'
|
||||
#else
|
||||
#define LAR_DIRSEP '/'
|
||||
#endif
|
||||
|
||||
|
||||
struct lar_index_item {
|
||||
uint32_t offset;
|
||||
uint32_t length;
|
||||
uint16_t type;
|
||||
uint16_t flags;
|
||||
char id[16];
|
||||
char *filename;
|
||||
struct lar_index_item *next;
|
||||
};
|
||||
|
||||
struct lar_member_item {
|
||||
uint16_t type;
|
||||
uint16_t flags;
|
||||
uint32_t length;
|
||||
char *data;
|
||||
char *mmap;
|
||||
size_t mlen;
|
||||
};
|
||||
|
||||
struct lar_archive_handle {
|
||||
int fd;
|
||||
int has_filenames;
|
||||
off_t length;
|
||||
char filename[LAR_FNAME_BUFFER];
|
||||
struct lar_index_item *index;
|
||||
};
|
||||
|
||||
typedef struct lar_index_item lar_index;
|
||||
typedef struct lar_member_item lar_member;
|
||||
typedef struct lar_archive_handle lar_archive;
|
||||
|
||||
|
||||
lar_index * lar_get_index( lar_archive *ar );
|
||||
|
||||
lar_member * lar_mmap_member( lar_archive *ar, lar_index *idx_ptr );
|
||||
|
||||
lar_member * lar_open_member( lar_archive *ar, const char *name );
|
||||
|
||||
int lar_close_member( lar_member *member );
|
||||
|
||||
lar_archive * lar_open( const char *filename );
|
||||
|
||||
int lar_close( lar_archive *ar );
|
||||
|
||||
lar_archive * lar_find_archive( const char *package, const char *path, int pkg);
|
||||
|
||||
lar_member * lar_find_member( lar_archive *ar, const char *package );
|
||||
|
||||
#endif
|
|
@ -1,50 +0,0 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
|
||||
@ARGV || die "Usage: $0 <file1> <file2> ... <fileN>\n";
|
||||
|
||||
my @index;
|
||||
my $offset = 0;
|
||||
|
||||
foreach my $file ( @ARGV )
|
||||
{
|
||||
if( -f $file && open F, "< $file" )
|
||||
{
|
||||
warn sprintf "Member at 0x%08X\n", $offset;
|
||||
push @index, [ ];
|
||||
|
||||
my $size = length $file;
|
||||
|
||||
print $file;
|
||||
print "\0" x ( $size % 4 );
|
||||
|
||||
$index[-1][0] = $offset;
|
||||
$index[-1][1] = $size;
|
||||
$index[-1][2] = $offset + $size + ( $size % 4 );
|
||||
|
||||
|
||||
$size = 0;
|
||||
while( read F, my $buffer, 4096 ) {
|
||||
$size += length $buffer;
|
||||
print $buffer;
|
||||
}
|
||||
print "\0" x ( $size % 4 );
|
||||
|
||||
$index[-1][3] = $size;
|
||||
$offset = $index[-1][2] + $size + ( $size % 4 );
|
||||
|
||||
close F;
|
||||
}
|
||||
}
|
||||
|
||||
my $count = 1;
|
||||
foreach my $file ( @index )
|
||||
{
|
||||
warn sprintf "Index[%4d]: 0x%08X 0x%08X 0x%08X 0x%08X\n", $count++, $file->[0], $file->[1], $file->[2], $file->[3];
|
||||
print pack "NNNNnn", $file->[0], $file->[1], $file->[2], $file->[3], 0x0000, 0x0000;
|
||||
}
|
||||
|
||||
warn sprintf "Index at 0x%08X, length 0x%08X\n", $offset, @index * 20;
|
||||
print pack "N", $offset;
|
||||
|
|
@ -1,540 +0,0 @@
|
|||
/*
|
||||
* lar - Lua Archive Library
|
||||
*
|
||||
* Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#include "lua.h"
|
||||
#include "lualib.h"
|
||||
#include "lauxlib.h"
|
||||
#include "lar.h"
|
||||
|
||||
typedef struct {
|
||||
int fd;
|
||||
char *data;
|
||||
size_t length;
|
||||
} mmap_handle;
|
||||
|
||||
static int larlib_perror( lua_State *L, const char *message )
|
||||
{
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, message);
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
int larlib_open( lua_State *L )
|
||||
{
|
||||
lar_archive *ar, **udata;
|
||||
const char *filename = luaL_checkstring( L, 1 );
|
||||
|
||||
if( filename != NULL && (ar = lar_open(filename)) != NULL )
|
||||
{
|
||||
if( (udata = lua_newuserdata(L, sizeof(lar_archive *))) != NULL )
|
||||
{
|
||||
*udata = ar;
|
||||
luaL_getmetatable(L, "lar.archive");
|
||||
lua_setmetatable(L, -2);
|
||||
}
|
||||
else
|
||||
{
|
||||
return luaL_error(L, "Out of memory");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return larlib_perror(L, "Archive not found");
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int larlib_find( lua_State *L )
|
||||
{
|
||||
const char *filename = luaL_checkstring( L, 1 );
|
||||
const char *basepath = luaL_optstring( L, 2, "./" );
|
||||
int is_pkg = strstr(filename, "/") ? 0 : 1;
|
||||
lar_archive *ar, **udata;
|
||||
|
||||
if( ((ar = lar_find_archive(filename, basepath, is_pkg)) != NULL) ||
|
||||
((ar = lar_find_archive(filename, LUA_LDIR, is_pkg)) != NULL) ||
|
||||
((ar = lar_find_archive(filename, LUA_CDIR, is_pkg)) != NULL) )
|
||||
{
|
||||
if( (udata = lua_newuserdata(L, sizeof(lar_archive *))) != NULL )
|
||||
{
|
||||
*udata = ar;
|
||||
luaL_getmetatable(L, "lar.archive");
|
||||
lua_setmetatable(L, -2);
|
||||
}
|
||||
else
|
||||
{
|
||||
return luaL_error(L, "Out of memory");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return larlib_perror(L, "Archive not found");
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int larlib_md5( lua_State *L )
|
||||
{
|
||||
int i;
|
||||
char md5[16], md5_hex[33];
|
||||
const char *data = luaL_checkstring( L, 1 );
|
||||
md5_state_t state;
|
||||
|
||||
md5_init(&state);
|
||||
md5_append(&state, (const md5_byte_t *)data, strlen(data));
|
||||
md5_finish(&state, (md5_byte_t *)md5);
|
||||
|
||||
for( i = 0; i < 16; i++ )
|
||||
sprintf(&md5_hex[i*2], "%02x", (unsigned char)md5[i]);
|
||||
|
||||
lua_pushstring(L, md5_hex);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int larlib_md5_file( lua_State *L )
|
||||
{
|
||||
int i, fd, len;
|
||||
char md5[16], md5_hex[33], buffer[1024];
|
||||
const char *filename = luaL_checkstring( L, 1 );
|
||||
md5_state_t state;
|
||||
|
||||
if( (fd = open(filename, O_RDONLY)) != -1 )
|
||||
{
|
||||
md5_init(&state);
|
||||
|
||||
while( (len = read(fd, buffer, 1024)) > 0 )
|
||||
md5_append(&state, (const md5_byte_t *)buffer, len);
|
||||
|
||||
md5_finish(&state, (md5_byte_t *)md5);
|
||||
|
||||
for( i = 0; i < 16; i++ )
|
||||
sprintf(&md5_hex[i*2], "%02x", (unsigned char)md5[i]);
|
||||
|
||||
close(fd);
|
||||
lua_pushstring(L, md5_hex);
|
||||
}
|
||||
else
|
||||
{
|
||||
return larlib_perror(L, strerror(errno));
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int larlib_mkpath( const char *name, const char *path, char *buffer )
|
||||
{
|
||||
int nlen = strlen(name);
|
||||
int plen = strlen(path);
|
||||
|
||||
if( (nlen + plen + 1) <= LAR_FNAME_BUFFER )
|
||||
{
|
||||
strcpy(buffer, path);
|
||||
|
||||
if( buffer[plen-1] != '/' )
|
||||
buffer[plen++] = '/';
|
||||
|
||||
strcpy(&buffer[plen], name);
|
||||
buffer[plen + nlen] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int larlib__gc( lua_State *L )
|
||||
{
|
||||
lar_archive **archive = luaL_checkudata( L, 1, "lar.archive" );
|
||||
|
||||
if( *archive )
|
||||
lar_close(*archive);
|
||||
|
||||
*archive = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int larlib_member__open( lua_State *L, lar_member *mb )
|
||||
{
|
||||
lar_archive **archive = NULL;
|
||||
const char *filename = NULL;
|
||||
lar_member **udata;
|
||||
|
||||
if( mb == NULL )
|
||||
{
|
||||
*archive = luaL_checkudata( L, 1, "lar.archive" );
|
||||
filename = luaL_checkstring( L, 2 );
|
||||
}
|
||||
|
||||
if( mb != NULL || (mb = lar_open_member(*archive, filename)) != NULL )
|
||||
{
|
||||
if( (udata = lua_newuserdata(L, sizeof(lar_member *))) != NULL )
|
||||
{
|
||||
*udata = mb;
|
||||
luaL_getmetatable(L, "lar.member");
|
||||
lua_setmetatable(L, -2);
|
||||
}
|
||||
else
|
||||
{
|
||||
return luaL_error(L, "Out of memory");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return larlib_perror(L, "Member not found in archive");
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int larlib_member_open( lua_State *L )
|
||||
{
|
||||
return larlib_member__open( L, NULL );
|
||||
}
|
||||
|
||||
int larlib_member_find( lua_State *L )
|
||||
{
|
||||
lar_archive **archive = luaL_checkudata( L, 1, "lar.archive" );
|
||||
const char *package = luaL_checkstring( L, 2 );
|
||||
lar_member *mb, **udata;
|
||||
|
||||
if( (mb = lar_find_member(*archive, package)) != NULL )
|
||||
{
|
||||
if( (udata = lua_newuserdata(L, sizeof(lar_member *))) != NULL )
|
||||
{
|
||||
*udata = mb;
|
||||
luaL_getmetatable(L, "lar.member");
|
||||
lua_setmetatable(L, -2);
|
||||
}
|
||||
else
|
||||
{
|
||||
return luaL_error(L, "Out of memory");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return larlib_perror(L, "Member not found in archive");
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int larlib_member_size( lua_State *L )
|
||||
{
|
||||
lar_member **member = luaL_checkudata( L, 1, "lar.member" );
|
||||
lua_pushnumber(L, (*member)->length);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int larlib_member_type( lua_State *L )
|
||||
{
|
||||
lar_member **member = luaL_checkudata( L, 1, "lar.member" );
|
||||
lua_pushnumber(L, (*member)->type);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int larlib_member_flags( lua_State *L )
|
||||
{
|
||||
lar_member **member = luaL_checkudata( L, 1, "lar.member" );
|
||||
lua_pushnumber(L, (*member)->flags);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int larlib_member_read( lua_State *L )
|
||||
{
|
||||
lar_member **member = luaL_checkudata( L, 1, "lar.member" );
|
||||
int start = luaL_checknumber( L, 2 );
|
||||
int length = luaL_optnumber( L, 3, (*member)->length );
|
||||
char *stringcopy;
|
||||
|
||||
if( (start >= 0) && (start < (*member)->length) && (length > 0) )
|
||||
{
|
||||
if( (start + length) >= (*member)->length )
|
||||
length = (*member)->length - start;
|
||||
|
||||
if( (stringcopy = (char *)malloc(length + 1)) != NULL )
|
||||
{
|
||||
memcpy(stringcopy, &(*member)->data[start], length);
|
||||
stringcopy[length] = '\0';
|
||||
lua_pushstring(L, stringcopy);
|
||||
free(stringcopy);
|
||||
}
|
||||
else
|
||||
{
|
||||
return luaL_error(L, "Out of memory");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return larlib_perror(L, "Invalid argument");
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int larlib_member_data( lua_State *L )
|
||||
{
|
||||
lar_member **member = luaL_checkudata( L, 1, "lar.member" );
|
||||
lua_pushstring(L, (*member)->data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int larlib_member_load( lua_State *L )
|
||||
{
|
||||
lar_member **member = luaL_checkudata( L, 1, "lar.member" );
|
||||
int status = luaL_loadbuffer( L, (*member)->data, (*member)->length,
|
||||
"=(lar member)" );
|
||||
|
||||
if( status )
|
||||
{
|
||||
lua_pushnil(L);
|
||||
lua_insert(L, -2);
|
||||
return 2;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int larlib_member__gc( lua_State *L )
|
||||
{
|
||||
lar_member **member = luaL_checkudata( L, 1, "lar.member" );
|
||||
|
||||
if( *member )
|
||||
lar_close_member(*member);
|
||||
|
||||
*member = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int larlib_mmfile__open( lua_State *L, const char *filename )
|
||||
{
|
||||
struct stat s;
|
||||
mmap_handle *fh, **udata;
|
||||
|
||||
if( filename == NULL )
|
||||
filename = (const char *)luaL_checkstring( L, 1 );
|
||||
|
||||
if( (fh = (mmap_handle *)malloc(sizeof(mmap_handle))) == NULL )
|
||||
return larlib_perror(L, "Out of memory");
|
||||
|
||||
if( stat(filename, &s) > -1 && (fh->fd = open(filename, O_RDONLY)) > -1 )
|
||||
{
|
||||
fh->length = s.st_size;
|
||||
fh->data = mmap( 0, s.st_size, PROT_READ, MAP_PRIVATE, fh->fd, 0 );
|
||||
|
||||
if( fh->data == MAP_FAILED )
|
||||
return larlib_perror(L, "Failed to mmap() file");
|
||||
|
||||
if( (udata = lua_newuserdata(L, sizeof(char *))) != NULL )
|
||||
{
|
||||
*udata = fh;
|
||||
luaL_getmetatable(L, "lar.mmfile");
|
||||
lua_setmetatable(L, -2);
|
||||
}
|
||||
else
|
||||
{
|
||||
return larlib_perror(L, "Out of memory");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return larlib_perror(L, strerror(errno));
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int larlib_mmfile_open( lua_State *L )
|
||||
{
|
||||
return larlib_mmfile__open(L, NULL);
|
||||
}
|
||||
|
||||
int larlib_mmfile_size( lua_State *L )
|
||||
{
|
||||
mmap_handle **fh = luaL_checkudata( L, 1, "lar.mmfile" );
|
||||
lua_pushnumber(L, (*fh)->length);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int larlib_mmfile_read( lua_State *L )
|
||||
{
|
||||
mmap_handle **fh = luaL_checkudata( L, 1, "lar.mmfile" );
|
||||
int start = luaL_checknumber( L, 2 );
|
||||
int length = luaL_optnumber( L, 3, (*fh)->length );
|
||||
char *stringcopy;
|
||||
|
||||
if( (start >= 0) && (start < (*fh)->length) && (length > 0) )
|
||||
{
|
||||
if( (start + length) >= (*fh)->length )
|
||||
length = (*fh)->length - start;
|
||||
|
||||
if( (stringcopy = (char *)malloc(length + 1)) != NULL )
|
||||
{
|
||||
memcpy(stringcopy, &(*fh)->data[start], length);
|
||||
stringcopy[length] = '\0';
|
||||
lua_pushstring(L, stringcopy);
|
||||
free(stringcopy);
|
||||
}
|
||||
else
|
||||
{
|
||||
return luaL_error(L, "Out of memory");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return larlib_perror(L, "Invalid argument");
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int larlib_mmfile_data( lua_State *L )
|
||||
{
|
||||
mmap_handle **fh = luaL_checkudata( L, 1, "lar.mmfile" );
|
||||
lua_pushstring(L, (*fh)->data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int larlib_mmfile_load( lua_State *L )
|
||||
{
|
||||
mmap_handle **fh = luaL_checkudata( L, 1, "lar.mmfile" );
|
||||
int status = luaL_loadbuffer(L, (*fh)->data, (*fh)->length, "=(mmap file)");
|
||||
|
||||
if( status )
|
||||
{
|
||||
lua_pushnil(L);
|
||||
lua_insert(L, -2);
|
||||
return 2;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int larlib_mmfile__gc( lua_State *L )
|
||||
{
|
||||
mmap_handle **fh = luaL_checkudata( L, 1, "lar.mmfile" );
|
||||
|
||||
if( *fh )
|
||||
{
|
||||
close((*fh)->fd);
|
||||
munmap((*fh)->data, (*fh)->length);
|
||||
free(*fh);
|
||||
*fh = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int larlib_findfile( lua_State *L )
|
||||
{
|
||||
int i;
|
||||
const char *filename = luaL_checkstring( L, 1 );
|
||||
const char *basepath = luaL_optstring( L, 2, "./" );
|
||||
struct stat s;
|
||||
lar_archive *ar;
|
||||
lar_member *mb;
|
||||
LAR_FNAME(filepath);
|
||||
|
||||
const char *searchpath[3] = { basepath, LUA_LDIR, LUA_CDIR };
|
||||
|
||||
for( i = 0; i < 3; i++ )
|
||||
if( !larlib_mkpath(filename, searchpath[i], filepath) )
|
||||
if( stat(filepath, &s) > -1 && (s.st_mode & S_IFREG) )
|
||||
return larlib_mmfile__open( L, filepath );
|
||||
|
||||
for( i = 0; i < 3; i++ )
|
||||
if( (ar = lar_find_archive(filename, searchpath[i], 0)) != NULL )
|
||||
if( (mb = lar_open_member(ar, filename)) != NULL )
|
||||
return larlib_member__open( L, mb );
|
||||
|
||||
return larlib_perror(L, "File not found");
|
||||
}
|
||||
|
||||
|
||||
static const luaL_reg LAR_REG[] = {
|
||||
{ "open", larlib_open },
|
||||
{ "find", larlib_find },
|
||||
{ "md5", larlib_md5 },
|
||||
{ "md5_file", larlib_md5_file },
|
||||
{ "mmap", larlib_mmfile_open },
|
||||
{ "findfile", larlib_findfile },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static const luaL_reg LAR_ARCHIVE_REG[] = {
|
||||
{ "member", larlib_member_open },
|
||||
{ "find", larlib_member_find },
|
||||
{ "__gc", larlib__gc },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static const luaL_reg LAR_MEMBER_REG[] = {
|
||||
{ "size", larlib_member_size },
|
||||
{ "type", larlib_member_type },
|
||||
{ "flags", larlib_member_flags },
|
||||
{ "read", larlib_member_read },
|
||||
{ "data", larlib_member_data },
|
||||
{ "load", larlib_member_load },
|
||||
{ "__gc", larlib_member__gc },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static const luaL_reg LAR_MMFILE_REG[] = {
|
||||
{ "size", larlib_mmfile_size },
|
||||
{ "read", larlib_mmfile_read },
|
||||
{ "data", larlib_mmfile_data },
|
||||
{ "load", larlib_mmfile_load },
|
||||
{ "__gc", larlib_mmfile__gc },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
|
||||
LUALIB_API int luaopen_larlib( lua_State *L )
|
||||
{
|
||||
luaL_newmetatable(L, "lar");
|
||||
luaL_register(L, NULL, LAR_REG);
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setfield(L, -2, "__index");
|
||||
lua_setglobal(L, "lar");
|
||||
|
||||
luaL_newmetatable(L, "lar.archive");
|
||||
luaL_register(L, NULL, LAR_ARCHIVE_REG);
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setfield(L, -2, "__index");
|
||||
lua_setglobal(L, "lar.archive");
|
||||
|
||||
luaL_newmetatable(L, "lar.member");
|
||||
luaL_register(L, NULL, LAR_MEMBER_REG);
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setfield(L, -2, "__index");
|
||||
lua_setglobal(L, "lar.member");
|
||||
|
||||
luaL_newmetatable(L, "lar.mmfile");
|
||||
luaL_register(L, NULL, LAR_MMFILE_REG);
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setfield(L, -2, "__index");
|
||||
lua_setglobal(L, "lar.mmfile");
|
||||
|
||||
return 1;
|
||||
}
|
|
@ -1,381 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
L. Peter Deutsch
|
||||
ghost@aladdin.com
|
||||
|
||||
*/
|
||||
/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */
|
||||
/*
|
||||
Independent implementation of MD5 (RFC 1321).
|
||||
|
||||
This code implements the MD5 Algorithm defined in RFC 1321, whose
|
||||
text is available at
|
||||
http://www.ietf.org/rfc/rfc1321.txt
|
||||
The code is derived from the text of the RFC, including the test suite
|
||||
(section A.5) but excluding the rest of Appendix A. It does not include
|
||||
any code or documentation that is identified in the RFC as being
|
||||
copyrighted.
|
||||
|
||||
The original and principal author of md5.c is L. Peter Deutsch
|
||||
<ghost@aladdin.com>. Other authors are noted in the change history
|
||||
that follows (in reverse chronological order):
|
||||
|
||||
2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
|
||||
either statically or dynamically; added missing #include <string.h>
|
||||
in library.
|
||||
2002-03-11 lpd Corrected argument list for main(), and added int return
|
||||
type, in test program and T value program.
|
||||
2002-02-21 lpd Added missing #include <stdio.h> in test program.
|
||||
2000-07-03 lpd Patched to eliminate warnings about "constant is
|
||||
unsigned in ANSI C, signed in traditional"; made test program
|
||||
self-checking.
|
||||
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
|
||||
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
|
||||
1999-05-03 lpd Original version.
|
||||
*/
|
||||
|
||||
#include "md5.h"
|
||||
#include <string.h>
|
||||
|
||||
#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
|
||||
#ifdef ARCH_IS_BIG_ENDIAN
|
||||
# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
|
||||
#else
|
||||
# define BYTE_ORDER 0
|
||||
#endif
|
||||
|
||||
#define T_MASK ((md5_word_t)~0)
|
||||
#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
|
||||
#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
|
||||
#define T3 0x242070db
|
||||
#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
|
||||
#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
|
||||
#define T6 0x4787c62a
|
||||
#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
|
||||
#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
|
||||
#define T9 0x698098d8
|
||||
#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
|
||||
#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
|
||||
#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
|
||||
#define T13 0x6b901122
|
||||
#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
|
||||
#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
|
||||
#define T16 0x49b40821
|
||||
#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
|
||||
#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
|
||||
#define T19 0x265e5a51
|
||||
#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
|
||||
#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
|
||||
#define T22 0x02441453
|
||||
#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
|
||||
#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
|
||||
#define T25 0x21e1cde6
|
||||
#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
|
||||
#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
|
||||
#define T28 0x455a14ed
|
||||
#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
|
||||
#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
|
||||
#define T31 0x676f02d9
|
||||
#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
|
||||
#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
|
||||
#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
|
||||
#define T35 0x6d9d6122
|
||||
#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
|
||||
#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
|
||||
#define T38 0x4bdecfa9
|
||||
#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
|
||||
#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
|
||||
#define T41 0x289b7ec6
|
||||
#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
|
||||
#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
|
||||
#define T44 0x04881d05
|
||||
#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
|
||||
#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
|
||||
#define T47 0x1fa27cf8
|
||||
#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
|
||||
#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
|
||||
#define T50 0x432aff97
|
||||
#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
|
||||
#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
|
||||
#define T53 0x655b59c3
|
||||
#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
|
||||
#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
|
||||
#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
|
||||
#define T57 0x6fa87e4f
|
||||
#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
|
||||
#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
|
||||
#define T60 0x4e0811a1
|
||||
#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
|
||||
#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
|
||||
#define T63 0x2ad7d2bb
|
||||
#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
|
||||
|
||||
|
||||
static void
|
||||
md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
|
||||
{
|
||||
md5_word_t
|
||||
a = pms->abcd[0], b = pms->abcd[1],
|
||||
c = pms->abcd[2], d = pms->abcd[3];
|
||||
md5_word_t t;
|
||||
#if BYTE_ORDER > 0
|
||||
/* Define storage only for big-endian CPUs. */
|
||||
md5_word_t X[16];
|
||||
#else
|
||||
/* Define storage for little-endian or both types of CPUs. */
|
||||
md5_word_t xbuf[16];
|
||||
const md5_word_t *X;
|
||||
#endif
|
||||
|
||||
{
|
||||
#if BYTE_ORDER == 0
|
||||
/*
|
||||
* Determine dynamically whether this is a big-endian or
|
||||
* little-endian machine, since we can use a more efficient
|
||||
* algorithm on the latter.
|
||||
*/
|
||||
static const int w = 1;
|
||||
|
||||
if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
|
||||
#endif
|
||||
#if BYTE_ORDER <= 0 /* little-endian */
|
||||
{
|
||||
/*
|
||||
* On little-endian machines, we can process properly aligned
|
||||
* data without copying it.
|
||||
*/
|
||||
if (!((data - (const md5_byte_t *)0) & 3)) {
|
||||
/* data are properly aligned */
|
||||
X = (const md5_word_t *)data;
|
||||
} else {
|
||||
/* not aligned */
|
||||
memcpy(xbuf, data, 64);
|
||||
X = xbuf;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if BYTE_ORDER == 0
|
||||
else /* dynamic big-endian */
|
||||
#endif
|
||||
#if BYTE_ORDER >= 0 /* big-endian */
|
||||
{
|
||||
/*
|
||||
* On big-endian machines, we must arrange the bytes in the
|
||||
* right order.
|
||||
*/
|
||||
const md5_byte_t *xp = data;
|
||||
int i;
|
||||
|
||||
# if BYTE_ORDER == 0
|
||||
X = xbuf; /* (dynamic only) */
|
||||
# else
|
||||
# define xbuf X /* (static only) */
|
||||
# endif
|
||||
for (i = 0; i < 16; ++i, xp += 4)
|
||||
xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
|
||||
|
||||
/* Round 1. */
|
||||
/* Let [abcd k s i] denote the operation
|
||||
a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
|
||||
#define SET(a, b, c, d, k, s, Ti)\
|
||||
t = a + F(b,c,d) + X[k] + Ti;\
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 0, 7, T1);
|
||||
SET(d, a, b, c, 1, 12, T2);
|
||||
SET(c, d, a, b, 2, 17, T3);
|
||||
SET(b, c, d, a, 3, 22, T4);
|
||||
SET(a, b, c, d, 4, 7, T5);
|
||||
SET(d, a, b, c, 5, 12, T6);
|
||||
SET(c, d, a, b, 6, 17, T7);
|
||||
SET(b, c, d, a, 7, 22, T8);
|
||||
SET(a, b, c, d, 8, 7, T9);
|
||||
SET(d, a, b, c, 9, 12, T10);
|
||||
SET(c, d, a, b, 10, 17, T11);
|
||||
SET(b, c, d, a, 11, 22, T12);
|
||||
SET(a, b, c, d, 12, 7, T13);
|
||||
SET(d, a, b, c, 13, 12, T14);
|
||||
SET(c, d, a, b, 14, 17, T15);
|
||||
SET(b, c, d, a, 15, 22, T16);
|
||||
#undef SET
|
||||
|
||||
/* Round 2. */
|
||||
/* Let [abcd k s i] denote the operation
|
||||
a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
|
||||
#define SET(a, b, c, d, k, s, Ti)\
|
||||
t = a + G(b,c,d) + X[k] + Ti;\
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 1, 5, T17);
|
||||
SET(d, a, b, c, 6, 9, T18);
|
||||
SET(c, d, a, b, 11, 14, T19);
|
||||
SET(b, c, d, a, 0, 20, T20);
|
||||
SET(a, b, c, d, 5, 5, T21);
|
||||
SET(d, a, b, c, 10, 9, T22);
|
||||
SET(c, d, a, b, 15, 14, T23);
|
||||
SET(b, c, d, a, 4, 20, T24);
|
||||
SET(a, b, c, d, 9, 5, T25);
|
||||
SET(d, a, b, c, 14, 9, T26);
|
||||
SET(c, d, a, b, 3, 14, T27);
|
||||
SET(b, c, d, a, 8, 20, T28);
|
||||
SET(a, b, c, d, 13, 5, T29);
|
||||
SET(d, a, b, c, 2, 9, T30);
|
||||
SET(c, d, a, b, 7, 14, T31);
|
||||
SET(b, c, d, a, 12, 20, T32);
|
||||
#undef SET
|
||||
|
||||
/* Round 3. */
|
||||
/* Let [abcd k s t] denote the operation
|
||||
a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define H(x, y, z) ((x) ^ (y) ^ (z))
|
||||
#define SET(a, b, c, d, k, s, Ti)\
|
||||
t = a + H(b,c,d) + X[k] + Ti;\
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 5, 4, T33);
|
||||
SET(d, a, b, c, 8, 11, T34);
|
||||
SET(c, d, a, b, 11, 16, T35);
|
||||
SET(b, c, d, a, 14, 23, T36);
|
||||
SET(a, b, c, d, 1, 4, T37);
|
||||
SET(d, a, b, c, 4, 11, T38);
|
||||
SET(c, d, a, b, 7, 16, T39);
|
||||
SET(b, c, d, a, 10, 23, T40);
|
||||
SET(a, b, c, d, 13, 4, T41);
|
||||
SET(d, a, b, c, 0, 11, T42);
|
||||
SET(c, d, a, b, 3, 16, T43);
|
||||
SET(b, c, d, a, 6, 23, T44);
|
||||
SET(a, b, c, d, 9, 4, T45);
|
||||
SET(d, a, b, c, 12, 11, T46);
|
||||
SET(c, d, a, b, 15, 16, T47);
|
||||
SET(b, c, d, a, 2, 23, T48);
|
||||
#undef SET
|
||||
|
||||
/* Round 4. */
|
||||
/* Let [abcd k s t] denote the operation
|
||||
a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
|
||||
#define SET(a, b, c, d, k, s, Ti)\
|
||||
t = a + I(b,c,d) + X[k] + Ti;\
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 0, 6, T49);
|
||||
SET(d, a, b, c, 7, 10, T50);
|
||||
SET(c, d, a, b, 14, 15, T51);
|
||||
SET(b, c, d, a, 5, 21, T52);
|
||||
SET(a, b, c, d, 12, 6, T53);
|
||||
SET(d, a, b, c, 3, 10, T54);
|
||||
SET(c, d, a, b, 10, 15, T55);
|
||||
SET(b, c, d, a, 1, 21, T56);
|
||||
SET(a, b, c, d, 8, 6, T57);
|
||||
SET(d, a, b, c, 15, 10, T58);
|
||||
SET(c, d, a, b, 6, 15, T59);
|
||||
SET(b, c, d, a, 13, 21, T60);
|
||||
SET(a, b, c, d, 4, 6, T61);
|
||||
SET(d, a, b, c, 11, 10, T62);
|
||||
SET(c, d, a, b, 2, 15, T63);
|
||||
SET(b, c, d, a, 9, 21, T64);
|
||||
#undef SET
|
||||
|
||||
/* Then perform the following additions. (That is increment each
|
||||
of the four registers by the value it had before this block
|
||||
was started.) */
|
||||
pms->abcd[0] += a;
|
||||
pms->abcd[1] += b;
|
||||
pms->abcd[2] += c;
|
||||
pms->abcd[3] += d;
|
||||
}
|
||||
|
||||
void
|
||||
md5_init(md5_state_t *pms)
|
||||
{
|
||||
pms->count[0] = pms->count[1] = 0;
|
||||
pms->abcd[0] = 0x67452301;
|
||||
pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
|
||||
pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
|
||||
pms->abcd[3] = 0x10325476;
|
||||
}
|
||||
|
||||
void
|
||||
md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)
|
||||
{
|
||||
const md5_byte_t *p = data;
|
||||
int left = nbytes;
|
||||
int offset = (pms->count[0] >> 3) & 63;
|
||||
md5_word_t nbits = (md5_word_t)(nbytes << 3);
|
||||
|
||||
if (nbytes <= 0)
|
||||
return;
|
||||
|
||||
/* Update the message length. */
|
||||
pms->count[1] += nbytes >> 29;
|
||||
pms->count[0] += nbits;
|
||||
if (pms->count[0] < nbits)
|
||||
pms->count[1]++;
|
||||
|
||||
/* Process an initial partial block. */
|
||||
if (offset) {
|
||||
int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
|
||||
|
||||
memcpy(pms->buf + offset, p, copy);
|
||||
if (offset + copy < 64)
|
||||
return;
|
||||
p += copy;
|
||||
left -= copy;
|
||||
md5_process(pms, pms->buf);
|
||||
}
|
||||
|
||||
/* Process full blocks. */
|
||||
for (; left >= 64; p += 64, left -= 64)
|
||||
md5_process(pms, p);
|
||||
|
||||
/* Process a final partial block. */
|
||||
if (left)
|
||||
memcpy(pms->buf, p, left);
|
||||
}
|
||||
|
||||
void
|
||||
md5_finish(md5_state_t *pms, md5_byte_t digest[16])
|
||||
{
|
||||
static const md5_byte_t pad[64] = {
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
md5_byte_t data[8];
|
||||
int i;
|
||||
|
||||
/* Save the length before padding. */
|
||||
for (i = 0; i < 8; ++i)
|
||||
data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
|
||||
/* Pad to 56 bytes mod 64. */
|
||||
md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
|
||||
/* Append the length. */
|
||||
md5_append(pms, data, 8);
|
||||
for (i = 0; i < 16; ++i)
|
||||
digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
|
||||
}
|
|
@ -1,91 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved.
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
L. Peter Deutsch
|
||||
ghost@aladdin.com
|
||||
|
||||
*/
|
||||
/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */
|
||||
/*
|
||||
Independent implementation of MD5 (RFC 1321).
|
||||
|
||||
This code implements the MD5 Algorithm defined in RFC 1321, whose
|
||||
text is available at
|
||||
http://www.ietf.org/rfc/rfc1321.txt
|
||||
The code is derived from the text of the RFC, including the test suite
|
||||
(section A.5) but excluding the rest of Appendix A. It does not include
|
||||
any code or documentation that is identified in the RFC as being
|
||||
copyrighted.
|
||||
|
||||
The original and principal author of md5.h is L. Peter Deutsch
|
||||
<ghost@aladdin.com>. Other authors are noted in the change history
|
||||
that follows (in reverse chronological order):
|
||||
|
||||
2002-04-13 lpd Removed support for non-ANSI compilers; removed
|
||||
references to Ghostscript; clarified derivation from RFC 1321;
|
||||
now handles byte order either statically or dynamically.
|
||||
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
|
||||
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
|
||||
added conditionalization for C++ compilation from Martin
|
||||
Purschke <purschke@bnl.gov>.
|
||||
1999-05-03 lpd Original version.
|
||||
*/
|
||||
|
||||
#ifndef md5_INCLUDED
|
||||
# define md5_INCLUDED
|
||||
|
||||
/*
|
||||
* This package supports both compile-time and run-time determination of CPU
|
||||
* byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
|
||||
* compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
|
||||
* defined as non-zero, the code will be compiled to run only on big-endian
|
||||
* CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
|
||||
* run on either big- or little-endian CPUs, but will run slightly less
|
||||
* efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
|
||||
*/
|
||||
|
||||
typedef unsigned char md5_byte_t; /* 8-bit byte */
|
||||
typedef unsigned int md5_word_t; /* 32-bit word */
|
||||
|
||||
/* Define the state of the MD5 Algorithm. */
|
||||
typedef struct md5_state_s {
|
||||
md5_word_t count[2]; /* message length in bits, lsw first */
|
||||
md5_word_t abcd[4]; /* digest buffer */
|
||||
md5_byte_t buf[64]; /* accumulate block */
|
||||
} md5_state_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/* Initialize the algorithm. */
|
||||
void md5_init(md5_state_t *pms);
|
||||
|
||||
/* Append a string to the message. */
|
||||
void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes);
|
||||
|
||||
/* Finish the message and return the digest. */
|
||||
void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* md5_INCLUDED */
|
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue