#include <sys/param.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/sysctl.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <dlfcn.h>
#include <err.h>
#include <errno.h>
#include <grp.h>
#include <limits.h>
#include <netdb.h>
#include <pwd.h>
#include <sysexits.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <timeconv.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netinet/tcp.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/route.h>
#include <net/ethernet.h>
#include <net/ipfw3/ip_fw3.h>
#include <net/ipfw3_basic/ip_fw3_table.h>
#include <net/ipfw3_basic/ip_fw3_sync.h>
#include <net/ipfw3_basic/ip_fw3_basic.h>
#include <net/ipfw3_nat/ip_fw3_nat.h>
#include <net/dummynet3/ip_dummynet3.h>
#include "ipfw3.h"
#include "ipfw3table.h"
int
lookup_host (char *host, struct in_addr *ipaddr)
{
struct hostent *he;
if (!inet_aton(host, ipaddr)) {
if ((he = gethostbyname(host)) == NULL)
return(-1);
*ipaddr = *(struct in_addr *)he->h_addr_list[0];
}
return(0);
}
void
table_append(int ac, char *av[])
{
struct ipfw_ioc_table tbl;
char *p;
int size;
NEXT_ARG;
if (isdigit(**av))
tbl.id = atoi(*av);
else
errx(EX_USAGE, "table id `%s' invalid", *av);
if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1)
errx(EX_USAGE, "table id `%d' invalid", tbl.id);
NEXT_ARG;
if (strcmp(*av, "ip") == 0)
tbl.type = 1;
else if (strcmp(*av, "mac") == 0)
tbl.type = 2;
else
errx(EX_USAGE, "table type `%s' not supported", *av);
NEXT_ARG;
if (tbl.type == 1) {
struct ipfw_ioc_table_ip_entry ip_ent;
if (!ac)
errx(EX_USAGE, "IP address required");
p = strchr(*av, '/');
if (p) {
*p++ = '\0';
ip_ent.masklen = atoi(p);
if (ip_ent.masklen > 32)
errx(EX_DATAERR, "bad width ``%s''", p);
} else {
ip_ent.masklen = 32;
}
if (lookup_host(*av, (struct in_addr *)&ip_ent.addr) != 0)
errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
tbl.ip_ent[0] = ip_ent;
size = sizeof(tbl) + sizeof(ip_ent);
} else if (tbl.type == 2) {
struct ipfw_ioc_table_mac_entry mac_ent;
if (!ac)
errx(EX_USAGE, "MAC address required");
mac_ent.addr = *ether_aton(*av);
tbl.mac_ent[0] = mac_ent;
size = sizeof(tbl) + sizeof(mac_ent);
}
if (do_set_x(IP_FW_TABLE_APPEND, &tbl, size) < 0 )
errx(EX_USAGE, "do_set_x(IP_FW_TABLE_APPEND) "
"table `%d' append `%s' failed", tbl.id, *av);
}
void
table_remove(int ac, char *av[])
{
struct ipfw_ioc_table tbl;
struct ipfw_ioc_table_ip_entry ip_ent;
char *p;
int size;
NEXT_ARG;
if (isdigit(**av))
tbl.id = atoi(*av);
else
errx(EX_USAGE, "table id `%s' invalid", *av);
if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1)
errx(EX_USAGE, "table id `%d' invalid", tbl.id);
NEXT_ARG;
if (strcmp(*av, "ip") == 0)
tbl.type = 1;
else if (strcmp(*av, "mac") == 0)
tbl.type = 2;
else
errx(EX_USAGE, "table type `%s' not supported", *av);
NEXT_ARG;
if (!ac)
errx(EX_USAGE, "IP address required");
p = strchr(*av, '/');
if (p) {
*p++ = '\0';
ip_ent.masklen = atoi(p);
if (ip_ent.masklen > 32)
errx(EX_DATAERR, "bad width ``%s''", p);
} else {
ip_ent.masklen = 32;
}
if (lookup_host(*av, (struct in_addr *)&ip_ent.addr) != 0)
errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
tbl.ip_ent[0] = ip_ent;
size = sizeof(tbl) + sizeof(ip_ent);
if (do_set_x(IP_FW_TABLE_REMOVE, &tbl, size) < 0 ) {
errx(EX_USAGE, "do_set_x(IP_FW_TABLE_REMOVE) "
"table `%d' append `%s' failed", tbl.id, *av);
}
}
void
table_flush(int ac, char *av[])
{
struct ipfw_ioc_table ioc_table;
struct ipfw_ioc_table *t = &ioc_table;
NEXT_ARG;
if (isdigit(**av)) {
t->id = atoi(*av);
if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1)
errx(EX_USAGE, "table id `%d' invalid", t->id);
} else {
errx(EX_USAGE, "table id `%s' invalid", *av);
}
if (do_set_x(IP_FW_TABLE_FLUSH, t, sizeof(struct ipfw_ioc_table)) < 0 )
errx(EX_USAGE, "do_set_x(IP_FW_TABLE_FLUSH) "
"table `%s' flush failed", *av);
}
void
table_list(int ac, char *av[])
{
struct ipfw_ioc_table *ioc_table;
int i, count, nbytes, nalloc = 1024;
void *data = NULL;
NEXT_ARG;
if (strcmp(*av, "list") == 0) {
nbytes = nalloc;
while (nbytes >= nalloc) {
nalloc = nalloc * 2 ;
nbytes = nalloc;
if ((data = realloc(data, nbytes)) == NULL)
err(EX_OSERR, "realloc");
if (do_get_x(IP_FW_TABLE_LIST, data, &nbytes) < 0)
err(EX_OSERR, "do_get_x(IP_FW_TABLE_LIST)");
}
ioc_table = (struct ipfw_ioc_table *)data;
count = nbytes / sizeof(struct ipfw_ioc_table);
for (i = 0; i < count; i++, ioc_table++) {
if (ioc_table->type > 0) {
printf("table %d",ioc_table->id);
if (ioc_table->type == 1)
printf(" type ip");
else if (ioc_table->type == 2)
printf(" type mac");
printf(" count %d",ioc_table->count);
if (strlen(ioc_table->name) > 0)
printf(" name %s",ioc_table->name);
printf("\n");
}
}
} else {
errx(EX_USAGE, "ipfw3 table `%s' delete invalid", *av);
}
}
void
table_print(struct ipfw_ioc_table * tbl)
{
int i;
if (tbl->type == 0)
errx(EX_USAGE, "table %d is not in use", tbl->id);
printf("table %d", tbl->id);
if (tbl->type == 1)
printf(" type ip");
else if (tbl->type == 2)
printf(" type mac");
printf(" count %d", tbl->count);
if (strlen(tbl->name) > 0)
printf(" name %s", tbl->name);
printf("\n");
if (tbl->type == 1) {
struct ipfw_ioc_table_ip_entry *ip_ent;
ip_ent = tbl->ip_ent;
for (i = 0; i < tbl->count; i++) {
printf("%s", inet_ntoa(*(struct in_addr *)&ip_ent->addr));
printf("/%d ", ip_ent->masklen);
printf("\n");
ip_ent++;
}
} else if (tbl->type == 2) {
struct ipfw_ioc_table_mac_entry *mac_ent;
mac_ent = tbl->mac_ent;
for (i = 0; i < tbl->count; i++) {
printf("%s", ether_ntoa(&mac_ent->addr));
printf("\n");
mac_ent++;
}
}
}
void
table_show(int ac, char *av[])
{
int nbytes, nalloc = 1024;
void *data = NULL;
NEXT_ARG;
if (isdigit(**av)) {
nbytes = nalloc;
while (nbytes >= nalloc) {
nalloc = nalloc * 2 + 256;
nbytes = nalloc;
if (data == NULL) {
if ((data = malloc(nbytes)) == NULL) {
err(EX_OSERR, "malloc");
}
} else if ((data = realloc(data, nbytes)) == NULL) {
err(EX_OSERR, "realloc");
}
int *head = (int *)data;
*head = atoi(*av);
if (*head < 0 || *head > IPFW_TABLES_MAX - 1)
errx(EX_USAGE, "table id `%d' invalid", *head);
if (do_get_x(IP_FW_TABLE_SHOW, data, &nbytes) < 0)
err(EX_OSERR, "do_get_x(IP_FW_TABLE_LIST)");
struct ipfw_ioc_table *tbl;
tbl = (struct ipfw_ioc_table *)data;
table_print(tbl);
}
} else {
errx(EX_USAGE, "ipfw3 table `%s' show invalid", *av);
}
}
void
table_create(int ac, char *av[])
{
struct ipfw_ioc_table ioc_table;
struct ipfw_ioc_table *t = &ioc_table;
NEXT_ARG;
if (ac < 2)
errx(EX_USAGE, "table parameters invalid");
if (isdigit(**av)) {
t->id = atoi(*av);
if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1)
errx(EX_USAGE, "table id `%d' invalid", t->id);
} else {
errx(EX_USAGE, "table id `%s' invalid", *av);
}
NEXT_ARG;
if (strcmp(*av, "ip") == 0)
t->type = 1;
else if (strcmp(*av, "mac") == 0)
t->type = 2;
else
errx(EX_USAGE, "table type `%s' not supported", *av);
NEXT_ARG;
memset(t->name, 0, IPFW_TABLE_NAME_LEN);
if (ac == 2 && strcmp(*av, "name") == 0) {
NEXT_ARG;
if (strlen(*av) < IPFW_TABLE_NAME_LEN) {
strncpy(t->name, *av, strlen(*av));
} else {
errx(EX_USAGE, "table name `%s' too long", *av);
}
} else if (ac == 1) {
errx(EX_USAGE, "table `%s' invalid", *av);
}
if (do_set_x(IP_FW_TABLE_CREATE, t, sizeof(struct ipfw_ioc_table)) < 0)
errx(EX_USAGE, "do_set_x(IP_FW_TABLE_CREATE) "
"table `%d' in use", t->id);
}
void
table_delete(int ac, char *av[])
{
struct ipfw_ioc_table ioc_table;
struct ipfw_ioc_table *t = &ioc_table;
NEXT_ARG;
if (isdigit(**av)) {
t->id = atoi(*av);
if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1)
errx(EX_USAGE, "table id `%d' invalid", t->id);
} else {
errx(EX_USAGE, "table id `%s' invalid", *av);
}
if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1)
errx(EX_USAGE, "table id `%d' invalid", t->id);
if (do_set_x(IP_FW_TABLE_DELETE, t, sizeof(struct ipfw_ioc_table)) < 0)
errx(EX_USAGE, "do_set_x(IP_FW_TABLE_DELETE) "
"table `%s' delete failed", *av);
}
void
table_test(int ac, char *av[])
{
struct ipfw_ioc_table tbl;
int size;
NEXT_ARG;
if (isdigit(**av))
tbl.id = atoi(*av);
else
errx(EX_USAGE, "table id `%s' invalid", *av);
if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1)
errx(EX_USAGE, "table id `%d' invalid", tbl.id);
NEXT_ARG;
if (strcmp(*av, "ip") == 0)
tbl.type = 1;
else if (strcmp(*av, "mac") == 0)
tbl.type = 2;
else
errx(EX_USAGE, "table type `%s' not supported", *av);
NEXT_ARG;
if (tbl.type == 1) {
struct ipfw_ioc_table_ip_entry ip_ent;
if (lookup_host(*av, (struct in_addr *)&ip_ent.addr) != 0)
errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
tbl.ip_ent[0] = ip_ent;
size = sizeof(tbl) + sizeof(ip_ent);
} else if (tbl.type == 2) {
struct ipfw_ioc_table_mac_entry mac_ent;
if (!ac)
errx(EX_USAGE, "MAC address required");
mac_ent.addr = *ether_aton(*av);
tbl.mac_ent[0] = mac_ent;
size = sizeof(tbl) + sizeof(mac_ent);
}
if (do_set_x(IP_FW_TABLE_TEST, &tbl, size) < 0 ) {
printf("NO, %s not exists in table %d\n", *av, tbl.id);
} else {
printf("YES, %s exists in table %d\n", *av, tbl.id);
}
}
static void
table_rename(int ac, char *av[])
{
struct ipfw_ioc_table tbl;
int size;
bzero(&tbl, sizeof(tbl));
NEXT_ARG;
if (isdigit(**av))
tbl.id = atoi(*av);
else
errx(EX_USAGE, "table id `%s' invalid", *av);
if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1)
errx(EX_USAGE, "table id `%d' invalid", tbl.id);
NEXT_ARG;
strlcpy(tbl.name, *av, IPFW_TABLE_NAME_LEN);
size = sizeof(tbl);
if (do_set_x(IP_FW_TABLE_RENAME, &tbl, size) < 0 )
errx(EX_USAGE, "do_set_x(IP_FW_TABLE_RENAME) "
"table `%d' not in use", tbl.id);
}
void
table_main(int ac, char **av)
{
if (!strncmp(*av, "append", strlen(*av))) {
table_append(ac, av);
} else if (!strncmp(*av, "add", strlen(*av))) {
table_append(ac, av);
} else if (!strncmp(*av, "remove", strlen(*av))) {
table_remove(ac, av);
} else if (!strncmp(*av, "flush", strlen(*av))) {
table_flush(ac, av);
} else if (!strncmp(*av, "list", strlen(*av))) {
table_list(ac, av);
} else if (!strncmp(*av, "show", strlen(*av))) {
table_show(ac, av);
} else if (!strncmp(*av, "type", strlen(*av))) {
table_create(ac, av);
} else if (!strncmp(*av, "delete", strlen(*av))) {
table_delete(ac, av);
} else if (!strncmp(*av, "test", strlen(*av))) {
table_test(ac,av);
} else if (!strncmp(*av, "name", strlen(*av))) {
table_rename(ac, av);
} else {
errx(EX_USAGE, "bad ipfw table command `%s'", *av);
}
}