diff --git a/CHANGES b/CHANGES index ef00d33..212c51c 100644 --- a/CHANGES +++ b/CHANGES @@ -43,6 +43,12 @@ corrections: Substituted cumbersom ISPEED_OFFSET mechanism for cfsetispeed() calls + With TCP6-LISTEN and the other passive IPv6 addresses the range option + just failed: due to a bug in the syntax parser and two more bugs in + the xiocheckrange_ip6() function. + The syntax has now been changed from "[::1/128]" to "[::1]/128"! + Thanks Leah Neukirchen for sending an initial fix. + testing: test.sh: Show a warning when phase-1 (insecure phase) of a security test fails diff --git a/doc/socat.yo b/doc/socat.yo index 258686e..2839887 100644 --- a/doc/socat.yo +++ b/doc/socat.yo @@ -2266,8 +2266,8 @@ startdit() label(OPTION_RANGE)dit(bf(tt(range=))) After accepting a connection, tests if the peer is within em(range). For IPv4 addresses, address-range takes the form address/bits, e.g. - 10.0.0.0/8, or address:mask, e.g. 10.0.0.0:255.0.0.0 (link(example)(EXAMPLE_OPTION_RANGE)); for IPv6, it is [ip6-address/bits], e.g. [::1/128]. - If the client address does not match, socat() issues a warning and keeps + 10.0.0.0/8, or address:mask, e.g. 10.0.0.0:255.0.0.0 (link(example)(EXAMPLE_OPTION_RANGE)); for IPv6, it is [ip6-address]/bits, e.g. [::1]/128. + If the client address does not match, socat() refuses the connection attempt, issues a warning, and keeps listening/receiving. label(OPTION_TCPWRAPPERS)dit(bf(tt(tcpwrap[=]))) Uses Wietse Venema's libwrap (tcpd) library to determine diff --git a/test.sh b/test.sh index ff105da..6a7d3eb 100755 --- a/test.sh +++ b/test.sh @@ -5576,7 +5576,7 @@ elif ! feat=$(testaddrs tcp ip6) || ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) else -testserversec "$N" "$TEST" "$opts" "tcp6-l:$PORT,reuseaddr,fork,retry=1" "" "range=[::2/128]" "tcp6:[::1]:$PORT" 6 tcp $PORT 0 +testserversec "$N" "$TEST" "$opts" "tcp6-l:$PORT,reuseaddr,fork,retry=1" "" "range=[::2]/128" "tcp6:[::1]:$PORT" 6 tcp $PORT 0 fi ;; # NUMCOND, feats esac PORT=$((PORT+1)) @@ -5695,8 +5695,8 @@ elif ! feat=$(testaddrs tcp ip6) || ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) else -#testserversec "$N" "$TEST" "$opts" "udp6-l:$PORT,reuseaddr,fork" "" "range=[::2/128]" "udp6:[::1]:$PORT" 6 udp $PORT 0 -testserversec "$N" "$TEST" "$opts" "udp6-l:$PORT,reuseaddr" "" "range=[::2/128]" "udp6:[::1]:$PORT" 6 udp $PORT 0 +#testserversec "$N" "$TEST" "$opts" "udp6-l:$PORT,reuseaddr,fork" "" "range=[::2]/128" "udp6:[::1]:$PORT" 6 udp $PORT 0 +testserversec "$N" "$TEST" "$opts" "udp6-l:$PORT,reuseaddr" "" "range=[::2]/128" "udp6:[::1]:$PORT" 6 udp $PORT 0 fi ;; # NUMCOND, feats esac PORT=$((PORT+1)) @@ -5868,7 +5868,7 @@ elif ! feat=$(testaddrs tcp ip6) || ! runsip6 >/dev/null; then numCANT=$((numCANT+1)) else gentestcert6 testsrv6 -testserversec "$N" "$TEST" "$opts" "ssl-l:$PORT,pf=ip6,reuseaddr,fork,retry=1,$SOCAT_EGD,verify=0,cert=testsrv6.crt,key=testsrv6.key" "" "range=[::2/128]" "ssl:[::1]:$PORT,cafile=testsrv6.crt,$SOCAT_EGD" 6 tcp $PORT -1 +testserversec "$N" "$TEST" "$opts" "ssl-l:$PORT,pf=ip6,reuseaddr,fork,retry=1,$SOCAT_EGD,verify=0,cert=testsrv6.crt,key=testsrv6.key" "" "range=[::2]/128" "ssl:[::1]:$PORT,cafile=testsrv6.crt,$SOCAT_EGD" 6 tcp $PORT -1 fi ;; # NUMCOND, feats esac PORT=$((PORT+1)) @@ -7483,8 +7483,8 @@ elif ! feat=$(testaddrs tcp ip6) || ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) else -#testserversec "$N" "$TEST" "$opts" "udp6-recvfrom:$PORT,reuseaddr,fork" "" "range=[::2/128]" "udp6-sendto:[::1]:$PORT" 6 udp $PORT 0 -testserversec "$N" "$TEST" "$opts" "udp6-recvfrom:$PORT,reuseaddr" "" "range=[::2/128]" "udp6-sendto:[::1]:$PORT" 6 udp $PORT 0 +#testserversec "$N" "$TEST" "$opts" "udp6-recvfrom:$PORT,reuseaddr,fork" "" "range=[::2]/128" "udp6-sendto:[::1]:$PORT" 6 udp $PORT 0 +testserversec "$N" "$TEST" "$opts" "udp6-recvfrom:$PORT,reuseaddr" "" "range=[::2]/128" "udp6-sendto:[::1]:$PORT" 6 udp $PORT 0 fi ;; # NUMCOND, feats esac PORT=$((PORT+1)) @@ -7562,7 +7562,7 @@ PORT1=$PORT; PORT=$((PORT+1)) PORT2=$PORT # we use the forward channel (PORT1) for testing, and have a backward channel # (PORT2) to get the data back, so we get the classical echo behaviour -testserversec "$N" "$TEST" "$opts" "udp6-recv:$PORT1,reuseaddr!!udp6-sendto:[::1]:$PORT2" "" "range=[::2/128]" "udp6-recv:$PORT2!!udp6-sendto:[::1]:$PORT1" 6 udp $PORT1 0 +testserversec "$N" "$TEST" "$opts" "udp6-recv:$PORT1,reuseaddr!!udp6-sendto:[::1]:$PORT2" "" "range=[::2]/128" "udp6-recv:$PORT2!!udp6-sendto:[::1]:$PORT1" 6 udp $PORT1 0 fi ;; # NUMCOND, feats esac PORT=$((PORT+1)) @@ -7701,8 +7701,8 @@ elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N numCANT=$((numCANT+1)) else -#testserversec "$N" "$TEST" "$opts" "ip6-recvfrom:$PROTO,reuseaddr,fork" "" "range=[::2/128]" "ip6-sendto:[::1]:$PROTO" 6 ip $PROTO 0 -testserversec "$N" "$TEST" "$opts" "ip6-recvfrom:$PROTO,reuseaddr!!udp6-sendto:[::1]:$PORT" "" "range=[::2/128]" "udp6-recv:$PORT!!ip6-sendto:[::1]:$PROTO" 6 ip $PROTO 0 +#testserversec "$N" "$TEST" "$opts" "ip6-recvfrom:$PROTO,reuseaddr,fork" "" "range=[::2]/128" "ip6-sendto:[::1]:$PROTO" 6 ip $PROTO 0 +testserversec "$N" "$TEST" "$opts" "ip6-recvfrom:$PROTO,reuseaddr!!udp6-sendto:[::1]:$PORT" "" "range=[::2]/128" "udp6-recv:$PORT!!ip6-sendto:[::1]:$PROTO" 6 ip $PROTO 0 fi ;; # NUMCOND, feats esac PROTO=$((PROTO+1)) @@ -7750,7 +7750,7 @@ PROTO1=$PROTO; PROTO=$((PROTO+1)) PROTO2=$PROTO # we use the forward channel (PROTO1) for testing, and have a backward channel # (PROTO2) to get the data back, so we get the classical echo behaviour -testserversec "$N" "$TEST" "$opts" "ip6-recv:$PROTO1,reuseaddr!!ip6-sendto:[::1]:$PROTO2" "" "range=[::2/128]" "ip6-recv:$PROTO2!!ip6-sendto:[::1]:$PROTO1" 6 ip $PROTO1 0 +testserversec "$N" "$TEST" "$opts" "ip6-recv:$PROTO1,reuseaddr!!ip6-sendto:[::1]:$PROTO2" "" "range=[::2]/128" "ip6-recv:$PROTO2!!ip6-sendto:[::1]:$PROTO1" 6 ip $PROTO1 0 fi ;; # NUMCOND, feats esac PROTO=$((PROTO+1)) diff --git a/xio-ip6.c b/xio-ip6.c index 20d3da2..ac272bd 100644 --- a/xio-ip6.c +++ b/xio-ip6.c @@ -87,23 +87,23 @@ int xioparsenetwork_ip6(const char *rangename, struct xiorange *range) { union xioin6_u *rangemask = (union xioin6_u *)&range->netmask.ip6.sin6_addr; union xioin6_u *nameaddr = (union xioin6_u *)&sockaddr.ip6.sin6_addr; - if (rangename[0] != '[' || rangename[strlen(rangename)-1] != ']') { - Error1("missing brackets for IPv6 range definition \"%s\"", - rangename); - return STAT_NORETRY; - } if ((delimpos = strchr(rangename, '/')) == NULL) { Error1("xioparsenetwork_ip6(\"%s\",,): missing mask bits delimiter '/'", rangename); return STAT_NORETRY; } delimind = delimpos - rangename; + if (rangename[0] != '[' || rangename[delimind-1] != ']') { + Error1("missing brackets for IPv6 range definition \"%s\"", + rangename); + return STAT_NORETRY; + } - if ((baseaddr = strdup(rangename+1)) == NULL) { + if ((baseaddr = strndup(rangename+1,delimind-2)) == NULL) { Error1("strdup(\"%s\"): out of memory", rangename+1); return STAT_NORETRY; } - baseaddr[delimind-1] = '\0'; + baseaddr[delimind-2] = '\0'; if (xiogetaddrinfo(baseaddr, NULL, PF_INET6, 0, 0, &sockaddr, &sockaddrlen, 0, 0) != STAT_OK) { @@ -175,7 +175,7 @@ int xiocheckrange_ip6(struct sockaddr_in6 *pa, struct xiorange *range) { int i; char peername[256]; union xioin6_u *rangeaddr = (union xioin6_u *)&range->netaddr.ip6.sin6_addr; - union xioin6_u *rangemask = (union xioin6_u *)&range->netmask.ip6; + union xioin6_u *rangemask = (union xioin6_u *)&range->netmask.ip6.sin6_addr; Debug16("permitted client subnet: [%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]:[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]", htons(rangeaddr->u6_addr16[0]), htons(rangeaddr->u6_addr16[1]), @@ -190,7 +190,7 @@ int xiocheckrange_ip6(struct sockaddr_in6 *pa, struct xiorange *range) { sockaddr_inet6_info(pa, peername, sizeof(peername))); for (i = 0; i < 4; ++i) { - masked.u6_addr32[i] = pa->sin6_addr.s6_addr[i] & rangemask->u6_addr16[i]; + masked.u6_addr32[i] = pa->sin6_addr.s6_addr32[i] & rangemask->u6_addr32[i]; } Debug8("masked address is [%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]", htons(masked.u6_addr16[0]), htons(masked.u6_addr16[1]),