package tcpspy tags 616473 + ipv6 patch A functional patch for IPv6 support is attached.
Best regards, Mats Erik Andersson, DM
Description: Implement IPv6 support. Functional IPv6 support depends on an extended grammar, an extended parser, and also reading of "/proc/net/tcp6". . Using a union large enough to accomodate "struct in_addr" and "struct in6_addr" a unified evaluation of the two address family is possible. . The implementation of CIDR netmasks for IPv4 is conducted. . Finally, the manual pages are expanded. Author: Mats Erik Andersson <[email protected]> Forwarded: no Last-Update: 2011-03-08 diff -Naur tcpspy-1.7d.debian/debian/tcpspy.rules.5 tcpspy-1.7d/debian/tcpspy.rules.5 --- tcpspy-1.7d.debian/debian/tcpspy.rules.5 2011-03-03 13:38:02.000000000 +0100 +++ tcpspy-1.7d/debian/tcpspy.rules.5 2011-03-08 16:33:19.000000000 +0100 @@ -60,9 +60,9 @@ .TP line 2 - for user whose UID is 1003 .TP -line 3 - to localhost:22 or localhost:21 +line 3 - to *:22 or *:21 (both locally) .TP -line 4 - for user "joedoe" to localhost:23 or to 192.168.1.20 (remote) +line 4 - for user "joedoe" to *:23 (local) or to 192.168.1.20 (remote) .LP Everything from an "#" signal and the end of the line will not be evaluated. .LP @@ -79,6 +79,12 @@ .BI user " \N'34'username\N'34'" Same as above, but using a username instead of a user id. .TP +.BI ip +True if the connection is IPv4. +.TP +.BI ip6 +True if the connection is IPv6. +.TP .BI lport " port" True if the local end of the connection has port number .IR port . @@ -108,9 +114,16 @@ but compares the port number of the remote end of the connection. .TP .BI laddr " n.n.n.n[/m.m.m.m]" +.TP +.BI laddr " n.n.n.n/m" +.TP +.BI laddr " ip6-addr[/m]" Interpreted as a "net/mask" expression; true if "net" is equal to the bitwise AND of the local address of the connection and "mask". If no mask is specified, -a default mask with all bits set (255.255.255.255) is used. +a default mask with all bits set (255.255.255.255) is used. The CIDR type netmask +is also possible. With IPv6 only a prefix length netmask is allowed, and the +length defaults to 128. Depending on the address family, these rules contain +an implicit match condition "ip" or "ip6", respectively. .TP .B raddr Same as diff -Naur tcpspy-1.7d.debian/rule.c tcpspy-1.7d/rule.c --- tcpspy-1.7d.debian/rule.c 2002-01-25 02:00:50.000000000 +0100 +++ tcpspy-1.7d/rule.c 2011-03-04 20:05:17.000000000 +0100 @@ -70,12 +70,16 @@ void rule_gen_rport (u_int16_t low, u_int16_t high); void rule_gen_laddr (u_int32_t addr, u_int32_t mask); void rule_gen_raddr (u_int32_t addr, u_int32_t mask); +void rule_gen_laddr6 (u_int32_t addr[4], u_int32_t mask[4]); +void rule_gen_raddr6 (u_int32_t addr[4], u_int32_t mask[4]); +void rule_gen_ip (void); +void rule_gen_ip6 (void); void rule_gen_exe (unsigned long estrid); void rule_gen_or (void); void rule_gen_and (void); void rule_gen_not (void); -int rule_eval (uid_t r_uid, u_int32_t laddr, u_int16_t lport, - u_int32_t raddr, u_int16_t rport, const char *mexe); +int rule_eval (int maf, uid_t r_uid, u_int32_t *laddr, u_int16_t lport, + u_int32_t *raddr, u_int16_t rport, const char *mexe); void rule_parse (const char *r); unsigned long st_store (const char *s); @@ -117,6 +121,10 @@ #define BC_LADDR 4 #define BC_RADDR 5 #define BC_EXE 6 +#define BC_LADDR6 7 +#define BC_RADDR6 8 +#define BC_IP 9 +#define BC_IP6 10 #define BC_OR 64 #define BC_AND 65 @@ -186,6 +194,62 @@ } /* + * rule_gen_laddr6 () + * + * Generate a local IPv6 address comparison. + */ +void rule_gen_laddr6 (u_int32_t addr[4], u_int32_t mask[4]) +{ + add_code (BC_LADDR6); + add_code ((bytecode_t) addr[0]); + add_code ((bytecode_t) addr[1]); + add_code ((bytecode_t) addr[2]); + add_code ((bytecode_t) addr[3]); + add_code ((bytecode_t) mask[0]); + add_code ((bytecode_t) mask[1]); + add_code ((bytecode_t) mask[2]); + add_code ((bytecode_t) mask[3]); +} + +/* + * rule_gen_raddr6 () + * + * Generate a remote IPv6 address comparison. + */ +void rule_gen_raddr6 (u_int32_t addr[4], u_int32_t mask[4]) +{ + add_code (BC_RADDR6); + add_code ((bytecode_t) addr[0]); + add_code ((bytecode_t) addr[1]); + add_code ((bytecode_t) addr[2]); + add_code ((bytecode_t) addr[3]); + add_code ((bytecode_t) mask[0]); + add_code ((bytecode_t) mask[1]); + add_code ((bytecode_t) mask[2]); + add_code ((bytecode_t) mask[3]); +} + +/* + * rule_gen_ip () + * + * Generate an IPv4 address check. + */ +void rule_gen_ip (void) +{ + add_code (BC_IP); +} + +/* + * rule_gen_ip () + * + * Generate an IPv6 address check. + */ +void rule_gen_ip6 (void) +{ + add_code (BC_IP6); +} + +/* * rule_gen_exe () * * Generate an executable filename comparison. @@ -284,8 +348,8 @@ * * Returns nonzero if the connection matches the rule, zero otherwise. */ -int rule_eval (uid_t muid, u_int32_t mladdr, u_int16_t mlport, - u_int32_t mraddr, u_int16_t mrport, const char *mexe) +int rule_eval (int maf, uid_t muid, u_int32_t *mladdr, u_int16_t mlport, + u_int32_t *mraddr, u_int16_t mrport, const char *mexe) { size_t ip = 0; unsigned int c; @@ -293,6 +357,8 @@ static size_t stack_size = 0, stack_ptr = 0; stack_ptr = 0; + PUSH(0); /* Put a single FALSE on the stack. This protects + * against a segfault from a simple rule. */ for (ip = 0; ip < code_length; ) { c = NEXTCODE; @@ -360,7 +426,9 @@ SHORTCIRCUIT; - PUSH (((mladdr & mask) == addr) ? 1 : 0); + PUSH (( (maf == AF_INET) && + ((*mladdr & mask) == addr) ) + ? 1 : 0); } break; case BC_RADDR: @@ -375,10 +443,77 @@ SHORTCIRCUIT; - PUSH (((mraddr & mask) == addr) ? 1 : 0); + PUSH (( (maf == AF_INET) && + ((*mraddr & mask) == addr) ) + ? 1 : 0); } break; + case BC_LADDR6: + /* + * Local IPv6 address comparison. + */ + { + u_int32_t addr[4], mask[4], patch[4]; + int j; + + for (j = 0; j < 4; ++j) + addr[j] = (u_int32_t) NEXTCODE; + for (j = 0; j < 4; ++j) + mask[j] = (u_int32_t) NEXTCODE; + SHORTCIRCUIT; + + for (j = 0; j < 4; ++j) + patch[j] = mladdr[j] & mask[j]; + + PUSH (( (maf == AF_INET6) && + (memcmp (patch, addr, sizeof (patch)) == 0) ) + ? 1 : 0); + } + break; + case BC_RADDR6: + /* + * Remote IPv6 address comparison. + */ + { + u_int32_t addr[4], mask[4], patch[4]; + int j; + + for (j = 0; j < 4; ++j) + addr[j] = (u_int32_t) NEXTCODE; + for (j = 0; j < 4; ++j) + mask[j] = (u_int32_t) NEXTCODE; + + SHORTCIRCUIT; + + for (j = 0; j < 4; ++j) + patch[j] = mraddr[j] & mask[j]; + + PUSH (( (maf == AF_INET6) && + (memcmp (patch, addr, sizeof (patch)) == 0) ) + ? 1 : 0); + } + break; + case BC_IP: + /* + * Verify that the address is IPv4. + */ + { + SHORTCIRCUIT; + + PUSH ( (maf == AF_INET) ? 1 : 0); + } + break; + case BC_IP6: + /* + * Verify that the address is IPv6. + */ + { + SHORTCIRCUIT; + + PUSH ( (maf == AF_INET6) ? 1 : 0); + } + break; case BC_EXE: /* * Executable filename comparison. diff -Naur tcpspy-1.7d.debian/rule_grammar.y tcpspy-1.7d/rule_grammar.y --- tcpspy-1.7d.debian/rule_grammar.y 2002-01-25 02:01:02.000000000 +0100 +++ tcpspy-1.7d/rule_grammar.y 2011-03-04 03:19:47.000000000 +0100 @@ -57,6 +57,9 @@ struct { u_int32_t addr, mask; } addr; + struct { + u_int32_t addr[4], mask[4]; + } addr6; unsigned long exe; } @@ -68,6 +71,8 @@ %token <port> PORT_SPEC %token LADDR RADDR %token <addr> ADDR_SPEC +%token <addr6> ADDR6_SPEC +%token IP IP6 %token EXE %token <exe> EXE_SPEC @@ -99,6 +104,10 @@ | RPORT PORT_SPEC { rule_gen_rport ($2.low, $2.high); } | LADDR ADDR_SPEC { rule_gen_laddr ($2.addr, $2.mask); } | RADDR ADDR_SPEC { rule_gen_raddr ($2.addr, $2.mask); } + | LADDR ADDR6_SPEC { rule_gen_laddr6 ($2.addr, $2.mask); } + | RADDR ADDR6_SPEC { rule_gen_raddr6 ($2.addr, $2.mask); } + | IP { rule_gen_ip (); } + | IP6 { rule_gen_ip6 (); } | EXE EXE_SPEC { rule_gen_exe ($2); } ; diff -Naur tcpspy-1.7d.debian/rule.h tcpspy-1.7d/rule.h --- tcpspy-1.7d.debian/rule.h 2002-01-25 02:00:50.000000000 +0100 +++ tcpspy-1.7d/rule.h 2011-03-04 03:22:38.000000000 +0100 @@ -44,12 +44,16 @@ void rule_gen_rport (u_int16_t low, u_int16_t high); void rule_gen_laddr (u_int32_t addr, u_int32_t mask); void rule_gen_raddr (u_int32_t addr, u_int32_t mask); +void rule_gen_laddr6 (u_int32_t addr6[4], u_int32_t mask6[4]); +void rule_gen_raddr6 (u_int32_t addr6[4], u_int32_t mask6[4]); +void rule_gen_ip (void); +void rule_gen_ip6 (void); void rule_gen_exe (unsigned long estrid); void rule_gen_or (void); void rule_gen_and (void); void rule_gen_not (void); -int rule_eval (uid_t muid, u_int32_t mladdr, u_int16_t mlport, - u_int32_t mraddr, u_int16_t mrport, const char *mexe); +int rule_eval (int maf, uid_t muid, u_int32_t *mladdr, u_int16_t mlport, + u_int32_t *mraddr, u_int16_t mrport, const char *mexe); void rule_parse (const char *r); void rule_parse_file (FILE *fp); diff -Naur tcpspy-1.7d.debian/rule_lexer.l tcpspy-1.7d/rule_lexer.l --- tcpspy-1.7d.debian/rule_lexer.l 2002-01-25 02:01:02.000000000 +0100 +++ tcpspy-1.7d/rule_lexer.l 2011-03-04 18:36:53.000000000 +0100 @@ -66,6 +66,10 @@ NUMBER {DIGIT}+ QSTRING \"[^"]*\" IPADDR {NUMBER}\.{NUMBER}\.{NUMBER}\.{NUMBER} +HEXGROUP ([[:xdigit:]]{1,4}) +HEXBLOCK ({HEXGROUP}(:{HEXGROUP}){0,7}) +HEXPART ((::)?{HEXBLOCK}|({HEXBLOCK}::({HEXBLOCK}?))) +IP6ADDR ({HEXPART}(:{IPADDR})?) %% @@ -74,6 +78,8 @@ "or" return OR; "and" return AND; "not" return NOT; +"ip" return IP; +"ip6" return IP6; <INITIAL>user { BEGIN (WANT_USER); @@ -152,25 +158,70 @@ BEGIN (WANT_ADDR); return RADDR; } -<WANT_ADDR>{IPADDR}(\/{IPADDR})? { +<WANT_ADDR>{IPADDR}(\/{IPADDR}|\/{NUMBER})? { struct in_addr in; + int pfx; char *s; BEGIN (INITIAL); yytext[yyleng] = '\0'; if ((s = strchr (yytext, '/')) != NULL) { *s++ = '\0'; - if (inet_aton (s, &in) == 0) - YY_FATAL_ERROR ("bad net mask"); - rulelval.addr.mask = in.s_addr; + if (strchr (s, '.')) { + if (inet_aton (s, &in) == 0) + YY_FATAL_ERROR ("bad net mask"); + rulelval.addr.mask = in.s_addr; + } else { + pfx = atoi (s); + if ((pfx < 1) || (pfx > 32)) + YY_FATAL_ERROR ("bad net mask"); + rulelval.addr.mask = htonl (0xFFFFFFFF << (32 - pfx)); + } } else rulelval.addr.mask = 0xFFFFFFFF; + if (inet_aton (yytext, &in) == 0) YY_FATAL_ERROR ("bad IP address"); - rulelval.addr.addr = in.s_addr; + rulelval.addr.addr = in.s_addr & rulelval.addr.mask; return ADDR_SPEC; } +<WANT_ADDR>{IP6ADDR}(\/{NUMBER})? { + struct in6_addr in6; + int pfx, j, grp, rem; + char *s; + uint8_t *bmask; + + BEGIN (INITIAL); + + yytext[yyleng] = '\0'; + for (j = 0; j < 4; ++j) + rulelval.addr6.mask[j] = 0xFFFFFFFF; + if ((s = strchr (yytext, '/')) != NULL) { + *s++ = '\0'; + pfx = atoi (s); + if ((pfx < 1) || (pfx > 128)) + YY_FATAL_ERROR ("bad net mask"); + grp = pfx / 8; + rem = pfx % 8; + if (grp < 16) { + /* Non-trivial netmask needs calculation. + * Cast to access network byte ordering. */ + bmask = (uint8_t *) rulelval.addr6.mask; + bmask[grp] <<= (8 - rem); + for (j = grp + 1; j < 16; ++j) + bmask[j] = 0; + } + } + + if (inet_pton (AF_INET6, yytext, &in6) < 1) + YY_FATAL_ERROR ("bad IP address"); + for (j = 0; j < 4; ++j) + rulelval.addr6.addr[j] = in6.s6_addr32[j] & rulelval.addr6.mask[j]; + + return ADDR6_SPEC; + } + <INITIAL>exe { BEGIN (WANT_EXE); return EXE; diff -Naur tcpspy-1.7d.debian/tcpspy.8 tcpspy-1.7d/tcpspy.8 --- tcpspy-1.7d.debian/tcpspy.8 2002-01-25 02:00:50.000000000 +0100 +++ tcpspy-1.7d/tcpspy.8 2011-03-08 16:18:30.000000000 +0100 @@ -133,6 +133,12 @@ .BI user " \N'34'username\N'34'" Same as above, but using a username instead of a user id. .TP +.BI ip +True if the connection is IPv4. +.TP +.BI ip6 +True if the connection is IPv6. +.TP .BI lport " port" True if the local end of the connection has port number .IR port . @@ -162,9 +168,16 @@ but compares the port number of the remote end of the connection. .TP .BI laddr " n.n.n.n[/m.m.m.m]" +.TP +.BI laddr " n.n.n.n/m" +.TP +.BI laddr " ip6-addr[/m]" Interpreted as a "net/mask" expression; true if "net" is equal to the bitwise AND of the local address of the connection and "mask". If no mask is specified, -a default mask with all bits set (255.255.255.255) is used. +a default mask with all bits set (255.255.255.255) is used. The CIDR type netmask +is also possible. With IPv6 only a prefix length netmask is allowed, and the +length defaults to 128. Depending on the address family, these rules contain +an implicit match condition "ip" or "ip6", respectively. .TP .B raddr Same as diff -Naur tcpspy-1.7d.debian/tcpspy.c tcpspy-1.7d/tcpspy.c --- tcpspy-1.7d.debian/tcpspy.c 2002-01-25 02:01:02.000000000 +0100 +++ tcpspy-1.7d/tcpspy.c 2011-03-08 16:07:13.000000000 +0100 @@ -31,6 +31,7 @@ * $Id: tcpspy.c,v 1.39.1.3 2001/07/02 11:55:36 tim Stab $ */ +#define __USE_GNU /* s6_addr32 */ #include <arpa/inet.h> #include <assert.h> #include <ctype.h> @@ -83,9 +84,16 @@ * easier. */ typedef struct conn { - unsigned long lcl; + int af; + union { + unsigned long lcl; + unsigned long lcl6[4]; + }; unsigned long lclp; - unsigned long rmt; + union { + unsigned long rmt; + unsigned long rmt6[4]; + }; unsigned long rmtp; unsigned long uid; unsigned long ino; @@ -149,7 +157,9 @@ assert (c != NULL); - h = c->lcl ^ c->lclp ^ c->rmt ^ c->rmtp ^ c->uid ^ c->ino; + h = c->lcl6[0] ^ c->lcl6[1] ^ c->lcl6[2] ^ c->lcl6[3]; + h = h ^ c->rmt6[0] ^ c->rmt6[1] ^ c->rmt6[2] ^ c->rmt6[3]; + h = h ^ c->lclp ^ c->rmtp ^ c->uid ^ c->ino; return h % CONNTABLE_BUCKETS; } @@ -194,8 +204,10 @@ bucket = ct->buckets[ct_hash (c)]; while (bucket != NULL) { - if ((c->lcl == bucket->lcl) && (c->lclp == bucket->lclp) && - (c->rmt == bucket->rmt) && (c->rmtp == bucket->rmtp) && + if ((c->af == bucket->af) && + (memcmp(c->lcl6, bucket->lcl6, sizeof (c->lcl6)) == 0) && + (memcmp(c->rmt6, bucket->rmt6, sizeof (c->rmt6)) == 0) && + (c->lclp == bucket->lclp) && (c->rmtp == bucket->rmtp) && (c->uid == bucket->uid) && (c->ino == bucket->ino)) { return 1; } @@ -213,7 +225,7 @@ */ static int ct_read (conntable_t *ct) { - static FILE *fp = NULL; + static FILE *fp = NULL, *fp6 = NULL; char buf[1024]; conn_t c; @@ -225,12 +237,24 @@ } rewind (fp); + if (fp6 == NULL) { + fp6 = fopen ("/proc/net/tcp6", "r"); +#ifndef RELAX_PROC_IP6 + if (fp6 == NULL) panic ("/proc/net/tcp6: %s", strerror (errno)); +#endif + } + if (fp6) + rewind (fp6); + if (fgets (buf, sizeof (buf), fp) == NULL) panic ("/proc/net/tcp: missing header"); while (fgets (buf, sizeof (buf), fp) != NULL) { unsigned long st; + memset (c.lcl6, 0, sizeof (c.lcl6)); + memset (c.rmt6, 0, sizeof (c.rmt6)); + c.af = AF_INET; if (sscanf (buf, "%*d: %lx:%lx %lx:%lx %lx %*x:%*x %*x:%*x %*x %lu %*d %lu", &c.lcl, &c.lclp, &c.rmt, &c.rmtp, &st, &c.uid, &c.ino) != 7) { logmsg ("/proc/net/tcp: warning: incomplete line"); continue; @@ -243,6 +267,33 @@ return 0; } + /* Some systems do not use IPv6. */ + if (fp6) { + if (fgets (buf, sizeof (buf), fp6) == NULL) + panic ("/proc/net/tcp6: missing header"); + + while (fgets (buf, sizeof (buf), fp6) != NULL) { + unsigned long st; + + memset (c.lcl6, 0, sizeof (c.lcl6)); + memset (c.rmt6, 0, sizeof (c.rmt6)); + c.af = AF_INET6; + if (sscanf (buf, "%*d: %8lx%8lx%8lx%8lx:%lx %8lx%8lx%8lx%8lx:%lx %lx %*x:%*x %*x:%*x %*x %lu %*d %lu", + &c.lcl6[0], &c.lcl6[1], &c.lcl6[2], &c.lcl6[3], &c.lclp, + &c.rmt6[0], &c.rmt6[1], &c.rmt6[2], &c.rmt6[3], &c.rmtp, + &st, &c.uid, &c.ino) != 13) { + logmsg ("/proc/net/tcp6: warning: incomplete line"); + continue; + } + if ((c.ino == 0) || (st != TCP_ESTABLISHED)) continue; + if (showprocs != 0) + huntinode ((ino_t) c.ino, c.exe, sizeof (c.exe)); + + if (ct_add (ct, &c) == 0) + return 0; + } + } + return 1; } @@ -323,7 +374,7 @@ if (len < 0) continue; lnktgt[len] = '\0'; - if (sscanf (lnktgt, "socket:[%lu]", &this_ino) != 1) + if (sscanf (lnktgt, "socket:[%lu]", (long unsigned int *) &this_ino) != 1) continue; if (this_ino != i) continue; @@ -351,9 +402,7 @@ */ static void logconn (conn_t *c, const char *action) { - struct in_addr in; - char laddr[16], raddr[16]; /* assume IPv4 nnn.nnn.nnn.nnn\0 */ - char *n; + char laddr[INET6_ADDRSTRLEN], raddr[INET6_ADDRSTRLEN]; /* space reserved for numeric IPv6 */ struct passwd *pw; char uidbuf[32]; char *user; @@ -363,16 +412,16 @@ assert (c != NULL); assert (action != NULL); - if ((gotrule != 0) && (rule_eval (c->uid, c->lcl, c->lclp, c->rmt, c->rmtp, (showprocs != 0) ? c->exe : NULL) == 0)) + if ((gotrule != 0) && + (rule_eval (c->af, c->uid, (u_int32_t *) c->lcl6, c->lclp, + (u_int32_t *) c->rmt6, c->rmtp, (showprocs != 0) ? c->exe : NULL) == 0)) return; - in.s_addr = c->lcl; - n = inet_ntoa (in); - strncpy (laddr, n, sizeof (laddr)); + if ((inet_ntop (c->af, c->lcl6, laddr, sizeof (laddr)) == NULL) && (errno == ENOSPC)) + laddr[0] = '\0'; laddr[sizeof (laddr) - 1] = '\0'; - in.s_addr = c->rmt; - n = inet_ntoa (in); - strncpy (raddr, n, sizeof (raddr)); + if ((inet_ntop (c->af, c->rmt6, raddr, sizeof (raddr)) == NULL) && (errno == ENOSPC)) + raddr[0] = '\0'; raddr[sizeof (raddr) - 1] = '\0'; snprintf (lport, sizeof (lport), "%lu", c->lclp); diff -Naur tcpspy-1.7d.debian/tcpspy.rules tcpspy-1.7d/tcpspy.rules --- tcpspy-1.7d.debian/tcpspy.rules 2011-03-03 13:38:02.000000000 +0100 +++ tcpspy-1.7d/tcpspy.rules 2011-03-08 16:35:59.000000000 +0100 @@ -15,6 +15,10 @@ # Same as above, but using a username instead of a # user id. # +# ip True if the connection is IPv4. +# +# ip6 True if the connection is IPv6. +# # lport port # True if the local end of the connection has port # number port. @@ -35,11 +39,17 @@ # remote end of the connection. # # laddr n.n.n.n[/m.m.m.m] +# laddr n.n.n.n/m +# laddr ip6-addr[/m] # Interpreted as a "net/mask" expression; true if # "net" is equal to the bitwise AND of the local # address of the connection and "mask". If no mask is # specified, a default mask with all bits set -# (255.255.255.255) is used. +# (255.255.255.255) is used. The CIDR type netmask is +# also possible. With IPv6 only a prefix length netmask +# is allowed, and the length defaults to 128. Depending +# on the address family, these rules contain an implicit +# match condition "ip" or "ip6", respectively. # # raddr Same as laddr but compares the remote address. # diff -Naur tcpspy-1.7d.debian/tcpspy.rules.5 tcpspy-1.7d/tcpspy.rules.5 --- tcpspy-1.7d.debian/tcpspy.rules.5 2011-03-03 13:38:02.000000000 +0100 +++ tcpspy-1.7d/tcpspy.rules.5 2011-03-08 16:32:28.000000000 +0100 @@ -60,9 +60,9 @@ .TP line 2 - for user whose UID is 1003 .TP -line 3 - to localhost:22 or localhost:21 +line 3 - to *:22 or *:21 (both locally) .TP -line 4 - for user "joedoe" to localhost:23 or to 192.168.1.20 (remote) +line 4 - for user "joedoe" to *:23 (local) or to 192.168.1.20 (remote) .LP Everything from an "#" signal and the end of the line will not be evaluated. .LP @@ -79,6 +79,12 @@ .BI user " \N'34'username\N'34'" Same as above, but using a username instead of a user id. .TP +.BI ip +True if the connection is IPv4. +.TP +.BI ip6 +True if the connection is IPv6. +.TP .BI lport " port" True if the local end of the connection has port number .IR port . @@ -108,9 +114,16 @@ but compares the port number of the remote end of the connection. .TP .BI laddr " n.n.n.n[/m.m.m.m]" +.TP +.BI laddr " n.n.n.n/m" +.TP +.BI laddr " ip6-addr[/m]" Interpreted as a "net/mask" expression; true if "net" is equal to the bitwise AND of the local address of the connection and "mask". If no mask is specified, -a default mask with all bits set (255.255.255.255) is used. +a default mask with all bits set (255.255.255.255) is used. The CIDR type netmask +is also possible. With IPv6 only a prefix length netmask is allowed, and the +length defaults to 128. Depending on the address family, these rules contain +an implicit match condition "ip" or "ip6", respectively. .TP .B raddr Same as
signature.asc
Description: Digital signature

