Through fixes and improvements our ipfilter sources have diverged enough to warrant move from contrib into sbin/ipf. Now that I'm planning on implementing MSS clamping as in iptables it makes more sense to move ipfilter to sbin. This is the second of three commits of the ipfilter move. Suggested by glebius on two occaions. Suggested by and discussed with: glebius Reviewed by: glebius, kp (for #network) MFC after: 1 month Differential Revision: https://reviews.freebsd.org/D33510
573 lines
10 KiB
Plaintext
573 lines
10 KiB
Plaintext
/* $FreeBSD$ */
|
|
|
|
/*
|
|
* Copyright (C) 2012 by Darren Reed.
|
|
*
|
|
* See the IPFILTER.LICENCE file for details on licencing.
|
|
*/
|
|
%{
|
|
#include <sys/types.h>
|
|
#include <sys/ioctl.h>
|
|
#include "ipf.h"
|
|
#include "opts.h"
|
|
#include "kmem.h"
|
|
#include "ipscan_l.h"
|
|
#include "netinet/ip_scan.h"
|
|
#include <ctype.h>
|
|
|
|
#define YYDEBUG 1
|
|
|
|
extern char *optarg;
|
|
extern void yyerror(char *);
|
|
extern int yyparse(void);
|
|
extern int yylex(void);
|
|
extern int yydebug;
|
|
extern FILE *yyin;
|
|
extern int yylineNum;
|
|
extern void printbuf(char *, int, int);
|
|
|
|
|
|
void printent(ipscan_t *);
|
|
void showlist(void);
|
|
int getportnum(char *);
|
|
struct in_addr gethostip(char *);
|
|
struct in_addr combine(int, int, int, int);
|
|
char **makepair(char *, char *);
|
|
void addtag(char *, char **, char **, struct action *);
|
|
int cram(char *, char *);
|
|
void usage(char *);
|
|
int main(int, char **);
|
|
|
|
int opts = 0;
|
|
int fd = -1;
|
|
|
|
|
|
%}
|
|
|
|
%union {
|
|
char *str;
|
|
char **astr;
|
|
u_32_t num;
|
|
struct in_addr ipa;
|
|
struct action act;
|
|
union i6addr ip6;
|
|
}
|
|
|
|
%type <str> tag
|
|
%type <act> action redirect result
|
|
%type <ipa> ipaddr
|
|
%type <num> portnum
|
|
%type <astr> matchup onehalf twohalves
|
|
|
|
%token <num> YY_NUMBER YY_HEX
|
|
%token <str> YY_STR
|
|
%token YY_COMMENT
|
|
%token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
|
|
%token YY_RANGE_OUT YY_RANGE_IN
|
|
%token <ip6> YY_IPV6
|
|
%token IPSL_START IPSL_STARTGROUP IPSL_CONTENT
|
|
|
|
%token IPSL_CLOSE IPSL_TRACK IPSL_EOF IPSL_REDIRECT IPSL_ELSE
|
|
|
|
%%
|
|
file: line ';'
|
|
| assign ';'
|
|
| file line ';'
|
|
| file assign ';'
|
|
| YY_COMMENT
|
|
;
|
|
|
|
line: IPSL_START dline
|
|
| IPSL_STARTGROUP gline
|
|
| IPSL_CONTENT oline
|
|
;
|
|
|
|
dline: cline { resetlexer(); }
|
|
| sline { resetlexer(); }
|
|
| csline { resetlexer(); }
|
|
;
|
|
|
|
gline: YY_STR ':' glist '=' action
|
|
;
|
|
|
|
oline: cline
|
|
| sline
|
|
| csline
|
|
;
|
|
|
|
assign: YY_STR assigning YY_STR
|
|
{ set_variable($1, $3);
|
|
resetlexer();
|
|
free($1);
|
|
free($3);
|
|
yyvarnext = 0;
|
|
}
|
|
;
|
|
|
|
assigning:
|
|
'=' { yyvarnext = 1; }
|
|
;
|
|
|
|
cline: tag ':' matchup '=' action { addtag($1, $3, NULL, &$5); }
|
|
;
|
|
|
|
sline: tag ':' '(' ')' ',' matchup '=' action { addtag($1, NULL, $6, &$8); }
|
|
;
|
|
|
|
csline: tag ':' matchup ',' matchup '=' action { addtag($1, $3, $5, &$7); }
|
|
;
|
|
|
|
glist: YY_STR
|
|
| glist ',' YY_STR
|
|
;
|
|
|
|
tag: YY_STR { $$ = $1; }
|
|
;
|
|
|
|
matchup:
|
|
onehalf { $$ = $1; }
|
|
| twohalves { $$ = $1; }
|
|
;
|
|
|
|
action: result { $$.act_val = $1.act_val;
|
|
$$.act_ip = $1.act_ip;
|
|
$$.act_port = $1.act_port; }
|
|
| result IPSL_ELSE result { $$.act_val = $1.act_val;
|
|
$$.act_else = $3.act_val;
|
|
if ($1.act_val == IPSL_REDIRECT) {
|
|
$$.act_ip = $1.act_ip;
|
|
$$.act_port = $1.act_port;
|
|
}
|
|
if ($3.act_val == IPSL_REDIRECT) {
|
|
$$.act_eip = $3.act_eip;
|
|
$$.act_eport = $3.act_eport;
|
|
}
|
|
}
|
|
|
|
result: IPSL_CLOSE { $$.act_val = IPSL_CLOSE; }
|
|
| IPSL_TRACK { $$.act_val = IPSL_TRACK; }
|
|
| redirect { $$.act_val = IPSL_REDIRECT;
|
|
$$.act_ip = $1.act_ip;
|
|
$$.act_port = $1.act_port; }
|
|
;
|
|
|
|
onehalf:
|
|
'(' YY_STR ')' { $$ = makepair($2, NULL); }
|
|
;
|
|
|
|
twohalves:
|
|
'(' YY_STR ',' YY_STR ')' { $$ = makepair($2, $4); }
|
|
;
|
|
|
|
redirect:
|
|
IPSL_REDIRECT '(' ipaddr ')' { $$.act_ip = $3;
|
|
$$.act_port = 0; }
|
|
| IPSL_REDIRECT '(' ipaddr ',' portnum ')'
|
|
{ $$.act_ip = $3;
|
|
$$.act_port = $5; }
|
|
;
|
|
|
|
|
|
ipaddr: YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER
|
|
{ $$ = combine($1,$3,$5,$7); }
|
|
| YY_STR { $$ = gethostip($1);
|
|
free($1);
|
|
}
|
|
;
|
|
|
|
portnum:
|
|
YY_NUMBER { $$ = htons($1); }
|
|
| YY_STR { $$ = getportnum($1);
|
|
free($1);
|
|
}
|
|
;
|
|
|
|
%%
|
|
|
|
|
|
static struct wordtab yywords[] = {
|
|
{ "close", IPSL_CLOSE },
|
|
{ "content", IPSL_CONTENT },
|
|
{ "else", IPSL_ELSE },
|
|
{ "start-group", IPSL_STARTGROUP },
|
|
{ "redirect", IPSL_REDIRECT },
|
|
{ "start", IPSL_START },
|
|
{ "track", IPSL_TRACK },
|
|
{ NULL, 0 }
|
|
};
|
|
|
|
|
|
int cram(dst, src)
|
|
char *dst;
|
|
char *src;
|
|
{
|
|
char c, *s, *t, *u;
|
|
int i, j, k;
|
|
|
|
c = *src;
|
|
s = src + 1;
|
|
t = strchr(s, c);
|
|
*t = '\0';
|
|
for (u = dst, i = 0; (i <= ISC_TLEN) && (s < t); ) {
|
|
c = *s++;
|
|
if (c == '\\') {
|
|
if (s >= t)
|
|
break;
|
|
j = k = 0;
|
|
do {
|
|
c = *s++;
|
|
if (j && (!ISDIGIT(c) || (c > '7') ||
|
|
(k >= 248))) {
|
|
*u++ = k, i++;
|
|
j = k = 0;
|
|
s--;
|
|
break;
|
|
}
|
|
i++;
|
|
|
|
if (ISALPHA(c) || (c > '7')) {
|
|
switch (c)
|
|
{
|
|
case 'n' :
|
|
*u++ = '\n';
|
|
break;
|
|
case 'r' :
|
|
*u++ = '\r';
|
|
break;
|
|
case 't' :
|
|
*u++ = '\t';
|
|
break;
|
|
default :
|
|
*u++ = c;
|
|
break;
|
|
}
|
|
} else if (ISDIGIT(c)) {
|
|
j = 1;
|
|
k <<= 3;
|
|
k |= (c - '0');
|
|
i--;
|
|
} else
|
|
*u++ = c;
|
|
} while ((i <= ISC_TLEN) && (s <= t) && (j > 0));
|
|
} else
|
|
*u++ = c, i++;
|
|
}
|
|
return i;
|
|
}
|
|
|
|
|
|
void printent(isc)
|
|
ipscan_t *isc;
|
|
{
|
|
char buf[ISC_TLEN+1];
|
|
u_char *u;
|
|
int i, j;
|
|
|
|
buf[ISC_TLEN] = '\0';
|
|
bcopy(isc->ipsc_ctxt, buf, ISC_TLEN);
|
|
printf("%s : (\"", isc->ipsc_tag);
|
|
printbuf(isc->ipsc_ctxt, isc->ipsc_clen, 0);
|
|
|
|
bcopy(isc->ipsc_cmsk, buf, ISC_TLEN);
|
|
printf("\", \"%s\"), (\"", buf);
|
|
|
|
printbuf(isc->ipsc_stxt, isc->ipsc_slen, 0);
|
|
|
|
bcopy(isc->ipsc_smsk, buf, ISC_TLEN);
|
|
printf("\", \"%s\") = ", buf);
|
|
|
|
switch (isc->ipsc_action)
|
|
{
|
|
case ISC_A_TRACK :
|
|
printf("track");
|
|
break;
|
|
case ISC_A_REDIRECT :
|
|
printf("redirect");
|
|
printf("(%s", inet_ntoa(isc->ipsc_ip));
|
|
if (isc->ipsc_port)
|
|
printf(",%d", isc->ipsc_port);
|
|
printf(")");
|
|
break;
|
|
case ISC_A_CLOSE :
|
|
printf("close");
|
|
break;
|
|
default :
|
|
break;
|
|
}
|
|
|
|
if (isc->ipsc_else != ISC_A_NONE) {
|
|
printf(" else ");
|
|
switch (isc->ipsc_else)
|
|
{
|
|
case ISC_A_TRACK :
|
|
printf("track");
|
|
break;
|
|
case ISC_A_REDIRECT :
|
|
printf("redirect");
|
|
printf("(%s", inet_ntoa(isc->ipsc_eip));
|
|
if (isc->ipsc_eport)
|
|
printf(",%d", isc->ipsc_eport);
|
|
printf(")");
|
|
break;
|
|
case ISC_A_CLOSE :
|
|
printf("close");
|
|
break;
|
|
default :
|
|
break;
|
|
}
|
|
}
|
|
printf("\n");
|
|
|
|
if (opts & OPT_DEBUG) {
|
|
for (u = (u_char *)isc, i = sizeof(*isc); i; ) {
|
|
printf("#");
|
|
for (j = 32; (j > 0) && (i > 0); j--, i--)
|
|
printf("%s%02x", (j & 7) ? "" : " ", *u++);
|
|
printf("\n");
|
|
}
|
|
}
|
|
if (opts & OPT_VERBOSE) {
|
|
printf("# hits %d active %d fref %d sref %d\n",
|
|
isc->ipsc_hits, isc->ipsc_active, isc->ipsc_fref,
|
|
isc->ipsc_sref);
|
|
}
|
|
}
|
|
|
|
|
|
void addtag(tstr, cp, sp, act)
|
|
char *tstr;
|
|
char **cp, **sp;
|
|
struct action *act;
|
|
{
|
|
ipscan_t isc, *iscp;
|
|
|
|
bzero((char *)&isc, sizeof(isc));
|
|
|
|
strncpy(isc.ipsc_tag, tstr, sizeof(isc.ipsc_tag));
|
|
isc.ipsc_tag[sizeof(isc.ipsc_tag) - 1] = '\0';
|
|
|
|
if (cp) {
|
|
isc.ipsc_clen = cram(isc.ipsc_ctxt, cp[0]);
|
|
if (cp[1]) {
|
|
if (cram(isc.ipsc_cmsk, cp[1]) != isc.ipsc_clen) {
|
|
fprintf(stderr,
|
|
"client text/mask strings different length\n");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (sp) {
|
|
isc.ipsc_slen = cram(isc.ipsc_stxt, sp[0]);
|
|
if (sp[1]) {
|
|
if (cram(isc.ipsc_smsk, sp[1]) != isc.ipsc_slen) {
|
|
fprintf(stderr,
|
|
"server text/mask strings different length\n");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (act->act_val == IPSL_CLOSE) {
|
|
isc.ipsc_action = ISC_A_CLOSE;
|
|
} else if (act->act_val == IPSL_TRACK) {
|
|
isc.ipsc_action = ISC_A_TRACK;
|
|
} else if (act->act_val == IPSL_REDIRECT) {
|
|
isc.ipsc_action = ISC_A_REDIRECT;
|
|
isc.ipsc_ip = act->act_ip;
|
|
isc.ipsc_port = act->act_port;
|
|
fprintf(stderr, "%d: redirect unsupported\n", yylineNum + 1);
|
|
}
|
|
|
|
if (act->act_else == IPSL_CLOSE) {
|
|
isc.ipsc_else = ISC_A_CLOSE;
|
|
} else if (act->act_else == IPSL_TRACK) {
|
|
isc.ipsc_else = ISC_A_TRACK;
|
|
} else if (act->act_else == IPSL_REDIRECT) {
|
|
isc.ipsc_else = ISC_A_REDIRECT;
|
|
isc.ipsc_eip = act->act_eip;
|
|
isc.ipsc_eport = act->act_eport;
|
|
fprintf(stderr, "%d: redirect unsupported\n", yylineNum + 1);
|
|
}
|
|
|
|
if (!(opts & OPT_DONOTHING)) {
|
|
iscp = &isc;
|
|
if (opts & OPT_REMOVE) {
|
|
if (ioctl(fd, SIOCRMSCA, &iscp) == -1)
|
|
perror("SIOCADSCA");
|
|
} else {
|
|
if (ioctl(fd, SIOCADSCA, &iscp) == -1)
|
|
perror("SIOCADSCA");
|
|
}
|
|
}
|
|
|
|
if (opts & OPT_VERBOSE)
|
|
printent(&isc);
|
|
}
|
|
|
|
|
|
char **makepair(s1, s2)
|
|
char *s1, *s2;
|
|
{
|
|
char **a;
|
|
|
|
a = malloc(sizeof(char *) * 2);
|
|
a[0] = s1;
|
|
a[1] = s2;
|
|
return a;
|
|
}
|
|
|
|
|
|
struct in_addr combine(a1, a2, a3, a4)
|
|
int a1, a2, a3, a4;
|
|
{
|
|
struct in_addr in;
|
|
|
|
a1 &= 0xff;
|
|
in.s_addr = a1 << 24;
|
|
a2 &= 0xff;
|
|
in.s_addr |= (a2 << 16);
|
|
a3 &= 0xff;
|
|
in.s_addr |= (a3 << 8);
|
|
a4 &= 0xff;
|
|
in.s_addr |= a4;
|
|
in.s_addr = htonl(in.s_addr);
|
|
return in;
|
|
}
|
|
|
|
|
|
struct in_addr gethostip(host)
|
|
char *host;
|
|
{
|
|
struct hostent *hp;
|
|
struct in_addr in;
|
|
|
|
in.s_addr = 0;
|
|
|
|
hp = gethostbyname(host);
|
|
if (!hp)
|
|
return in;
|
|
bcopy(hp->h_addr, (char *)&in, sizeof(in));
|
|
return in;
|
|
}
|
|
|
|
|
|
int getportnum(port)
|
|
char *port;
|
|
{
|
|
struct servent *s;
|
|
|
|
s = getservbyname(port, "tcp");
|
|
if (s == NULL)
|
|
return -1;
|
|
return s->s_port;
|
|
}
|
|
|
|
|
|
void showlist()
|
|
{
|
|
ipscanstat_t ipsc, *ipscp = &ipsc;
|
|
ipscan_t isc;
|
|
|
|
if (ioctl(fd, SIOCGSCST, &ipscp) == -1)
|
|
perror("ioctl(SIOCGSCST)");
|
|
else if (opts & OPT_SHOWLIST) {
|
|
while (ipsc.iscs_list != NULL) {
|
|
if (kmemcpy((char *)&isc, (u_long)ipsc.iscs_list,
|
|
sizeof(isc)) == -1) {
|
|
perror("kmemcpy");
|
|
break;
|
|
} else {
|
|
printent(&isc);
|
|
ipsc.iscs_list = isc.ipsc_next;
|
|
}
|
|
}
|
|
} else {
|
|
printf("scan entries loaded\t%d\n", ipsc.iscs_entries);
|
|
printf("scan entries matches\t%ld\n", ipsc.iscs_acted);
|
|
printf("negative matches\t%ld\n", ipsc.iscs_else);
|
|
}
|
|
}
|
|
|
|
|
|
void usage(prog)
|
|
char *prog;
|
|
{
|
|
fprintf(stderr, "Usage:\t%s [-dnrv] -f <filename>\n", prog);
|
|
fprintf(stderr, "\t%s [-dlv]\n", prog);
|
|
exit(1);
|
|
}
|
|
|
|
|
|
int main(argc, argv)
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
FILE *fp = NULL;
|
|
int c;
|
|
|
|
(void) yysettab(yywords);
|
|
|
|
if (argc < 2)
|
|
usage(argv[0]);
|
|
|
|
while ((c = getopt(argc, argv, "df:lnrsv")) != -1)
|
|
switch (c)
|
|
{
|
|
case 'd' :
|
|
opts |= OPT_DEBUG;
|
|
yydebug++;
|
|
break;
|
|
case 'f' :
|
|
if (!strcmp(optarg, "-"))
|
|
fp = stdin;
|
|
else {
|
|
fp = fopen(optarg, "r");
|
|
if (!fp) {
|
|
perror("open");
|
|
exit(1);
|
|
}
|
|
}
|
|
yyin = fp;
|
|
break;
|
|
case 'l' :
|
|
opts |= OPT_SHOWLIST;
|
|
break;
|
|
case 'n' :
|
|
opts |= OPT_DONOTHING;
|
|
break;
|
|
case 'r' :
|
|
opts |= OPT_REMOVE;
|
|
break;
|
|
case 's' :
|
|
opts |= OPT_STAT;
|
|
break;
|
|
case 'v' :
|
|
opts |= OPT_VERBOSE;
|
|
break;
|
|
}
|
|
|
|
if (!(opts & OPT_DONOTHING)) {
|
|
fd = open(IPL_SCAN, O_RDWR);
|
|
if (fd == -1) {
|
|
perror("open(IPL_SCAN)");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
if (fp != NULL) {
|
|
yylineNum = 1;
|
|
|
|
while (!feof(fp))
|
|
yyparse();
|
|
fclose(fp);
|
|
exit(0);
|
|
}
|
|
|
|
if (opts & (OPT_SHOWLIST|OPT_STAT)) {
|
|
showlist();
|
|
exit(0);
|
|
}
|
|
exit(1);
|
|
}
|