+++ /dev/null
-include ../../build/config.mk
-include ../../build/module.mk
+++ /dev/null
-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
-
+++ /dev/null
-/*
- * 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);
-}
-
+++ /dev/null
-/*
- * 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
+++ /dev/null
-/*
- * 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);
-}
-
+++ /dev/null
-/*
- * 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
-
+++ /dev/null
-/*
- * 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;
-}
-
+++ /dev/null
-#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
+++ /dev/null
-/*
- * 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));
-}
+++ /dev/null
-/*
- * 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
+++ /dev/null
-/*
- * 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);
-}
-
+++ /dev/null
-/*
- * 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
-
+++ /dev/null
-/*
- * 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;
-}
-
-
+++ /dev/null
-/*
- * 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
-
+++ /dev/null
-/*
- * 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);
-}
-
+++ /dev/null
-/*
- * 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
+++ /dev/null
-/*
- * 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);
-}
-
-
+++ /dev/null
-/*
- * 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
-
+++ /dev/null
-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)
+++ /dev/null
-#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;
-}
+++ /dev/null
-/*
- * 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);
-}
+++ /dev/null
-/*
- * 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
+++ /dev/null
-#!/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;
-
+++ /dev/null
-/*
- * 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;
-}
+++ /dev/null
-/*
- 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));
-}
+++ /dev/null
-/*
- 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 */
+++ /dev/null
-diff -Nbur lua-5.1.4.orig/src/Makefile lua-5.1.4/src/Makefile
---- lua-5.1.4.orig/src/Makefile 2009-04-06 21:36:52.000000000 +0200
-+++ lua-5.1.4/src/Makefile 2009-04-11 01:02:45.000000000 +0200
-@@ -28,7 +28,7 @@
- lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o \
- lundump.o lvm.o lzio.o lnum.o
- LIB_O= lauxlib.o lbaselib.o ldblib.o liolib.o lmathlib.o loslib.o ltablib.o \
-- lstrlib.o loadlib.o linit.o
-+ lstrlib.o loadlib.o linit.o lar.o md5.o larlib.o
-
- LUA_T= lua
- LUA_O= lua.o
-diff -Nbur lua-5.1.4.orig/src/lar.c lua-5.1.4/src/lar.c
---- lua-5.1.4.orig/src/lar.c 1970-01-01 01:00:00.000000000 +0100
-+++ lua-5.1.4/src/lar.c 2009-04-13 16:51:07.000000000 +0200
-@@ -0,0 +1,328 @@
-+/*
-+ * 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);
-+}
-diff -Nbur lua-5.1.4.orig/src/lar.h lua-5.1.4/src/lar.h
---- lua-5.1.4.orig/src/lar.h 1970-01-01 01:00:00.000000000 +0100
-+++ lua-5.1.4/src/lar.h 2009-04-13 17:13:47.000000000 +0200
-@@ -0,0 +1,108 @@
-+/*
-+ * 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
-diff -Nbur lua-5.1.4.orig/src/larlib.c lua-5.1.4/src/larlib.c
---- lua-5.1.4.orig/src/larlib.c 1970-01-01 01:00:00.000000000 +0100
-+++ lua-5.1.4/src/larlib.c 2009-04-13 17:24:57.000000000 +0200
-@@ -0,0 +1,540 @@
-+/*
-+ * 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;
-+}
-diff -Nbur lua-5.1.4.orig/src/linit.c lua-5.1.4/src/linit.c
---- lua-5.1.4.orig/src/linit.c 2009-04-06 21:36:52.000000000 +0200
-+++ lua-5.1.4/src/linit.c 2009-04-11 01:27:00.000000000 +0200
-@@ -23,6 +23,7 @@
- {LUA_STRLIBNAME, luaopen_string},
- {LUA_MATHLIBNAME, luaopen_math},
- {LUA_DBLIBNAME, luaopen_debug},
-+ {LUA_LARLIBNAME, luaopen_larlib},
- {NULL, NULL}
- };
-
-diff -Nbur lua-5.1.4.orig/src/loadlib.c lua-5.1.4/src/loadlib.c
---- lua-5.1.4.orig/src/loadlib.c 2009-04-06 21:36:52.000000000 +0200
-+++ lua-5.1.4/src/loadlib.c 2009-04-11 01:04:47.000000000 +0200
-@@ -21,6 +21,7 @@
- #include "lauxlib.h"
- #include "lualib.h"
-
-+#include "lar.h"
-
- /* prefix for open functions in C libraries */
- #define LUA_POF "luaopen_"
-@@ -388,6 +389,36 @@
- }
-
-
-+static int loader_Lar (lua_State *L) {
-+ lar_archive *ar;
-+ lar_member *mb;
-+ const char *name = luaL_checkstring(L, 1);
-+
-+ if( (ar = lar_find_archive(name, "./", 1)) ||
-+ (ar = lar_find_archive(name, LUA_LDIR, 1)) ||
-+ (ar = lar_find_archive(name, LUA_CDIR, 1))
-+ ) {
-+ if( (mb = lar_find_member(ar, name)) != NULL ) {
-+ if( luaL_loadbuffer(L, mb->data, mb->length, ar->filename) != 0 ) {
-+ luaL_error(L, "error while loading lar member '%s':\n\t%s",
-+ name, lua_tostring(L, -1));
-+ }
-+ lar_close_member(mb);
-+ }
-+ else {
-+ lua_pushfstring(L, "\n\tno matching lar member " LUA_QS " in " LUA_QS,
-+ name, ar->filename);
-+ }
-+ lar_close(ar);
-+ }
-+ else {
-+ lua_pushfstring(L, "\n\tno matching lar archive for " LUA_QS, name);
-+ }
-+
-+ return 1;
-+}
-+
-+
- static const char *mkfuncname (lua_State *L, const char *modname) {
- const char *funcname;
- const char *mark = strchr(modname, *LUA_IGMARK);
-@@ -621,7 +652,7 @@
-
-
- static const lua_CFunction loaders[] =
-- {loader_preload, loader_Lua, loader_C, loader_Croot, NULL};
-+ {loader_preload, loader_Lua, loader_Lar, loader_C, loader_Croot, NULL};
-
-
- LUALIB_API int luaopen_package (lua_State *L) {
-diff -Nbur lua-5.1.4.orig/src/lualib.h lua-5.1.4/src/lualib.h
---- lua-5.1.4.orig/src/lualib.h 2009-04-06 21:36:52.000000000 +0200
-+++ lua-5.1.4/src/lualib.h 2009-04-11 01:28:24.000000000 +0200
-@@ -39,6 +39,9 @@
- #define LUA_LOADLIBNAME "package"
- LUALIB_API int (luaopen_package) (lua_State *L);
-
-+#define LUA_LARLIBNAME "lar"
-+LUALIB_API int (luaopen_larlib) (lua_State *L);
-+
-
- /* open all previous libraries */
- LUALIB_API void (luaL_openlibs) (lua_State *L);
-diff -Nbur lua-5.1.4.orig/src/md5.c lua-5.1.4/src/md5.c
---- lua-5.1.4.orig/src/md5.c 1970-01-01 01:00:00.000000000 +0100
-+++ lua-5.1.4/src/md5.c 2009-04-10 23:07:56.000000000 +0200
-@@ -0,0 +1,381 @@
-+/*
-+ 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));
-+}
-diff -Nbur lua-5.1.4.orig/src/md5.h lua-5.1.4/src/md5.h
---- lua-5.1.4.orig/src/md5.h 1970-01-01 01:00:00.000000000 +0100
-+++ lua-5.1.4/src/md5.h 2009-04-10 23:07:56.000000000 +0200
-@@ -0,0 +1,91 @@
-+/*
-+ 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 */