#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include <net/if.h>
#include <net/route.h>
#include <net/pfil.h>
#include <netinet/in.h>
#include <net/ipfw3/ip_fw3.h>
#include "../../../sbin/ipfw3/ipfw3.h"
#include "ipfw3_layer2.h"
static int
contigmask(u_char *p, int len)
{
int i, n;
for (i = 0; i < len ; i++) {
if ( (p[i/8] & (1 << (7 - (i%8)))) == 0)
break;
}
for (n = i + 1; n < len; n++) {
if ( (p[n/8] & (1 << (7 - (n%8)))) != 0)
return -1;
}
return i;
}
static void
print_mac(u_char *addr, u_char *mask)
{
int l = contigmask(mask, 48);
if (l == 0) {
printf(" any");
} else {
printf(" %02x:%02x:%02x:%02x:%02x:%02x",
addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
if (l == -1) {
printf("&%02x:%02x:%02x:%02x:%02x:%02x",
mask[0], mask[1], mask[2],
mask[3], mask[4], mask[5]);
} else if (l < 48) {
printf("/%d", l);
}
}
}
static void
get_mac_addr_mask(char *p, u_char *addr, u_char *mask)
{
int i, l;
for (i = 0; i < 6; i++)
addr[i] = mask[i] = 0;
if (!strcmp(p, "any"))
return;
for (i = 0; *p && i < 6; i++, p++) {
addr[i] = strtol(p, &p, 16);
if (*p != ':')
break;
}
if (*p == '/') {
l = strtol(p + 1, &p, 0);
for (i = 0; l > 0; l -= 8, i++)
mask[i] = (l >=8) ? 0xff : (~0) << (8-l);
} else if (*p == '&') {
for (i = 0, p++; *p && i < 6; i++, p++) {
mask[i] = strtol(p, &p, 16);
if (*p != ':')
break;
}
} else if (*p == '\0') {
for (i = 0; i < 6; i++)
mask[i] = 0xff;
}
for (i = 0; i < 6; i++)
addr[i] &= mask[i];
}
void
parse_layer2(ipfw_insn **cmd, int *ac, char **av[])
{
(*cmd)->opcode = O_LAYER2_LAYER2;
(*cmd)->module = MODULE_LAYER2_ID;
(*cmd)->len |= LEN_OF_IPFWINSN;
NEXT_ARG1;
}
void
parse_mac_from(ipfw_insn **cmd, int *ac, char **av[])
{
NEED(*ac, 2, "mac-from src");
NEXT_ARG1;
if (strcmp(**av, "table") == 0) {
NEED(*ac, 2, "mac-from table N");
NEXT_ARG1;
(*cmd)->opcode = O_LAYER2_MAC_SRC_LOOKUP;
(*cmd)->module = MODULE_LAYER2_ID;
(*cmd)->len |= F_INSN_SIZE(ipfw_insn);
(*cmd)->arg1 = strtoul(**av, NULL, 10);
NEXT_ARG1;
} else {
(*cmd)->opcode = O_LAYER2_MAC_SRC;
(*cmd)->module = MODULE_LAYER2_ID;
(*cmd)->len |= F_INSN_SIZE(ipfw_insn_mac);
ipfw_insn_mac *mac = (ipfw_insn_mac *)(*cmd);
get_mac_addr_mask(**av, &(mac->addr[6]), &(mac->mask[6]));
NEXT_ARG1;
}
}
void
parse_mac_to(ipfw_insn **cmd, int *ac, char **av[])
{
NEED(*ac, 2, "mac-to dst");
NEXT_ARG1;
if (strcmp(**av, "table") == 0) {
NEED(*ac, 2, "mac-to table N");
NEXT_ARG1;
(*cmd)->opcode = O_LAYER2_MAC_DST_LOOKUP;
(*cmd)->module = MODULE_LAYER2_ID;
(*cmd)->len |= F_INSN_SIZE(ipfw_insn);
(*cmd)->arg1 = strtoul(**av, NULL, 10);
NEXT_ARG1;
} else {
(*cmd)->opcode = O_LAYER2_MAC_DST;
(*cmd)->module = MODULE_LAYER2_ID;
(*cmd)->len |= F_INSN_SIZE(ipfw_insn_mac);
ipfw_insn_mac *mac = (ipfw_insn_mac *)(*cmd);
get_mac_addr_mask(**av, mac->addr, mac->mask);
NEXT_ARG1;
}
}
void
parse_mac(ipfw_insn **cmd, int *ac, char **av[])
{
NEED(*ac, 3, "mac dst src");
NEXT_ARG1;
(*cmd)->opcode = O_LAYER2_MAC;
(*cmd)->module = MODULE_LAYER2_ID;
(*cmd)->len |= F_INSN_SIZE(ipfw_insn_mac);
ipfw_insn_mac *mac = (ipfw_insn_mac *)(*cmd);
get_mac_addr_mask(**av, mac->addr, mac->mask);
NEXT_ARG1;
get_mac_addr_mask(**av, &(mac->addr[6]), &(mac->mask[6]));
NEXT_ARG1;
}
void
show_layer2(ipfw_insn *cmd, int show_or)
{
printf(" layer2");
}
void
show_mac(ipfw_insn *cmd, int show_or)
{
ipfw_insn_mac *m = (ipfw_insn_mac *)cmd;
if (show_or)
printf(" or");
else
printf(" mac");
print_mac( m->addr, m->mask);
print_mac( m->addr + 6, m->mask + 6);
}
void
show_mac_from(ipfw_insn *cmd, int show_or)
{
ipfw_insn_mac *m = (ipfw_insn_mac *)cmd;
if (show_or)
printf(" or");
else
printf(" mac-from");
print_mac( m->addr + 6, m->mask + 6);
}
void
show_mac_from_lookup(ipfw_insn *cmd, int show_or)
{
printf(" mac-from table %d", cmd->arg1);
}
void
show_mac_to(ipfw_insn *cmd, int show_or)
{
ipfw_insn_mac *m = (ipfw_insn_mac *)cmd;
if (show_or)
printf(" or");
else
printf(" mac-to");
print_mac( m->addr, m->mask);
}
void
show_mac_to_lookup(ipfw_insn *cmd, int show_or)
{
printf(" mac-to table %d", cmd->arg1);
}
void
load_module(register_func function, register_keyword keyword)
{
keyword(MODULE_LAYER2_ID, O_LAYER2_LAYER2, "layer2", FILTER);
function(MODULE_LAYER2_ID, O_LAYER2_LAYER2,
(parser_func)parse_layer2, (shower_func)show_layer2);
keyword(MODULE_LAYER2_ID, O_LAYER2_MAC, "mac", FILTER);
function(MODULE_LAYER2_ID, O_LAYER2_MAC,
(parser_func)parse_mac,(shower_func)show_mac);
keyword(MODULE_LAYER2_ID, O_LAYER2_MAC_SRC, "mac-from", FROM);
function(MODULE_LAYER2_ID, O_LAYER2_MAC_SRC,
(parser_func)parse_mac_from,(shower_func)show_mac_from);
keyword(MODULE_LAYER2_ID, O_LAYER2_MAC_SRC_LOOKUP,
"mac-from-[table]", FROM);
function(MODULE_LAYER2_ID, O_LAYER2_MAC_SRC_LOOKUP,
(parser_func)parse_mac_from,
(shower_func)show_mac_from_lookup);
keyword(MODULE_LAYER2_ID, O_LAYER2_MAC_DST, "mac-to", TO);
function(MODULE_LAYER2_ID, O_LAYER2_MAC_DST,
(parser_func)parse_mac_to,(shower_func)show_mac_to);
keyword(MODULE_LAYER2_ID, O_LAYER2_MAC_DST_LOOKUP,
"mac-to-[table]", TO);
function(MODULE_LAYER2_ID, O_LAYER2_MAC_DST_LOOKUP,
(parser_func)parse_mac_to,
(shower_func)show_mac_to_lookup);
}