4779 lines
119 KiB
Diff
4779 lines
119 KiB
Diff
|
From 79799b389703e8775f90e9728fa7e9d0dca26739 Mon Sep 17 00:00:00 2001
|
||
|
From: Gerrit Pape <pape@smarden.org>
|
||
|
Date: Tue, 13 Oct 2009 22:38:01 +0000
|
||
|
Subject: [PATCH] Apply fefe's ucspi-tcp-0.88-ipv6.diff19 ipv6 patch
|
||
|
|
||
|
What is ucspi-tcp and why does it need IPv6?
|
||
|
|
||
|
Please see http://cr.yp.to/ucspi-tcp.html for an explanation what
|
||
|
ucspi-tcp is. Basically, many people use it to replace inetd. It
|
||
|
consists of tcpserver and tcpclient. tcpserver can listen on sockets and
|
||
|
start programs in an inetd like fashion except that information like the
|
||
|
IP address and remote port are communicated via environment variables,
|
||
|
so writing a server is very easy and the servers are also more portable
|
||
|
since they don't have to use the socket API directly.
|
||
|
|
||
|
What does your diff do?
|
||
|
|
||
|
The current version adds simple IPv6 support for tcpserver and
|
||
|
tcpclient.
|
||
|
|
||
|
Note that IPv6 has inherent IPv4 compatibility, so IPv4 connections are
|
||
|
still possible without having to start a second tcpserver or something
|
||
|
like that. But since some systems may have IPv6 support in their libc
|
||
|
but not in the kernel, my tcpserver will always try to create an IPv6
|
||
|
listening socket but will fall back to transparent IPv4 support. Note
|
||
|
that this is done by the socket wrappers, not explicitly by tcpserver,
|
||
|
so to tcpserver the connections look like a normal IPv4 mapped IPv6
|
||
|
connection.
|
||
|
|
||
|
If a client connects via IPv4 (and you don't use the new -6 option),
|
||
|
tcpserver will make the environment variables look just like the
|
||
|
unpatched version. tcpclient also has a -6 option now with the same
|
||
|
effect.
|
||
|
|
||
|
IPv6 connections use $PROTO=TCP6, so clients can use this to see how
|
||
|
they should try to parse the IP numbers given in the environment, should
|
||
|
they feel the need to do so.
|
||
|
|
||
|
There is a new -4 option to tcpclient. I updated the resolver so that
|
||
|
you can request an IPv6 address for a machine that has only an A record.
|
||
|
If the lookup for an AAAA record fails, dns_ip6 will do an A lookup and
|
||
|
convert the address(es) to IP4-mapped IPv6 addresses. If you want
|
||
|
tcpclient to connect to the IPv4 address even if there is an AAAA
|
||
|
record, you can use the -4 option to tcpclient.
|
||
|
|
||
|
What does not work yet?
|
||
|
|
||
|
There are quite a few servers using tcpserver out there. If they try to
|
||
|
parse the IP addresses, they are not IPv6 ready and need to be touched.
|
||
|
|
||
|
Amend:
|
||
|
rm -rf usr/
|
||
|
---
|
||
|
FILES | 37 +++++++
|
||
|
Makefile | 184 ++++++++++++++++++++++++++++-----
|
||
|
TARGETS | 28 +++++
|
||
|
addcr.1 | 22 ++++
|
||
|
argv0.1 | 47 ++++++++
|
||
|
date@.1 | 32 ++++++
|
||
|
delcr.1 | 30 ++++++
|
||
|
dns.h | 63 +++++++-----
|
||
|
dns_dfd.c | 11 +-
|
||
|
dns_domain.c | 36 ++++--
|
||
|
dns_dtda.c | 2 +-
|
||
|
dns_ip.c | 4 +-
|
||
|
dns_ip6.c | 103 ++++++++++++++++++
|
||
|
dns_ipq.c | 6 +-
|
||
|
dns_ipq6.c | 72 +++++++++++++
|
||
|
dns_name.c | 19 +++-
|
||
|
dns_nd.c | 2 +-
|
||
|
dns_nd6.c | 28 +++++
|
||
|
dns_packet.c | 9 +-
|
||
|
dns_random.c | 3 +-
|
||
|
dns_rcip.c | 29 +++---
|
||
|
dns_rcrw.c | 5 +-
|
||
|
dns_resolve.c | 7 +-
|
||
|
dns_sortip6.c | 20 ++++
|
||
|
dns_transmit.c | 71 +++++++------
|
||
|
dns_txt.c | 4 +-
|
||
|
error.h | 2 +-
|
||
|
finger@.1 | 45 ++++++++
|
||
|
fixcr.1 | 11 ++
|
||
|
fmt_xlong.c | 22 ++++
|
||
|
haveip6.h1 | 1 +
|
||
|
haveip6.h2 | 1 +
|
||
|
hier.c | 19 ++++
|
||
|
http@.1 | 52 +++++++++
|
||
|
ip4.h | 2 +
|
||
|
ip6.h | 28 +++++
|
||
|
ip6_fmt.c | 64 +++++++++++
|
||
|
mconnect.1 | 36 +++++++
|
||
|
old-rules.c | 101 ++++++++++++++++++
|
||
|
pathexec.h | 2 +-
|
||
|
pathexec_env.c | 3 +-
|
||
|
recordio.1 | 75 +++++++++++++
|
||
|
remoteinfo.h | 1 +
|
||
|
remoteinfo6.c | 98 +++++++++++++++++
|
||
|
rules.c | 2 +-
|
||
|
scan_ip6.c | 87 +++++++++++++++
|
||
|
scan_xlong.c | 23 ++++
|
||
|
socket.h | 39 ++++++-
|
||
|
socket_accept6.c | 44 ++++++++
|
||
|
socket_bind.c | 4 +-
|
||
|
socket_bind6.c | 45 ++++++++
|
||
|
socket_conn.c | 2 +-
|
||
|
socket_conn6.c | 38 +++++++
|
||
|
socket_getifidx.c | 8 ++
|
||
|
socket_getifname.c | 14 +++
|
||
|
socket_ip4loopback.c | 2 +
|
||
|
socket_local6.c | 39 +++++++
|
||
|
socket_recv6.c | 44 ++++++++
|
||
|
socket_remote6.c | 39 +++++++
|
||
|
socket_send6.c | 40 +++++++
|
||
|
socket_tcp6.c | 44 ++++++++
|
||
|
socket_udp6.c | 38 +++++++
|
||
|
socket_v4mappedprefix.c | 2 +
|
||
|
socket_v6any.c | 2 +
|
||
|
socket_v6loopback.c | 2 +
|
||
|
str.h | 14 ++--
|
||
|
str_chr.c | 4 +-
|
||
|
str_diff.c | 2 +-
|
||
|
str_len.c | 4 +-
|
||
|
str_start.c | 2 +-
|
||
|
stralloc.h | 12 ++-
|
||
|
stralloc_catb.c | 2 +-
|
||
|
stralloc_cats.c | 2 +-
|
||
|
stralloc_opyb.c | 2 +-
|
||
|
stralloc_opys.c | 2 +-
|
||
|
tcp-environ.5 | 66 ++++++++++++
|
||
|
tcpcat.1 | 20 ++++
|
||
|
tcpclient.1 | 173 ++++++++++++++++++++++++++++++
|
||
|
tcpclient.c | 73 ++++++++-----
|
||
|
tcprules.1 | 221 +++++++++++++++++++++++++++++++++++++++
|
||
|
tcprules.c | 11 ++-
|
||
|
tcprulescheck.1 | 25 +++++
|
||
|
tcpserver.1 | 266 +++++++++++++++++++++++++++++++++++++++++++++++
|
||
|
tcpserver.c | 112 ++++++++++++++------
|
||
|
timeoutconn.h | 2 +
|
||
|
timeoutconn6.c | 34 ++++++
|
||
|
tryip6.c | 8 ++
|
||
|
who@.1 | 32 ++++++
|
||
|
88 files changed, 2849 insertions(+), 235 deletions(-)
|
||
|
create mode 100644 addcr.1
|
||
|
create mode 100644 argv0.1
|
||
|
create mode 100644 date@.1
|
||
|
create mode 100644 delcr.1
|
||
|
create mode 100644 dns_ip6.c
|
||
|
create mode 100644 dns_ipq6.c
|
||
|
create mode 100644 dns_nd6.c
|
||
|
create mode 100644 dns_sortip6.c
|
||
|
create mode 100644 finger@.1
|
||
|
create mode 100644 fixcr.1
|
||
|
create mode 100644 fmt_xlong.c
|
||
|
create mode 100644 haveip6.h1
|
||
|
create mode 100644 haveip6.h2
|
||
|
create mode 100644 http@.1
|
||
|
create mode 100644 ip6.h
|
||
|
create mode 100644 ip6_fmt.c
|
||
|
create mode 100644 mconnect.1
|
||
|
create mode 100644 old-rules.c
|
||
|
create mode 100644 recordio.1
|
||
|
create mode 100644 remoteinfo6.c
|
||
|
create mode 100644 scan_ip6.c
|
||
|
create mode 100644 scan_xlong.c
|
||
|
create mode 100644 socket_accept6.c
|
||
|
create mode 100644 socket_bind6.c
|
||
|
create mode 100644 socket_conn6.c
|
||
|
create mode 100644 socket_getifidx.c
|
||
|
create mode 100644 socket_getifname.c
|
||
|
create mode 100644 socket_ip4loopback.c
|
||
|
create mode 100644 socket_local6.c
|
||
|
create mode 100644 socket_recv6.c
|
||
|
create mode 100644 socket_remote6.c
|
||
|
create mode 100644 socket_send6.c
|
||
|
create mode 100644 socket_tcp6.c
|
||
|
create mode 100644 socket_udp6.c
|
||
|
create mode 100644 socket_v4mappedprefix.c
|
||
|
create mode 100644 socket_v6any.c
|
||
|
create mode 100644 socket_v6loopback.c
|
||
|
create mode 100644 tcp-environ.5
|
||
|
create mode 100644 tcpcat.1
|
||
|
create mode 100644 tcpclient.1
|
||
|
create mode 100644 tcprules.1
|
||
|
create mode 100644 tcprulescheck.1
|
||
|
create mode 100644 tcpserver.1
|
||
|
create mode 100644 timeoutconn6.c
|
||
|
create mode 100644 tryip6.c
|
||
|
create mode 100644 who@.1
|
||
|
|
||
|
diff --git a/FILES b/FILES
|
||
|
index cfb38a5..142aed9 100644
|
||
|
--- a/FILES
|
||
|
+++ b/FILES
|
||
|
@@ -216,3 +216,40 @@ wait_pid.c
|
||
|
warn-auto.sh
|
||
|
warn-shsgr
|
||
|
x86cpuid.c
|
||
|
+dns_ip6.c
|
||
|
+dns_ipq6.c
|
||
|
+dns_nd6.c
|
||
|
+dns_sortip6.c
|
||
|
+fmt_xlong.c
|
||
|
+ip6_fmt.c
|
||
|
+ip6_scan.c
|
||
|
+scan_0x.c
|
||
|
+socket_accept6.c
|
||
|
+socket_bind6.c
|
||
|
+socket_conn6.c
|
||
|
+socket_local6.c
|
||
|
+socket_recv6.c
|
||
|
+socket_remote6.c
|
||
|
+socket_send6.c
|
||
|
+socket_tcp6.c
|
||
|
+timeoutconn6.c
|
||
|
+tryip6.c
|
||
|
+haveip6.h2
|
||
|
+haveip6.h1
|
||
|
+remoteinfo6.c
|
||
|
+addcr.1
|
||
|
+argv0.1
|
||
|
+date@.1
|
||
|
+delcr.1
|
||
|
+finger@.1
|
||
|
+fixcr.1
|
||
|
+http@.1
|
||
|
+mconnect.1
|
||
|
+recordio.1
|
||
|
+tcp-environ.5
|
||
|
+tcpcat.1
|
||
|
+tcpclient.1
|
||
|
+tcprules.1
|
||
|
+tcprulescheck.1
|
||
|
+tcpserver.1
|
||
|
+who@.1
|
||
|
diff --git a/Makefile b/Makefile
|
||
|
index bcf5bd5..9dc6844 100644
|
||
|
--- a/Makefile
|
||
|
+++ b/Makefile
|
||
|
@@ -76,12 +76,14 @@ byte.a: \
|
||
|
makelib byte_chr.o byte_copy.o byte_cr.o byte_diff.o byte_rchr.o \
|
||
|
byte_zero.o case_diffb.o case_diffs.o fmt_ulong.o ip4_fmt.o \
|
||
|
ip4_scan.o scan_ulong.o str_chr.o str_diff.o str_len.o str_start.o \
|
||
|
-uint16_pack.o uint16_unpack.o uint32_pack.o uint32_unpack.o
|
||
|
+uint16_pack.o uint16_unpack.o uint32_pack.o uint32_unpack.o \
|
||
|
+ip6_fmt.o scan_ip6.o scan_xlong.o fmt_xlong.o
|
||
|
./makelib byte.a byte_chr.o byte_copy.o byte_cr.o \
|
||
|
byte_diff.o byte_rchr.o byte_zero.o case_diffb.o \
|
||
|
case_diffs.o fmt_ulong.o ip4_fmt.o ip4_scan.o scan_ulong.o \
|
||
|
str_chr.o str_diff.o str_len.o str_start.o uint16_pack.o \
|
||
|
- uint16_unpack.o uint32_pack.o uint32_unpack.o
|
||
|
+ uint16_unpack.o uint32_pack.o uint32_unpack.o ip6_fmt.o \
|
||
|
+ scan_ip6.o scan_xlong.o fmt_xlong.o
|
||
|
|
||
|
byte_chr.o: \
|
||
|
compile byte_chr.c byte.h
|
||
|
@@ -180,11 +182,13 @@ compile delcr.c buffer.h exit.h
|
||
|
dns.a: \
|
||
|
makelib dns_dfd.o dns_domain.o dns_dtda.o dns_ip.o dns_ipq.o \
|
||
|
dns_name.o dns_nd.o dns_packet.o dns_random.o dns_rcip.o dns_rcrw.o \
|
||
|
-dns_resolve.o dns_sortip.o dns_transmit.o dns_txt.o
|
||
|
+dns_resolve.o dns_sortip.o dns_transmit.o dns_txt.o dns_ip6.o \
|
||
|
+dns_sortip6.o dns_nd6.o dns_ipq6.o
|
||
|
./makelib dns.a dns_dfd.o dns_domain.o dns_dtda.o dns_ip.o \
|
||
|
dns_ipq.o dns_name.o dns_nd.o dns_packet.o dns_random.o \
|
||
|
dns_rcip.o dns_rcrw.o dns_resolve.o dns_sortip.o \
|
||
|
- dns_transmit.o dns_txt.o
|
||
|
+ dns_transmit.o dns_txt.o dns_ip6.o dns_sortip6.o dns_nd6.o \
|
||
|
+ dns_ipq6.o
|
||
|
|
||
|
dns_dfd.o: \
|
||
|
compile dns_dfd.c error.h alloc.h byte.h dns.h stralloc.h gen_alloc.h \
|
||
|
@@ -256,7 +260,7 @@ taia.h tai.h uint64.h taia.h
|
||
|
dns_transmit.o: \
|
||
|
compile dns_transmit.c socket.h uint16.h alloc.h error.h byte.h \
|
||
|
readwrite.h uint16.h dns.h stralloc.h gen_alloc.h iopause.h taia.h \
|
||
|
-tai.h uint64.h taia.h
|
||
|
+tai.h uint64.h taia.h uint32.h
|
||
|
./compile dns_transmit.c
|
||
|
|
||
|
dns_txt.o: \
|
||
|
@@ -497,9 +501,15 @@ exit.h fmt.h iopause.h taia.h tai.h uint64.h pathexec.h
|
||
|
remoteinfo.o: \
|
||
|
compile remoteinfo.c fmt.h buffer.h socket.h uint16.h error.h \
|
||
|
iopause.h taia.h tai.h uint64.h timeoutconn.h uint16.h remoteinfo.h \
|
||
|
-stralloc.h gen_alloc.h uint16.h
|
||
|
+stralloc.h gen_alloc.h uint16.h uint32.h
|
||
|
./compile remoteinfo.c
|
||
|
|
||
|
+remoteinfo6.o: \
|
||
|
+compile remoteinfo6.c fmt.h buffer.h socket.h uint16.h error.h \
|
||
|
+iopause.h taia.h tai.h uint64.h timeoutconn.h uint16.h remoteinfo.h \
|
||
|
+stralloc.h gen_alloc.h uint16.h uint32.h
|
||
|
+ ./compile remoteinfo6.c
|
||
|
+
|
||
|
rts: \
|
||
|
warn-auto.sh rts.sh conf-home
|
||
|
cat warn-auto.sh rts.sh \
|
||
|
@@ -556,43 +566,43 @@ trylsock.c compile load
|
||
|
rm -f trylsock.o trylsock
|
||
|
|
||
|
socket_accept.o: \
|
||
|
-compile socket_accept.c byte.h socket.h uint16.h
|
||
|
+compile socket_accept.c byte.h socket.h uint16.h uint32.h
|
||
|
./compile socket_accept.c
|
||
|
|
||
|
socket_bind.o: \
|
||
|
-compile socket_bind.c byte.h socket.h uint16.h
|
||
|
+compile socket_bind.c byte.h socket.h uint16.h uint32.h
|
||
|
./compile socket_bind.c
|
||
|
|
||
|
socket_conn.o: \
|
||
|
-compile socket_conn.c readwrite.h byte.h socket.h uint16.h
|
||
|
+compile socket_conn.c readwrite.h byte.h socket.h uint16.h uint32.h
|
||
|
./compile socket_conn.c
|
||
|
|
||
|
socket_delay.o: \
|
||
|
-compile socket_delay.c socket.h uint16.h
|
||
|
+compile socket_delay.c socket.h uint16.h uint32.h
|
||
|
./compile socket_delay.c
|
||
|
|
||
|
socket_listen.o: \
|
||
|
-compile socket_listen.c socket.h uint16.h
|
||
|
+compile socket_listen.c socket.h uint16.h uint32.h
|
||
|
./compile socket_listen.c
|
||
|
|
||
|
socket_local.o: \
|
||
|
-compile socket_local.c byte.h socket.h uint16.h
|
||
|
+compile socket_local.c byte.h socket.h uint16.h uint32.h
|
||
|
./compile socket_local.c
|
||
|
|
||
|
socket_opts.o: \
|
||
|
-compile socket_opts.c socket.h uint16.h
|
||
|
+compile socket_opts.c socket.h uint16.h uint32.h
|
||
|
./compile socket_opts.c
|
||
|
|
||
|
socket_remote.o: \
|
||
|
-compile socket_remote.c byte.h socket.h uint16.h
|
||
|
+compile socket_remote.c byte.h socket.h uint16.h uint32.h
|
||
|
./compile socket_remote.c
|
||
|
|
||
|
socket_tcp.o: \
|
||
|
-compile socket_tcp.c ndelay.h socket.h uint16.h
|
||
|
+compile socket_tcp.c ndelay.h socket.h uint16.h uint32.h
|
||
|
./compile socket_tcp.c
|
||
|
|
||
|
socket_udp.o: \
|
||
|
-compile socket_udp.c ndelay.h socket.h uint16.h
|
||
|
+compile socket_udp.c ndelay.h socket.h uint16.h uint32.h
|
||
|
./compile socket_udp.c
|
||
|
|
||
|
str_chr.o: \
|
||
|
@@ -709,9 +719,9 @@ warn-auto.sh tcpcat.sh conf-home
|
||
|
chmod 755 tcpcat
|
||
|
|
||
|
tcpclient: \
|
||
|
-load tcpclient.o remoteinfo.o timeoutconn.o dns.a time.a unix.a \
|
||
|
-byte.a socket.lib
|
||
|
- ./load tcpclient remoteinfo.o timeoutconn.o dns.a time.a \
|
||
|
+load tcpclient.o remoteinfo6.o dns.a time.a unix.a \
|
||
|
+byte.a socket.lib byte.h timeoutconn6.o
|
||
|
+ ./load tcpclient remoteinfo6.o timeoutconn6.o dns.a time.a \
|
||
|
unix.a byte.a `cat socket.lib`
|
||
|
|
||
|
tcpclient.o: \
|
||
|
@@ -719,7 +729,7 @@ compile tcpclient.c sig.h exit.h sgetopt.h subgetopt.h uint16.h fmt.h \
|
||
|
scan.h str.h ip4.h uint16.h socket.h uint16.h fd.h stralloc.h \
|
||
|
gen_alloc.h buffer.h error.h strerr.h pathexec.h timeoutconn.h \
|
||
|
uint16.h remoteinfo.h stralloc.h uint16.h dns.h stralloc.h iopause.h \
|
||
|
-taia.h tai.h uint64.h taia.h
|
||
|
+taia.h tai.h uint64.h taia.h uint32.h
|
||
|
./compile tcpclient.c
|
||
|
|
||
|
tcprules: \
|
||
|
@@ -741,9 +751,9 @@ stralloc.h gen_alloc.h
|
||
|
./compile tcprulescheck.c
|
||
|
|
||
|
tcpserver: \
|
||
|
-load tcpserver.o rules.o remoteinfo.o timeoutconn.o cdb.a dns.a \
|
||
|
+load tcpserver.o rules.o remoteinfo6.o timeoutconn6.o cdb.a dns.a \
|
||
|
time.a unix.a byte.a socket.lib
|
||
|
- ./load tcpserver rules.o remoteinfo.o timeoutconn.o cdb.a \
|
||
|
+ ./load tcpserver rules.o remoteinfo6.o timeoutconn6.o cdb.a \
|
||
|
dns.a time.a unix.a byte.a `cat socket.lib`
|
||
|
|
||
|
tcpserver.o: \
|
||
|
@@ -752,7 +762,7 @@ exit.h env.h prot.h open.h wait.h readwrite.h stralloc.h gen_alloc.h \
|
||
|
alloc.h buffer.h error.h strerr.h sgetopt.h subgetopt.h pathexec.h \
|
||
|
socket.h uint16.h ndelay.h remoteinfo.h stralloc.h uint16.h rules.h \
|
||
|
stralloc.h sig.h dns.h stralloc.h iopause.h taia.h tai.h uint64.h \
|
||
|
-taia.h
|
||
|
+taia.h uint32.h
|
||
|
./compile tcpserver.c
|
||
|
|
||
|
time.a: \
|
||
|
@@ -764,9 +774,14 @@ taia_less.o taia_now.o taia_pack.o taia_sub.o taia_uint.o
|
||
|
|
||
|
timeoutconn.o: \
|
||
|
compile timeoutconn.c ndelay.h socket.h uint16.h iopause.h taia.h \
|
||
|
-tai.h uint64.h error.h timeoutconn.h uint16.h
|
||
|
+tai.h uint64.h error.h timeoutconn.h uint16.h uint32.h
|
||
|
./compile timeoutconn.c
|
||
|
|
||
|
+timeoutconn6.o: \
|
||
|
+compile timeoutconn6.c ndelay.h socket.h uint16.h iopause.h taia.h \
|
||
|
+tai.h uint64.h error.h timeoutconn.h uint16.h uint32.h
|
||
|
+ ./compile timeoutconn6.c
|
||
|
+
|
||
|
uint16_pack.o: \
|
||
|
compile uint16_pack.c uint16.h
|
||
|
./compile uint16_pack.c
|
||
|
@@ -805,7 +820,12 @@ socket_conn.o socket_delay.o socket_listen.o socket_local.o \
|
||
|
socket_opts.o socket_remote.o socket_tcp.o socket_udp.o \
|
||
|
stralloc_cat.o stralloc_catb.o stralloc_cats.o stralloc_copy.o \
|
||
|
stralloc_eady.o stralloc_opyb.o stralloc_opys.o stralloc_pend.o \
|
||
|
-strerr_die.o strerr_sys.o subgetopt.o wait_nohang.o wait_pid.o
|
||
|
+strerr_die.o strerr_sys.o subgetopt.o wait_nohang.o wait_pid.o \
|
||
|
+socket_conn6.o socket_bind6.o socket_accept6.o socket_recv6.o \
|
||
|
+socket_send6.o socket_local6.o socket_remote6.o socket_tcp6.o \
|
||
|
+socket_getifname.o socket_getifidx.o socket_v4mappedprefix.o \
|
||
|
+socket_ip4loopback.o socket_v6any.o socket_v6loopback.o \
|
||
|
+socket_udp6.o
|
||
|
./makelib unix.a alloc.o alloc_re.o buffer.o buffer_0.o \
|
||
|
buffer_1.o buffer_2.o buffer_copy.o buffer_get.o \
|
||
|
buffer_put.o env.o error.o error_str.o fd_copy.o fd_move.o \
|
||
|
@@ -818,7 +838,12 @@ strerr_die.o strerr_sys.o subgetopt.o wait_nohang.o wait_pid.o
|
||
|
socket_udp.o stralloc_cat.o stralloc_catb.o stralloc_cats.o \
|
||
|
stralloc_copy.o stralloc_eady.o stralloc_opyb.o \
|
||
|
stralloc_opys.o stralloc_pend.o strerr_die.o strerr_sys.o \
|
||
|
- subgetopt.o wait_nohang.o wait_pid.o
|
||
|
+ subgetopt.o wait_nohang.o wait_pid.o socket_conn6.o \
|
||
|
+ socket_bind6.o socket_accept6.o socket_recv6.o socket_send6.o \
|
||
|
+ socket_local6.o socket_remote6.o socket_tcp6.o \
|
||
|
+ socket_getifname.o socket_getifidx.o socket_v4mappedprefix.o \
|
||
|
+ socket_ip4loopback.o socket_v6any.o socket_v6loopback.o \
|
||
|
+ socket_udp6.o
|
||
|
|
||
|
wait_nohang.o: \
|
||
|
compile wait_nohang.c haswaitp.h
|
||
|
@@ -834,3 +859,110 @@ warn-auto.sh who@.sh conf-home
|
||
|
| sed s}HOME}"`head -1 conf-home`"}g \
|
||
|
> who@
|
||
|
chmod 755 who@
|
||
|
+
|
||
|
+socket_conn6.o: \
|
||
|
+compile socket_conn6.c socket.h uint16.h haveip6.h error.h ip6.h \
|
||
|
+uint32.h
|
||
|
+ ./compile socket_conn6.c
|
||
|
+
|
||
|
+socket_bind6.o: \
|
||
|
+compile socket_bind6.c socket.h uint16.h haveip6.h error.h ip6.h \
|
||
|
+uint32.h
|
||
|
+ ./compile socket_bind6.c
|
||
|
+
|
||
|
+socket_accept6.o: \
|
||
|
+compile socket_accept6.c socket.h uint16.h haveip6.h error.h ip6.h \
|
||
|
+uint32.h
|
||
|
+ ./compile socket_accept6.c
|
||
|
+
|
||
|
+socket_recv6.o: \
|
||
|
+compile socket_recv6.c socket.h uint16.h haveip6.h error.h ip6.h \
|
||
|
+uint32.h
|
||
|
+ ./compile socket_recv6.c
|
||
|
+
|
||
|
+socket_send6.o: \
|
||
|
+compile socket_send6.c socket.h uint16.h haveip6.h error.h uint32.h
|
||
|
+ ./compile socket_send6.c
|
||
|
+
|
||
|
+socket_local6.o: \
|
||
|
+compile socket_local6.c socket.h uint16.h haveip6.h error.h uint32.h
|
||
|
+ ./compile socket_local6.c
|
||
|
+
|
||
|
+socket_remote6.o: \
|
||
|
+compile socket_remote6.c socket.h uint16.h haveip6.h error.h uint32.h
|
||
|
+ ./compile socket_remote6.c
|
||
|
+
|
||
|
+dns_sortip6.o: \
|
||
|
+compile dns_sortip6.c byte.h dns.h stralloc.h gen_alloc.h iopause.h \
|
||
|
+taia.h tai.h uint64.h taia.h
|
||
|
+ ./compile dns_sortip6.c
|
||
|
+
|
||
|
+dns_nd6.o: \
|
||
|
+compile dns_nd6.c byte.h fmt.h dns.h stralloc.h gen_alloc.h iopause.h \
|
||
|
+taia.h tai.h uint64.h taia.h
|
||
|
+ ./compile dns_nd6.c
|
||
|
+
|
||
|
+dns_ipq6.o: \
|
||
|
+compile dns_ipq6.c stralloc.h gen_alloc.h case.h byte.h str.h dns.h \
|
||
|
+stralloc.h iopause.h taia.h tai.h uint64.h taia.h ip6.h
|
||
|
+ ./compile dns_ipq6.c
|
||
|
+
|
||
|
+dns_ip6.o: \
|
||
|
+compile dns_ip6.c stralloc.h gen_alloc.h uint16.h byte.h dns.h \
|
||
|
+stralloc.h iopause.h taia.h tai.h uint64.h taia.h
|
||
|
+ ./compile dns_ip6.c
|
||
|
+
|
||
|
+fmt_xlong.o: \
|
||
|
+compile fmt_xlong.c scan.h
|
||
|
+ ./compile fmt_xlong.c
|
||
|
+
|
||
|
+scan_xlong.o: \
|
||
|
+compile scan_xlong.c scan.h
|
||
|
+ ./compile scan_xlong.c
|
||
|
+
|
||
|
+ip6_fmt.o: \
|
||
|
+compile ip6_fmt.c fmt.h ip6.h
|
||
|
+ ./compile ip6_fmt.c
|
||
|
+
|
||
|
+scan_ip6.o: \
|
||
|
+compile scan_ip6.c scan.h ip6.h
|
||
|
+ ./compile scan_ip6.c
|
||
|
+
|
||
|
+socket_tcp6.o: \
|
||
|
+compile socket_tcp6.c ndelay.h socket.h uint16.h haveip6.h uint32.h
|
||
|
+ ./compile socket_tcp6.c
|
||
|
+
|
||
|
+socket_udp6.o: \
|
||
|
+compile socket_udp6.c ndelay.h socket.h uint16.h haveip6.h uint32.h
|
||
|
+ ./compile socket_udp6.c
|
||
|
+
|
||
|
+haveip6.h: \
|
||
|
+tryip6.c choose compile haveip6.h1 haveip6.h2
|
||
|
+ ./choose c tryip6 haveip6.h1 haveip6.h2 > haveip6.h
|
||
|
+
|
||
|
+socket_getifname.o: \
|
||
|
+compile socket_getifname.c socket.h uint16.h uint32.h
|
||
|
+ ./compile socket_getifname.c
|
||
|
+
|
||
|
+socket_getifidx.o: \
|
||
|
+compile socket_getifidx.c socket.h uint16.h uint32.h
|
||
|
+ ./compile socket_getifidx.c
|
||
|
+
|
||
|
+socket_ip4loopback.o: \
|
||
|
+compile socket_ip4loopback.c
|
||
|
+ ./compile socket_ip4loopback.c
|
||
|
+
|
||
|
+socket_v4mappedprefix.o: \
|
||
|
+compile socket_v4mappedprefix.c
|
||
|
+ ./compile socket_v4mappedprefix.c
|
||
|
+
|
||
|
+socket_v6any.o: \
|
||
|
+compile socket_v6any.c
|
||
|
+ ./compile socket_v6any.c
|
||
|
+
|
||
|
+socket_v6loopback.o: \
|
||
|
+compile socket_v6loopback.c
|
||
|
+ ./compile socket_v6loopback.c
|
||
|
+
|
||
|
+clean:
|
||
|
+ rm -f `cat TARGETS`
|
||
|
diff --git a/TARGETS b/TARGETS
|
||
|
index 4d1f2a0..0385f96 100644
|
||
|
--- a/TARGETS
|
||
|
+++ b/TARGETS
|
||
|
@@ -169,3 +169,31 @@ instcheck
|
||
|
it
|
||
|
setup
|
||
|
check
|
||
|
+dns_ip6.o
|
||
|
+dns_ipq6.o
|
||
|
+dns_nd6.o
|
||
|
+dns_sortip6.o
|
||
|
+fmt_xlong.o
|
||
|
+ip6_fmt.o
|
||
|
+ip6_scan.o
|
||
|
+scan_0x.o
|
||
|
+socket_accept6.o
|
||
|
+socket_bind6.o
|
||
|
+socket_conn6.o
|
||
|
+socket_local6.o
|
||
|
+socket_recv6.o
|
||
|
+socket_remote6.o
|
||
|
+socket_send6.o
|
||
|
+socket_tcp6.o
|
||
|
+timeoutconn6.o
|
||
|
+haveip6.h
|
||
|
+remoteinfo6.o
|
||
|
+socket_getifidx.o
|
||
|
+socket_getifname.o
|
||
|
+scan_ip6.o
|
||
|
+scan_xlong.o
|
||
|
+socket_ip4loopback.o
|
||
|
+socket_udp6.o
|
||
|
+socket_v4mappedprefix.o
|
||
|
+socket_v6any.o
|
||
|
+socket_v6loopback.o
|
||
|
diff --git a/addcr.1 b/addcr.1
|
||
|
new file mode 100644
|
||
|
index 0000000..3bae1f7
|
||
|
--- /dev/null
|
||
|
+++ b/addcr.1
|
||
|
@@ -0,0 +1,22 @@
|
||
|
+.TH addcr 1
|
||
|
+.SH NAME
|
||
|
+addcr \- add a CR before each LF
|
||
|
+.SH SYNOPSIS
|
||
|
+.B addcr
|
||
|
+.SH DESCRIPTION
|
||
|
+.B addcr
|
||
|
+inserts CR at the end of each line of input.
|
||
|
+It does not insert CR at the end of a partial final line.
|
||
|
+.SH COMPATIBILITY
|
||
|
+Some vendors ship
|
||
|
+.B unix2dos
|
||
|
+or
|
||
|
+.B bsd2dos
|
||
|
+tools similar to
|
||
|
+.BR addcr .
|
||
|
+Those tools often blow up on long lines and nulls.
|
||
|
+.B addcr
|
||
|
+has no trouble with long lines and nulls.
|
||
|
+.SH "SEE ALSO"
|
||
|
+delcr(1),
|
||
|
+fixcr(1)
|
||
|
diff --git a/argv0.1 b/argv0.1
|
||
|
new file mode 100644
|
||
|
index 0000000..ad9634d
|
||
|
--- /dev/null
|
||
|
+++ b/argv0.1
|
||
|
@@ -0,0 +1,47 @@
|
||
|
+.TH argv0 1
|
||
|
+.SH NAME
|
||
|
+argv0 \- run a program with a specified 0th argument
|
||
|
+.SH SYNOPSIS
|
||
|
+.B argv0
|
||
|
+.I realname
|
||
|
+.I zero
|
||
|
+[
|
||
|
+.I arg ...
|
||
|
+]
|
||
|
+.SH DESCRIPTION
|
||
|
+.B argv0
|
||
|
+runs
|
||
|
+the program stored as
|
||
|
+.I realname
|
||
|
+on disk,
|
||
|
+with the given
|
||
|
+arguments.
|
||
|
+It sets the 0th argument of
|
||
|
+the program to
|
||
|
+.IR zero .
|
||
|
+
|
||
|
+For example,
|
||
|
+
|
||
|
+.EX
|
||
|
+ argv0 /bin/csh -bin/csh
|
||
|
+.EE
|
||
|
+
|
||
|
+runs
|
||
|
+.B /bin/csh
|
||
|
+with a 0th argument of
|
||
|
+.BR -bin/csh .
|
||
|
+.B csh
|
||
|
+will think it is a login shell
|
||
|
+and behave accordingly.
|
||
|
+
|
||
|
+.B argv0
|
||
|
+can be used to run some
|
||
|
+.B inetd
|
||
|
+wrappers under
|
||
|
+.BR tcpserver .
|
||
|
+.SH "SEE ALSO"
|
||
|
+csh(1),
|
||
|
+tcpserver(1),
|
||
|
+execve(2),
|
||
|
+execvp(3),
|
||
|
+inetd(8)
|
||
|
diff --git a/date@.1 b/date@.1
|
||
|
new file mode 100644
|
||
|
index 0000000..fa0ba98
|
||
|
--- /dev/null
|
||
|
+++ b/date@.1
|
||
|
@@ -0,0 +1,32 @@
|
||
|
+.TH date@ 1
|
||
|
+.SH NAME
|
||
|
+date@ \- print the date on a host
|
||
|
+.SH SYNTAX
|
||
|
+.B date@
|
||
|
+[
|
||
|
+.I host
|
||
|
+]
|
||
|
+.SH DESCRIPTION
|
||
|
+.B date@
|
||
|
+connects to TCP port 13 (Daytime) on
|
||
|
+.I host
|
||
|
+and prints any data it receives.
|
||
|
+It removes CR and converts unprintable characters to a visible format.
|
||
|
+
|
||
|
+If
|
||
|
+.I host
|
||
|
+is not supplied,
|
||
|
+.B date@
|
||
|
+connects to the local host.
|
||
|
+
|
||
|
+Some computers respond to port 13 with a human-readable date.
|
||
|
+For example, they may be running
|
||
|
+
|
||
|
+.EX
|
||
|
+ tcpserver 0 13 date &
|
||
|
+.EE
|
||
|
+.SH "SEE ALSO"
|
||
|
+cat(1),
|
||
|
+delcr(1),
|
||
|
+tcpclient(1),
|
||
|
+tcpserver(1)
|
||
|
diff --git a/delcr.1 b/delcr.1
|
||
|
new file mode 100644
|
||
|
index 0000000..18ea736
|
||
|
--- /dev/null
|
||
|
+++ b/delcr.1
|
||
|
@@ -0,0 +1,30 @@
|
||
|
+.TH delcr 1
|
||
|
+.SH NAME
|
||
|
+delcr \- remove a CR before each LF
|
||
|
+.SH SYNOPSIS
|
||
|
+.B delcr
|
||
|
+.SH DESCRIPTION
|
||
|
+.B delcr
|
||
|
+removes a CR at the end of each line of input,
|
||
|
+if a CR is present.
|
||
|
+It also removes a CR at the end of a partial final line.
|
||
|
+
|
||
|
+The pipeline
|
||
|
+
|
||
|
+.EX
|
||
|
+ addcr | delcr
|
||
|
+.EE
|
||
|
+
|
||
|
+prints an exact copy of its input.
|
||
|
+.SH COMPATIBILITY
|
||
|
+Some vendors ship
|
||
|
+.B dos2unix
|
||
|
+or
|
||
|
+.B dos2bsd
|
||
|
+tools similar to
|
||
|
+.BR delcr .
|
||
|
+Those tools often blow up on long lines and nulls.
|
||
|
+.B delcr
|
||
|
+has no trouble with long lines and nulls.
|
||
|
+.SH "SEE ALSO"
|
||
|
+addcr(1)
|
||
|
diff --git a/dns.h b/dns.h
|
||
|
index 0948b1a..f06c5a8 100644
|
||
|
--- a/dns.h
|
||
|
+++ b/dns.h
|
||
|
@@ -34,51 +34,60 @@ struct dns_transmit {
|
||
|
unsigned int curserver;
|
||
|
struct taia deadline;
|
||
|
unsigned int pos;
|
||
|
- char *servers;
|
||
|
- char localip[4];
|
||
|
+ const char *servers;
|
||
|
+ char localip[16];
|
||
|
+ unsigned int scope_id;
|
||
|
char qtype[2];
|
||
|
} ;
|
||
|
|
||
|
-extern void dns_random_init(char *);
|
||
|
+extern void dns_random_init(const char *);
|
||
|
extern unsigned int dns_random(unsigned int);
|
||
|
|
||
|
extern void dns_sortip(char *,unsigned int);
|
||
|
+extern void dns_sortip6(char *,unsigned int);
|
||
|
|
||
|
extern void dns_domain_free(char **);
|
||
|
-extern int dns_domain_copy(char **,char *);
|
||
|
-extern unsigned int dns_domain_length(char *);
|
||
|
-extern int dns_domain_equal(char *,char *);
|
||
|
-extern char *dns_domain_suffix(char *,char *);
|
||
|
-extern int dns_domain_fromdot(char **,char *,unsigned int);
|
||
|
-extern int dns_domain_todot_cat(stralloc *,char *);
|
||
|
+extern int dns_domain_copy(char **,const char *);
|
||
|
+extern unsigned int dns_domain_length(const char *);
|
||
|
+extern int dns_domain_equal(const char *,const char *);
|
||
|
+extern int dns_domain_suffix(const char *,const char *);
|
||
|
+extern unsigned int dns_domain_suffixpos(const char *,const char *);
|
||
|
+extern int dns_domain_fromdot(char **,const char *,unsigned int);
|
||
|
+extern int dns_domain_todot_cat(stralloc *,const char *);
|
||
|
|
||
|
-extern unsigned int dns_packet_copy(char *,unsigned int,unsigned int,char *,unsigned int);
|
||
|
-extern unsigned int dns_packet_getname(char *,unsigned int,unsigned int,char **);
|
||
|
-extern unsigned int dns_packet_skipname(char *,unsigned int,unsigned int);
|
||
|
-extern int dns_packet_nameequal(char *,unsigned int,unsigned int,char *,unsigned int,unsigned int);
|
||
|
+extern unsigned int dns_packet_copy(const char *,unsigned int,unsigned int,char *,unsigned int);
|
||
|
+extern unsigned int dns_packet_getname(const char *,unsigned int,unsigned int,char **);
|
||
|
+extern unsigned int dns_packet_skipname(const char *,unsigned int,unsigned int);
|
||
|
|
||
|
-extern int dns_transmit_start(struct dns_transmit *,char *,int,char *,char *,char *);
|
||
|
+extern int dns_transmit_start(struct dns_transmit *,const char *,int,const char *,const char *,const char *);
|
||
|
extern void dns_transmit_free(struct dns_transmit *);
|
||
|
extern void dns_transmit_io(struct dns_transmit *,iopause_fd *,struct taia *);
|
||
|
-extern int dns_transmit_get(struct dns_transmit *,iopause_fd *,struct taia *);
|
||
|
+extern int dns_transmit_get(struct dns_transmit *,const iopause_fd *,const struct taia *);
|
||
|
|
||
|
extern int dns_resolvconfip(char *);
|
||
|
-extern int dns_resolve(char *,char *);
|
||
|
+extern int dns_resolve(const char *,const char *);
|
||
|
extern struct dns_transmit dns_resolve_tx;
|
||
|
|
||
|
-extern int dns_ip4_packet(stralloc *,char *,unsigned int);
|
||
|
-extern int dns_ip4(stralloc *,stralloc *);
|
||
|
-extern int dns_name_packet(stralloc *,char *,unsigned int);
|
||
|
-extern void dns_name4_domain(char *,char *);
|
||
|
+extern int dns_ip4_packet(stralloc *,const char *,unsigned int);
|
||
|
+extern int dns_ip4(stralloc *,const stralloc *);
|
||
|
+extern int dns_ip6_packet(stralloc *,const char *,unsigned int);
|
||
|
+extern int dns_ip6(stralloc *,stralloc *);
|
||
|
+extern int dns_name_packet(stralloc *,const char *,unsigned int);
|
||
|
+extern void dns_name4_domain(char *,const char *);
|
||
|
#define DNS_NAME4_DOMAIN 31
|
||
|
-extern int dns_name4(stralloc *,char *);
|
||
|
-extern int dns_txt_packet(stralloc *,char *,unsigned int);
|
||
|
-extern int dns_txt(stralloc *,stralloc *);
|
||
|
-extern int dns_mx_packet(stralloc *,char *,unsigned int);
|
||
|
-extern int dns_mx(stralloc *,stralloc *);
|
||
|
+extern int dns_name4(stralloc *,const char *);
|
||
|
+extern int dns_txt_packet(stralloc *,const char *,unsigned int);
|
||
|
+extern int dns_txt(stralloc *,const stralloc *);
|
||
|
+extern int dns_mx_packet(stralloc *,const char *,unsigned int);
|
||
|
+extern int dns_mx(stralloc *,const stralloc *);
|
||
|
|
||
|
extern int dns_resolvconfrewrite(stralloc *);
|
||
|
-extern int dns_ip4_qualify_rules(stralloc *,stralloc *,stralloc *,stralloc *);
|
||
|
-extern int dns_ip4_qualify(stralloc *,stralloc *,stralloc *);
|
||
|
+extern int dns_ip4_qualify_rules(stralloc *,stralloc *,const stralloc *,const stralloc *);
|
||
|
+extern int dns_ip4_qualify(stralloc *,stralloc *,const stralloc *);
|
||
|
+extern int dns_ip6_qualify_rules(stralloc *,stralloc *,const stralloc *,const stralloc *);
|
||
|
+extern int dns_ip6_qualify(stralloc *,stralloc *,const stralloc *);
|
||
|
+
|
||
|
+extern int dns_name6_domain(char *,char *);
|
||
|
+#define DNS_NAME6_DOMAIN (4*16+11)
|
||
|
|
||
|
#endif
|
||
|
diff --git a/dns_dfd.c b/dns_dfd.c
|
||
|
index 14a29d8..c924718 100644
|
||
|
--- a/dns_dfd.c
|
||
|
+++ b/dns_dfd.c
|
||
|
@@ -1,9 +1,10 @@
|
||
|
-#include "error.h"
|
||
|
-#include "alloc.h"
|
||
|
+#include <stdlib.h>
|
||
|
+#include <errno.h>
|
||
|
#include "byte.h"
|
||
|
#include "dns.h"
|
||
|
+#include "error.h"
|
||
|
|
||
|
-int dns_domain_fromdot(char **out,char *buf,unsigned int n)
|
||
|
+int dns_domain_fromdot(char **out,const char *buf,unsigned int n)
|
||
|
{
|
||
|
char label[63];
|
||
|
unsigned int labellen = 0; /* <= sizeof label */
|
||
|
@@ -59,11 +60,11 @@ int dns_domain_fromdot(char **out,char *buf,unsigned int n)
|
||
|
if (namelen + 1 > sizeof name) return 0;
|
||
|
name[namelen++] = 0;
|
||
|
|
||
|
- x = alloc(namelen);
|
||
|
+ x = malloc(namelen);
|
||
|
if (!x) return 0;
|
||
|
byte_copy(x,namelen,name);
|
||
|
|
||
|
- if (*out) alloc_free(*out);
|
||
|
+ if (*out) free(*out);
|
||
|
*out = x;
|
||
|
return 1;
|
||
|
}
|
||
|
diff --git a/dns_domain.c b/dns_domain.c
|
||
|
index f898485..80ac5ea 100644
|
||
|
--- a/dns_domain.c
|
||
|
+++ b/dns_domain.c
|
||
|
@@ -1,16 +1,15 @@
|
||
|
-#include "error.h"
|
||
|
-#include "alloc.h"
|
||
|
+#include <stdlib.h>
|
||
|
#include "case.h"
|
||
|
#include "byte.h"
|
||
|
#include "dns.h"
|
||
|
|
||
|
-unsigned int dns_domain_length(char *dn)
|
||
|
+unsigned int dns_domain_length(const char *dn)
|
||
|
{
|
||
|
- char *x;
|
||
|
+ const char *x;
|
||
|
unsigned char c;
|
||
|
|
||
|
x = dn;
|
||
|
- while (c = *x++)
|
||
|
+ while ((c = *x++))
|
||
|
x += (unsigned int) c;
|
||
|
return x - dn;
|
||
|
}
|
||
|
@@ -18,26 +17,26 @@ unsigned int dns_domain_length(char *dn)
|
||
|
void dns_domain_free(char **out)
|
||
|
{
|
||
|
if (*out) {
|
||
|
- alloc_free(*out);
|
||
|
+ free(*out);
|
||
|
*out = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
-int dns_domain_copy(char **out,char *in)
|
||
|
+int dns_domain_copy(char **out,const char *in)
|
||
|
{
|
||
|
unsigned int len;
|
||
|
char *x;
|
||
|
|
||
|
len = dns_domain_length(in);
|
||
|
- x = alloc(len);
|
||
|
+ x = malloc(len);
|
||
|
if (!x) return 0;
|
||
|
byte_copy(x,len,in);
|
||
|
- if (*out) alloc_free(*out);
|
||
|
+ if (*out) free(*out);
|
||
|
*out = x;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
-int dns_domain_equal(char *dn1,char *dn2)
|
||
|
+int dns_domain_equal(const char *dn1,const char *dn2)
|
||
|
{
|
||
|
unsigned int len;
|
||
|
|
||
|
@@ -48,12 +47,25 @@ int dns_domain_equal(char *dn1,char *dn2)
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
-char *dns_domain_suffix(char *big,char *little)
|
||
|
+int dns_domain_suffix(const char *big,const char *little)
|
||
|
+{
|
||
|
+ unsigned char c;
|
||
|
+
|
||
|
+ for (;;) {
|
||
|
+ if (dns_domain_equal(big,little)) return 1;
|
||
|
+ c = *big++;
|
||
|
+ if (!c) return 0;
|
||
|
+ big += c;
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+unsigned int dns_domain_suffixpos(const char *big,const char *little)
|
||
|
{
|
||
|
+ const char *orig = big;
|
||
|
unsigned char c;
|
||
|
|
||
|
for (;;) {
|
||
|
- if (dns_domain_equal(big,little)) return big;
|
||
|
+ if (dns_domain_equal(big,little)) return big - orig;
|
||
|
c = *big++;
|
||
|
if (!c) return 0;
|
||
|
big += c;
|
||
|
diff --git a/dns_dtda.c b/dns_dtda.c
|
||
|
index 00b41a1..ba1db4f 100644
|
||
|
--- a/dns_dtda.c
|
||
|
+++ b/dns_dtda.c
|
||
|
@@ -1,7 +1,7 @@
|
||
|
#include "stralloc.h"
|
||
|
#include "dns.h"
|
||
|
|
||
|
-int dns_domain_todot_cat(stralloc *out,char *d)
|
||
|
+int dns_domain_todot_cat(stralloc *out,const char *d)
|
||
|
{
|
||
|
char ch;
|
||
|
char ch2;
|
||
|
diff --git a/dns_ip.c b/dns_ip.c
|
||
|
index fb0526c..e7c3a9a 100644
|
||
|
--- a/dns_ip.c
|
||
|
+++ b/dns_ip.c
|
||
|
@@ -3,7 +3,7 @@
|
||
|
#include "byte.h"
|
||
|
#include "dns.h"
|
||
|
|
||
|
-int dns_ip4_packet(stralloc *out,char *buf,unsigned int len)
|
||
|
+int dns_ip4_packet(stralloc *out,const char *buf,unsigned int len)
|
||
|
{
|
||
|
unsigned int pos;
|
||
|
char header[12];
|
||
|
@@ -36,7 +36,7 @@ int dns_ip4_packet(stralloc *out,char *buf,unsigned int len)
|
||
|
|
||
|
static char *q = 0;
|
||
|
|
||
|
-int dns_ip4(stralloc *out,stralloc *fqdn)
|
||
|
+int dns_ip4(stralloc *out,const stralloc *fqdn)
|
||
|
{
|
||
|
unsigned int i;
|
||
|
char code;
|
||
|
diff --git a/dns_ip6.c b/dns_ip6.c
|
||
|
new file mode 100644
|
||
|
index 0000000..1a2ce08
|
||
|
--- /dev/null
|
||
|
+++ b/dns_ip6.c
|
||
|
@@ -0,0 +1,103 @@
|
||
|
+#include "stralloc.h"
|
||
|
+#include "uint16.h"
|
||
|
+#include "byte.h"
|
||
|
+#include "dns.h"
|
||
|
+#include "ip4.h"
|
||
|
+#include "ip6.h"
|
||
|
+
|
||
|
+static int dns_ip6_packet_add(stralloc *out,const char *buf,unsigned int len)
|
||
|
+{
|
||
|
+ unsigned int pos;
|
||
|
+ char header[16];
|
||
|
+ uint16 numanswers;
|
||
|
+ uint16 datalen;
|
||
|
+
|
||
|
+ pos = dns_packet_copy(buf,len,0,header,12); if (!pos) return -1;
|
||
|
+ uint16_unpack_big(header + 6,&numanswers);
|
||
|
+ pos = dns_packet_skipname(buf,len,pos); if (!pos) return -1;
|
||
|
+ pos += 4;
|
||
|
+
|
||
|
+ while (numanswers--) {
|
||
|
+ pos = dns_packet_skipname(buf,len,pos); if (!pos) return -1;
|
||
|
+ pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) return -1;
|
||
|
+ uint16_unpack_big(header + 8,&datalen);
|
||
|
+ if (byte_equal(header,2,DNS_T_AAAA)) {
|
||
|
+ if (byte_equal(header + 2,2,DNS_C_IN))
|
||
|
+ if (datalen == 16) {
|
||
|
+ if (!dns_packet_copy(buf,len,pos,header,16)) return -1;
|
||
|
+ if (!stralloc_catb(out,header,16)) return -1;
|
||
|
+ }
|
||
|
+ } else if (byte_equal(header,2,DNS_T_A))
|
||
|
+ if (byte_equal(header + 2,2,DNS_C_IN))
|
||
|
+ if (datalen == 4) {
|
||
|
+ byte_copy(header,12,V4mappedprefix);
|
||
|
+ if (!dns_packet_copy(buf,len,pos,header+12,4)) return -1;
|
||
|
+ if (!stralloc_catb(out,header,16)) return -1;
|
||
|
+ }
|
||
|
+ pos += datalen;
|
||
|
+ }
|
||
|
+
|
||
|
+ dns_sortip6(out->s,out->len);
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+int dns_ip6_packet(stralloc *out,const char *buf,unsigned int len) {
|
||
|
+ if (!stralloc_copys(out,"")) return -1;
|
||
|
+ return dns_ip6_packet_add(out,buf,len);
|
||
|
+}
|
||
|
+
|
||
|
+static char *q = 0;
|
||
|
+
|
||
|
+int dns_ip6(stralloc *out,stralloc *fqdn)
|
||
|
+{
|
||
|
+ unsigned int i;
|
||
|
+ char code;
|
||
|
+ char ch;
|
||
|
+ char ip[16];
|
||
|
+
|
||
|
+ if (!stralloc_copys(out,"")) return -1;
|
||
|
+ if (!stralloc_readyplus(fqdn,1)) return -1;
|
||
|
+ fqdn->s[fqdn->len]=0;
|
||
|
+ if ((i=scan_ip6(fqdn->s,ip))) {
|
||
|
+ if (fqdn->s[i]) return -1;
|
||
|
+ stralloc_copyb(out,ip,16);
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+ code = 0;
|
||
|
+ for (i = 0;i <= fqdn->len;++i) {
|
||
|
+ if (i < fqdn->len)
|
||
|
+ ch = fqdn->s[i];
|
||
|
+ else
|
||
|
+ ch = '.';
|
||
|
+
|
||
|
+ if ((ch == '[') || (ch == ']')) continue;
|
||
|
+ if (ch == '.') {
|
||
|
+ if (!stralloc_append(out,&code)) return -1;
|
||
|
+ code = 0;
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+ if ((ch >= '0') && (ch <= '9')) {
|
||
|
+ code *= 10;
|
||
|
+ code += ch - '0';
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (!dns_domain_fromdot(&q,fqdn->s,fqdn->len)) return -1;
|
||
|
+ if (!stralloc_copys(out,"")) return -1;
|
||
|
+ if (dns_resolve(q,DNS_T_AAAA) != -1)
|
||
|
+ if (dns_ip6_packet_add(out,dns_resolve_tx.packet,dns_resolve_tx.packetlen) != -1) {
|
||
|
+ dns_transmit_free(&dns_resolve_tx);
|
||
|
+ dns_domain_free(&q);
|
||
|
+ }
|
||
|
+ if (!dns_domain_fromdot(&q,fqdn->s,fqdn->len)) return -1;
|
||
|
+ if (dns_resolve(q,DNS_T_A) != -1)
|
||
|
+ if (dns_ip6_packet_add(out,dns_resolve_tx.packet,dns_resolve_tx.packetlen) != -1) {
|
||
|
+ dns_transmit_free(&dns_resolve_tx);
|
||
|
+ dns_domain_free(&q);
|
||
|
+ }
|
||
|
+ return out->a>0?0:-1;
|
||
|
+ }
|
||
|
+
|
||
|
+ out->len &= ~3;
|
||
|
+ return 0;
|
||
|
+}
|
||
|
diff --git a/dns_ipq.c b/dns_ipq.c
|
||
|
index 8181ab7..5b65e23 100644
|
||
|
--- a/dns_ipq.c
|
||
|
+++ b/dns_ipq.c
|
||
|
@@ -4,7 +4,7 @@
|
||
|
#include "str.h"
|
||
|
#include "dns.h"
|
||
|
|
||
|
-static int doit(stralloc *work,char *rule)
|
||
|
+static int doit(stralloc *work,const char *rule)
|
||
|
{
|
||
|
char ch;
|
||
|
unsigned int colon;
|
||
|
@@ -30,7 +30,7 @@ static int doit(stralloc *work,char *rule)
|
||
|
return stralloc_cats(work,rule + colon + 1);
|
||
|
}
|
||
|
|
||
|
-int dns_ip4_qualify_rules(stralloc *out,stralloc *fqdn,stralloc *in,stralloc *rules)
|
||
|
+int dns_ip4_qualify_rules(stralloc *out,stralloc *fqdn,const stralloc *in,const stralloc *rules)
|
||
|
{
|
||
|
unsigned int i;
|
||
|
unsigned int j;
|
||
|
@@ -63,7 +63,7 @@ int dns_ip4_qualify_rules(stralloc *out,stralloc *fqdn,stralloc *in,stralloc *ru
|
||
|
}
|
||
|
}
|
||
|
|
||
|
-int dns_ip4_qualify(stralloc *out,stralloc *fqdn,stralloc *in)
|
||
|
+int dns_ip4_qualify(stralloc *out,stralloc *fqdn,const stralloc *in)
|
||
|
{
|
||
|
static stralloc rules;
|
||
|
if (dns_resolvconfrewrite(&rules) == -1) return -1;
|
||
|
diff --git a/dns_ipq6.c b/dns_ipq6.c
|
||
|
new file mode 100644
|
||
|
index 0000000..d5cea12
|
||
|
--- /dev/null
|
||
|
+++ b/dns_ipq6.c
|
||
|
@@ -0,0 +1,72 @@
|
||
|
+#include "stralloc.h"
|
||
|
+#include "case.h"
|
||
|
+#include "byte.h"
|
||
|
+#include "str.h"
|
||
|
+#include "dns.h"
|
||
|
+
|
||
|
+static int doit(stralloc *work,const char *rule)
|
||
|
+{
|
||
|
+ char ch;
|
||
|
+ unsigned int colon;
|
||
|
+ unsigned int prefixlen;
|
||
|
+
|
||
|
+ ch = *rule++;
|
||
|
+ if ((ch != '?') && (ch != '=') && (ch != '*') && (ch != '-')) return 1;
|
||
|
+ colon = str_chr(rule,':');
|
||
|
+ if (!rule[colon]) return 1;
|
||
|
+
|
||
|
+ if (work->len < colon) return 1;
|
||
|
+ prefixlen = work->len - colon;
|
||
|
+ if ((ch == '=') && prefixlen) return 1;
|
||
|
+ if (case_diffb(rule,colon,work->s + prefixlen)) return 1;
|
||
|
+ if (ch == '?') {
|
||
|
+ if (byte_chr(work->s,prefixlen,'.') < prefixlen) return 1;
|
||
|
+ if (byte_chr(work->s,prefixlen,':') < prefixlen) return 1;
|
||
|
+ if (byte_chr(work->s,prefixlen,'[') < prefixlen) return 1;
|
||
|
+ if (byte_chr(work->s,prefixlen,']') < prefixlen) return 1;
|
||
|
+ }
|
||
|
+
|
||
|
+ work->len = prefixlen;
|
||
|
+ if (ch == '-') work->len = 0;
|
||
|
+ return stralloc_cats(work,rule + colon + 1);
|
||
|
+}
|
||
|
+
|
||
|
+int dns_ip6_qualify_rules(stralloc *out,stralloc *fqdn,const stralloc *in,const stralloc *rules)
|
||
|
+{
|
||
|
+ unsigned int i;
|
||
|
+ unsigned int j;
|
||
|
+ unsigned int plus;
|
||
|
+ unsigned int fqdnlen;
|
||
|
+
|
||
|
+ if (!stralloc_copy(fqdn,in)) return -1;
|
||
|
+
|
||
|
+ for (j = i = 0;j < rules->len;++j)
|
||
|
+ if (!rules->s[j]) {
|
||
|
+ if (!doit(fqdn,rules->s + i)) return -1;
|
||
|
+ i = j + 1;
|
||
|
+ }
|
||
|
+
|
||
|
+ fqdnlen = fqdn->len;
|
||
|
+ plus = byte_chr(fqdn->s,fqdnlen,'+');
|
||
|
+ if (plus >= fqdnlen)
|
||
|
+ return dns_ip6(out,fqdn);
|
||
|
+
|
||
|
+ i = plus + 1;
|
||
|
+ for (;;) {
|
||
|
+ j = byte_chr(fqdn->s + i,fqdnlen - i,'+');
|
||
|
+ byte_copy(fqdn->s + plus,j,fqdn->s + i);
|
||
|
+ fqdn->len = plus + j;
|
||
|
+ if (dns_ip6(out,fqdn) == -1) return -1;
|
||
|
+ if (out->len) return 0;
|
||
|
+ i += j;
|
||
|
+ if (i >= fqdnlen) return 0;
|
||
|
+ ++i;
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+int dns_ip6_qualify(stralloc *out,stralloc *fqdn,const stralloc *in)
|
||
|
+{
|
||
|
+ static stralloc rules;
|
||
|
+ if (dns_resolvconfrewrite(&rules) == -1) return -1;
|
||
|
+ return dns_ip6_qualify_rules(out,fqdn,in,&rules);
|
||
|
+}
|
||
|
diff --git a/dns_name.c b/dns_name.c
|
||
|
index dcb10c7..1f03186 100644
|
||
|
--- a/dns_name.c
|
||
|
+++ b/dns_name.c
|
||
|
@@ -2,10 +2,11 @@
|
||
|
#include "uint16.h"
|
||
|
#include "byte.h"
|
||
|
#include "dns.h"
|
||
|
+#include "ip6.h"
|
||
|
|
||
|
static char *q = 0;
|
||
|
|
||
|
-int dns_name_packet(stralloc *out,char *buf,unsigned int len)
|
||
|
+int dns_name_packet(stralloc *out,const char *buf,unsigned int len)
|
||
|
{
|
||
|
unsigned int pos;
|
||
|
char header[12];
|
||
|
@@ -35,7 +36,7 @@ int dns_name_packet(stralloc *out,char *buf,unsigned int len)
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
-int dns_name4(stralloc *out,char ip[4])
|
||
|
+int dns_name4(stralloc *out,const char ip[4])
|
||
|
{
|
||
|
char name[DNS_NAME4_DOMAIN];
|
||
|
|
||
|
@@ -46,3 +47,17 @@ int dns_name4(stralloc *out,char ip[4])
|
||
|
dns_domain_free(&q);
|
||
|
return 0;
|
||
|
}
|
||
|
+
|
||
|
+int dns_name6(stralloc *out,char ip[16])
|
||
|
+{
|
||
|
+ char name[DNS_NAME6_DOMAIN];
|
||
|
+
|
||
|
+ if (ip6_isv4mapped(ip))
|
||
|
+ return dns_name4(out,ip+12);
|
||
|
+ dns_name6_domain(name,ip);
|
||
|
+ if (dns_resolve(name,DNS_T_PTR) == -1) return -1;
|
||
|
+ if (dns_name_packet(out,dns_resolve_tx.packet,dns_resolve_tx.packetlen) == -1) return -1;
|
||
|
+ dns_transmit_free(&dns_resolve_tx);
|
||
|
+ dns_domain_free(&q);
|
||
|
+ return 0;
|
||
|
+}
|
||
|
diff --git a/dns_nd.c b/dns_nd.c
|
||
|
index 279d74d..aa54e5d 100644
|
||
|
--- a/dns_nd.c
|
||
|
+++ b/dns_nd.c
|
||
|
@@ -2,7 +2,7 @@
|
||
|
#include "fmt.h"
|
||
|
#include "dns.h"
|
||
|
|
||
|
-void dns_name4_domain(char name[DNS_NAME4_DOMAIN],char ip[4])
|
||
|
+void dns_name4_domain(char name[DNS_NAME4_DOMAIN],const char ip[4])
|
||
|
{
|
||
|
unsigned int namelen;
|
||
|
unsigned int i;
|
||
|
diff --git a/dns_nd6.c b/dns_nd6.c
|
||
|
new file mode 100644
|
||
|
index 0000000..fb1da88
|
||
|
--- /dev/null
|
||
|
+++ b/dns_nd6.c
|
||
|
@@ -0,0 +1,28 @@
|
||
|
+#include "byte.h"
|
||
|
+#include "fmt.h"
|
||
|
+#include "dns.h"
|
||
|
+
|
||
|
+/* RFC1886:
|
||
|
+ * 4321:0:1:2:3:4:567:89ab
|
||
|
+ * ->
|
||
|
+ * b.a.9.8.7.6.5.0.4.0.0.0.3.0.0.0.2.0.0.0.1.0.0.0.0.0.0.0.1.2.3.4.IP6.INT.
|
||
|
+ */
|
||
|
+
|
||
|
+static inline char tohex(char c) {
|
||
|
+ return c>=10?c-10+'a':c+'0';
|
||
|
+}
|
||
|
+
|
||
|
+int dns_name6_domain(char name[DNS_NAME6_DOMAIN],char ip[16])
|
||
|
+{
|
||
|
+ unsigned int j;
|
||
|
+
|
||
|
+ for (j=0; j<16; j++) {
|
||
|
+ name[j*4]=1;
|
||
|
+ name[j*4+1]=tohex(ip[15-j] & 15);
|
||
|
+ name[j*4+2]=1;
|
||
|
+ name[j*4+3]=tohex((unsigned char)ip[15-j] >> 4);
|
||
|
+ }
|
||
|
+ byte_copy(name + 4*16,10,"\3ip6\4arpa\0");
|
||
|
+ return 4*16+10;
|
||
|
+}
|
||
|
+
|
||
|
diff --git a/dns_packet.c b/dns_packet.c
|
||
|
index 04a2cc8..72cfb35 100644
|
||
|
--- a/dns_packet.c
|
||
|
+++ b/dns_packet.c
|
||
|
@@ -2,10 +2,11 @@
|
||
|
DNS should have used LZ77 instead of its own sophomoric compression algorithm.
|
||
|
*/
|
||
|
|
||
|
-#include "error.h"
|
||
|
+#include <errno.h>
|
||
|
#include "dns.h"
|
||
|
+#include "error.h"
|
||
|
|
||
|
-unsigned int dns_packet_copy(char *buf,unsigned int len,unsigned int pos,char *out,unsigned int outlen)
|
||
|
+unsigned int dns_packet_copy(const char *buf,unsigned int len,unsigned int pos,char *out,unsigned int outlen)
|
||
|
{
|
||
|
while (outlen) {
|
||
|
if (pos >= len) { errno = error_proto; return 0; }
|
||
|
@@ -15,7 +16,7 @@ unsigned int dns_packet_copy(char *buf,unsigned int len,unsigned int pos,char *o
|
||
|
return pos;
|
||
|
}
|
||
|
|
||
|
-unsigned int dns_packet_skipname(char *buf,unsigned int len,unsigned int pos)
|
||
|
+unsigned int dns_packet_skipname(const char *buf,unsigned int len,unsigned int pos)
|
||
|
{
|
||
|
unsigned char ch;
|
||
|
|
||
|
@@ -32,7 +33,7 @@ unsigned int dns_packet_skipname(char *buf,unsigned int len,unsigned int pos)
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
-unsigned int dns_packet_getname(char *buf,unsigned int len,unsigned int pos,char **d)
|
||
|
+unsigned int dns_packet_getname(const char *buf,unsigned int len,unsigned int pos,char **d)
|
||
|
{
|
||
|
unsigned int loop = 0;
|
||
|
unsigned int state = 0;
|
||
|
diff --git a/dns_random.c b/dns_random.c
|
||
|
index b9892b4..2158ed4 100644
|
||
|
--- a/dns_random.c
|
||
|
+++ b/dns_random.c
|
||
|
@@ -1,3 +1,4 @@
|
||
|
+#include <unistd.h>
|
||
|
#include "dns.h"
|
||
|
#include "taia.h"
|
||
|
#include "uint32.h"
|
||
|
@@ -29,7 +30,7 @@ static void surf(void)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
-void dns_random_init(char data[128])
|
||
|
+void dns_random_init(const char data[128])
|
||
|
{
|
||
|
int i;
|
||
|
struct taia t;
|
||
|
diff --git a/dns_rcip.c b/dns_rcip.c
|
||
|
index 2356c8b..794f6be 100644
|
||
|
--- a/dns_rcip.c
|
||
|
+++ b/dns_rcip.c
|
||
|
@@ -2,12 +2,13 @@
|
||
|
#include "openreadclose.h"
|
||
|
#include "byte.h"
|
||
|
#include "ip4.h"
|
||
|
-#include "env.h"
|
||
|
+#include "ip6.h"
|
||
|
#include "dns.h"
|
||
|
+#include "env.h"
|
||
|
|
||
|
static stralloc data = {0};
|
||
|
|
||
|
-static int init(char ip[64])
|
||
|
+static int init(char ip[256])
|
||
|
{
|
||
|
int i;
|
||
|
int j;
|
||
|
@@ -16,15 +17,16 @@ static int init(char ip[64])
|
||
|
|
||
|
x = env_get("DNSCACHEIP");
|
||
|
if (x)
|
||
|
- while (iplen <= 60)
|
||
|
+ while (iplen <= 60) {
|
||
|
if (*x == '.')
|
||
|
++x;
|
||
|
else {
|
||
|
- i = ip4_scan(x,ip + iplen);
|
||
|
+ i = scan_ip6(x,ip + iplen);
|
||
|
if (!i) break;
|
||
|
x += i;
|
||
|
- iplen += 4;
|
||
|
+ iplen += 16;
|
||
|
}
|
||
|
+ }
|
||
|
|
||
|
if (!iplen) {
|
||
|
i = openreadclose("/etc/resolv.conf",&data,64);
|
||
|
@@ -39,8 +41,9 @@ static int init(char ip[64])
|
||
|
while ((data.s[i] == ' ') || (data.s[i] == '\t'))
|
||
|
++i;
|
||
|
if (iplen <= 60)
|
||
|
- if (ip4_scan(data.s + i,ip + iplen))
|
||
|
- iplen += 4;
|
||
|
+ if (scan_ip6(data.s + i,ip + iplen)) {
|
||
|
+ iplen += 16;
|
||
|
+ }
|
||
|
}
|
||
|
i = j + 1;
|
||
|
}
|
||
|
@@ -48,19 +51,19 @@ static int init(char ip[64])
|
||
|
}
|
||
|
|
||
|
if (!iplen) {
|
||
|
- byte_copy(ip,4,"\177\0\0\1");
|
||
|
- iplen = 4;
|
||
|
+ byte_copy(ip,16,"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1");
|
||
|
+ iplen = 16;
|
||
|
}
|
||
|
- byte_zero(ip + iplen,64 - iplen);
|
||
|
+ byte_zero(ip + iplen,256 - iplen);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int ok = 0;
|
||
|
static unsigned int uses;
|
||
|
static struct taia deadline;
|
||
|
-static char ip[64]; /* defined if ok */
|
||
|
+static char ip[256]; /* defined if ok */
|
||
|
|
||
|
-int dns_resolvconfip(char s[64])
|
||
|
+int dns_resolvconfip(char s[256])
|
||
|
{
|
||
|
struct taia now;
|
||
|
|
||
|
@@ -77,6 +80,6 @@ int dns_resolvconfip(char s[64])
|
||
|
}
|
||
|
|
||
|
--uses;
|
||
|
- byte_copy(s,64,ip);
|
||
|
+ byte_copy(s,256,ip);
|
||
|
return 0;
|
||
|
}
|
||
|
diff --git a/dns_rcrw.c b/dns_rcrw.c
|
||
|
index 6f215ac..b0c8e6d 100644
|
||
|
--- a/dns_rcrw.c
|
||
|
+++ b/dns_rcrw.c
|
||
|
@@ -1,16 +1,17 @@
|
||
|
+#include <unistd.h>
|
||
|
#include "taia.h"
|
||
|
-#include "env.h"
|
||
|
#include "byte.h"
|
||
|
#include "str.h"
|
||
|
#include "openreadclose.h"
|
||
|
#include "dns.h"
|
||
|
+#include "env.h"
|
||
|
|
||
|
static stralloc data = {0};
|
||
|
|
||
|
static int init(stralloc *rules)
|
||
|
{
|
||
|
char host[256];
|
||
|
- char *x;
|
||
|
+ const char *x;
|
||
|
int i;
|
||
|
int j;
|
||
|
int k;
|
||
|
diff --git a/dns_resolve.c b/dns_resolve.c
|
||
|
index 3365c00..82b5bbb 100644
|
||
|
--- a/dns_resolve.c
|
||
|
+++ b/dns_resolve.c
|
||
|
@@ -2,19 +2,20 @@
|
||
|
#include "taia.h"
|
||
|
#include "byte.h"
|
||
|
#include "dns.h"
|
||
|
+#include "ip6.h"
|
||
|
|
||
|
struct dns_transmit dns_resolve_tx = {0};
|
||
|
|
||
|
-int dns_resolve(char *q,char qtype[2])
|
||
|
+int dns_resolve(const char *q,const char qtype[2])
|
||
|
{
|
||
|
struct taia stamp;
|
||
|
struct taia deadline;
|
||
|
- char servers[64];
|
||
|
+ char servers[256];
|
||
|
iopause_fd x[1];
|
||
|
int r;
|
||
|
|
||
|
if (dns_resolvconfip(servers) == -1) return -1;
|
||
|
- if (dns_transmit_start(&dns_resolve_tx,servers,1,q,qtype,"\0\0\0\0") == -1) return -1;
|
||
|
+ if (dns_transmit_start(&dns_resolve_tx,servers,1,q,qtype,V6any) == -1) return -1;
|
||
|
|
||
|
for (;;) {
|
||
|
taia_now(&stamp);
|
||
|
diff --git a/dns_sortip6.c b/dns_sortip6.c
|
||
|
new file mode 100644
|
||
|
index 0000000..7e752e9
|
||
|
--- /dev/null
|
||
|
+++ b/dns_sortip6.c
|
||
|
@@ -0,0 +1,20 @@
|
||
|
+#include "byte.h"
|
||
|
+#include "dns.h"
|
||
|
+
|
||
|
+/* XXX: sort servers by configurable notion of closeness? */
|
||
|
+/* XXX: pay attention to competence of each server? */
|
||
|
+
|
||
|
+void dns_sortip6(char *s,unsigned int n)
|
||
|
+{
|
||
|
+ unsigned int i;
|
||
|
+ char tmp[16];
|
||
|
+
|
||
|
+ n >>= 4;
|
||
|
+ while (n > 1) {
|
||
|
+ i = dns_random(n);
|
||
|
+ --n;
|
||
|
+ byte_copy(tmp,16,s + (i << 4));
|
||
|
+ byte_copy(s + (i << 4),16,s + (n << 4));
|
||
|
+ byte_copy(s + (n << 4),16,tmp);
|
||
|
+ }
|
||
|
+}
|
||
|
diff --git a/dns_transmit.c b/dns_transmit.c
|
||
|
index df12826..9511511 100644
|
||
|
--- a/dns_transmit.c
|
||
|
+++ b/dns_transmit.c
|
||
|
@@ -1,12 +1,15 @@
|
||
|
+#include <sys/types.h>
|
||
|
+#include <sys/socket.h>
|
||
|
+#include <unistd.h>
|
||
|
+#include <stdlib.h>
|
||
|
#include "socket.h"
|
||
|
-#include "alloc.h"
|
||
|
-#include "error.h"
|
||
|
+#include <errno.h>
|
||
|
#include "byte.h"
|
||
|
-#include "readwrite.h"
|
||
|
#include "uint16.h"
|
||
|
#include "dns.h"
|
||
|
+#include "ip6.h"
|
||
|
|
||
|
-static int serverwantstcp(char *buf,unsigned int len)
|
||
|
+static int serverwantstcp(const char *buf,unsigned int len)
|
||
|
{
|
||
|
char out[12];
|
||
|
|
||
|
@@ -15,7 +18,7 @@ static int serverwantstcp(char *buf,unsigned int len)
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
-static int serverfailed(char *buf,unsigned int len)
|
||
|
+static int serverfailed(const char *buf,unsigned int len)
|
||
|
{
|
||
|
char out[12];
|
||
|
unsigned int rcode;
|
||
|
@@ -23,11 +26,11 @@ static int serverfailed(char *buf,unsigned int len)
|
||
|
if (!dns_packet_copy(buf,len,0,out,12)) return 1;
|
||
|
rcode = out[3];
|
||
|
rcode &= 15;
|
||
|
- if (rcode && (rcode != 3)) { errno = error_again; return 1; }
|
||
|
+ if (rcode && (rcode != 3)) { errno = EAGAIN; return 1; }
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
-static int irrelevant(struct dns_transmit *d,char *buf,unsigned int len)
|
||
|
+static int irrelevant(const struct dns_transmit *d,const char *buf,unsigned int len)
|
||
|
{
|
||
|
char out[12];
|
||
|
char *dn;
|
||
|
@@ -40,8 +43,8 @@ static int irrelevant(struct dns_transmit *d,char *buf,unsigned int len)
|
||
|
|
||
|
dn = 0;
|
||
|
pos = dns_packet_getname(buf,len,pos,&dn); if (!pos) return 1;
|
||
|
- if (!dns_domain_equal(dn,d->query + 14)) { alloc_free(dn); return 1; }
|
||
|
- alloc_free(dn);
|
||
|
+ if (!dns_domain_equal(dn,d->query + 14)) { free(dn); return 1; }
|
||
|
+ free(dn);
|
||
|
|
||
|
pos = dns_packet_copy(buf,len,pos,out,4); if (!pos) return 1;
|
||
|
if (byte_diff(out,2,d->qtype)) return 1;
|
||
|
@@ -53,14 +56,14 @@ static int irrelevant(struct dns_transmit *d,char *buf,unsigned int len)
|
||
|
static void packetfree(struct dns_transmit *d)
|
||
|
{
|
||
|
if (!d->packet) return;
|
||
|
- alloc_free(d->packet);
|
||
|
+ free(d->packet);
|
||
|
d->packet = 0;
|
||
|
}
|
||
|
|
||
|
static void queryfree(struct dns_transmit *d)
|
||
|
{
|
||
|
if (!d->query) return;
|
||
|
- alloc_free(d->query);
|
||
|
+ free(d->query);
|
||
|
d->query = 0;
|
||
|
}
|
||
|
|
||
|
@@ -83,9 +86,9 @@ static int randombind(struct dns_transmit *d)
|
||
|
int j;
|
||
|
|
||
|
for (j = 0;j < 10;++j)
|
||
|
- if (socket_bind4(d->s1 - 1,d->localip,1025 + dns_random(64510)) == 0)
|
||
|
+ if (socket_bind6(d->s1 - 1,d->localip,1025 + dns_random(64510),d->scope_id) == 0)
|
||
|
return 0;
|
||
|
- if (socket_bind4(d->s1 - 1,d->localip,0) == 0)
|
||
|
+ if (socket_bind6(d->s1 - 1,d->localip,0,d->scope_id) == 0)
|
||
|
return 0;
|
||
|
return -1;
|
||
|
}
|
||
|
@@ -94,22 +97,22 @@ static const int timeouts[4] = { 1, 3, 11, 45 };
|
||
|
|
||
|
static int thisudp(struct dns_transmit *d)
|
||
|
{
|
||
|
- char *ip;
|
||
|
+ const char *ip;
|
||
|
|
||
|
socketfree(d);
|
||
|
|
||
|
while (d->udploop < 4) {
|
||
|
for (;d->curserver < 16;++d->curserver) {
|
||
|
- ip = d->servers + 4 * d->curserver;
|
||
|
- if (byte_diff(ip,4,"\0\0\0\0")) {
|
||
|
+ ip = d->servers + 16 * d->curserver;
|
||
|
+ if (byte_diff(ip,16,V6any)) {
|
||
|
d->query[2] = dns_random(256);
|
||
|
d->query[3] = dns_random(256);
|
||
|
|
||
|
- d->s1 = 1 + socket_udp();
|
||
|
+ d->s1 = 1 + socket_udp6();
|
||
|
if (!d->s1) { dns_transmit_free(d); return -1; }
|
||
|
if (randombind(d) == -1) { dns_transmit_free(d); return -1; }
|
||
|
|
||
|
- if (socket_connect4(d->s1 - 1,ip,53) == 0)
|
||
|
+ if (socket_connect6(d->s1 - 1,ip,53,d->scope_id) == 0)
|
||
|
if (send(d->s1 - 1,d->query + 2,d->querylen - 2,0) == d->querylen - 2) {
|
||
|
struct taia now;
|
||
|
taia_now(&now);
|
||
|
@@ -145,29 +148,29 @@ static int nextudp(struct dns_transmit *d)
|
||
|
static int thistcp(struct dns_transmit *d)
|
||
|
{
|
||
|
struct taia now;
|
||
|
- char *ip;
|
||
|
+ const char *ip;
|
||
|
|
||
|
socketfree(d);
|
||
|
packetfree(d);
|
||
|
|
||
|
for (;d->curserver < 16;++d->curserver) {
|
||
|
- ip = d->servers + 4 * d->curserver;
|
||
|
- if (byte_diff(ip,4,"\0\0\0\0")) {
|
||
|
+ ip = d->servers + 16 * d->curserver;
|
||
|
+ if (byte_diff(ip,16,V6any)) {
|
||
|
d->query[2] = dns_random(256);
|
||
|
d->query[3] = dns_random(256);
|
||
|
|
||
|
- d->s1 = 1 + socket_tcp();
|
||
|
+ d->s1 = 1 + socket_tcp6();
|
||
|
if (!d->s1) { dns_transmit_free(d); return -1; }
|
||
|
if (randombind(d) == -1) { dns_transmit_free(d); return -1; }
|
||
|
|
||
|
taia_now(&now);
|
||
|
taia_uint(&d->deadline,10);
|
||
|
taia_add(&d->deadline,&d->deadline,&now);
|
||
|
- if (socket_connect4(d->s1 - 1,ip,53) == 0) {
|
||
|
+ if (socket_connect6(d->s1 - 1,ip,53,d->scope_id) == 0) {
|
||
|
d->tcpstate = 2;
|
||
|
return 0;
|
||
|
}
|
||
|
- if ((errno == error_inprogress) || (errno == error_wouldblock)) {
|
||
|
+ if ((errno == EINPROGRESS) || (errno == EWOULDBLOCK)) {
|
||
|
d->tcpstate = 1;
|
||
|
return 0;
|
||
|
}
|
||
|
@@ -191,16 +194,16 @@ static int nexttcp(struct dns_transmit *d)
|
||
|
return thistcp(d);
|
||
|
}
|
||
|
|
||
|
-int dns_transmit_start(struct dns_transmit *d,char servers[64],int flagrecursive,char *q,char qtype[2],char localip[4])
|
||
|
+int dns_transmit_start(struct dns_transmit *d,const char servers[256],int flagrecursive,const char *q,const char qtype[2],const char localip[16])
|
||
|
{
|
||
|
unsigned int len;
|
||
|
|
||
|
dns_transmit_free(d);
|
||
|
- errno = error_io;
|
||
|
+ errno = EIO;
|
||
|
|
||
|
len = dns_domain_length(q);
|
||
|
d->querylen = len + 18;
|
||
|
- d->query = alloc(d->querylen);
|
||
|
+ d->query = malloc(d->querylen);
|
||
|
if (!d->query) return -1;
|
||
|
|
||
|
uint16_pack_big(d->query,len + 16);
|
||
|
@@ -211,7 +214,7 @@ int dns_transmit_start(struct dns_transmit *d,char servers[64],int flagrecursive
|
||
|
|
||
|
byte_copy(d->qtype,2,qtype);
|
||
|
d->servers = servers;
|
||
|
- byte_copy(d->localip,4,localip);
|
||
|
+ byte_copy(d->localip,16,localip);
|
||
|
|
||
|
d->udploop = flagrecursive ? 1 : 0;
|
||
|
|
||
|
@@ -236,19 +239,19 @@ void dns_transmit_io(struct dns_transmit *d,iopause_fd *x,struct taia *deadline)
|
||
|
*deadline = d->deadline;
|
||
|
}
|
||
|
|
||
|
-int dns_transmit_get(struct dns_transmit *d,iopause_fd *x,struct taia *when)
|
||
|
+int dns_transmit_get(struct dns_transmit *d,const iopause_fd *x,const struct taia *when)
|
||
|
{
|
||
|
char udpbuf[513];
|
||
|
unsigned char ch;
|
||
|
int r;
|
||
|
int fd;
|
||
|
|
||
|
- errno = error_io;
|
||
|
+ errno = EIO;
|
||
|
fd = d->s1 - 1;
|
||
|
|
||
|
if (!x->revents) {
|
||
|
if (taia_less(when,&d->deadline)) return 0;
|
||
|
- errno = error_timeout;
|
||
|
+ errno = ETIMEDOUT;
|
||
|
if (d->tcpstate == 0) return nextudp(d);
|
||
|
return nexttcp(d);
|
||
|
}
|
||
|
@@ -260,7 +263,7 @@ have sent query to curserver on UDP socket s
|
||
|
*/
|
||
|
r = recv(fd,udpbuf,sizeof udpbuf,0);
|
||
|
if (r <= 0) {
|
||
|
- if (d->udploop == 2) return 0;
|
||
|
+ if (errno == ECONNREFUSED) if (d->udploop == 2) return 0;
|
||
|
return nextudp(d);
|
||
|
}
|
||
|
if (r + 1 > sizeof udpbuf) return 0;
|
||
|
@@ -274,7 +277,7 @@ have sent query to curserver on UDP socket s
|
||
|
socketfree(d);
|
||
|
|
||
|
d->packetlen = r;
|
||
|
- d->packet = alloc(d->packetlen);
|
||
|
+ d->packet = malloc(d->packetlen);
|
||
|
if (!d->packet) { dns_transmit_free(d); return -1; }
|
||
|
byte_copy(d->packet,d->packetlen,udpbuf);
|
||
|
queryfree(d);
|
||
|
@@ -334,7 +337,7 @@ have received one byte of packet length into packetlen
|
||
|
d->packetlen += ch;
|
||
|
d->tcpstate = 5;
|
||
|
d->pos = 0;
|
||
|
- d->packet = alloc(d->packetlen);
|
||
|
+ d->packet = malloc(d->packetlen);
|
||
|
if (!d->packet) { dns_transmit_free(d); return -1; }
|
||
|
return 0;
|
||
|
}
|
||
|
diff --git a/dns_txt.c b/dns_txt.c
|
||
|
index 263b641..44deafe 100644
|
||
|
--- a/dns_txt.c
|
||
|
+++ b/dns_txt.c
|
||
|
@@ -3,7 +3,7 @@
|
||
|
#include "byte.h"
|
||
|
#include "dns.h"
|
||
|
|
||
|
-int dns_txt_packet(stralloc *out,char *buf,unsigned int len)
|
||
|
+int dns_txt_packet(stralloc *out,const char *buf,unsigned int len)
|
||
|
{
|
||
|
unsigned int pos;
|
||
|
char header[12];
|
||
|
@@ -48,7 +48,7 @@ int dns_txt_packet(stralloc *out,char *buf,unsigned int len)
|
||
|
|
||
|
static char *q = 0;
|
||
|
|
||
|
-int dns_txt(stralloc *out,stralloc *fqdn)
|
||
|
+int dns_txt(stralloc *out,const stralloc *fqdn)
|
||
|
{
|
||
|
if (!dns_domain_fromdot(&q,fqdn->s,fqdn->len)) return -1;
|
||
|
if (dns_resolve(q,DNS_T_TXT) == -1) return -1;
|
||
|
diff --git a/error.h b/error.h
|
||
|
index d5f3c7e..f660d93 100644
|
||
|
--- a/error.h
|
||
|
+++ b/error.h
|
||
|
@@ -1,7 +1,7 @@
|
||
|
#ifndef ERROR_H
|
||
|
#define ERROR_H
|
||
|
|
||
|
-extern int errno;
|
||
|
+#include <errno.h>
|
||
|
|
||
|
extern int error_intr;
|
||
|
extern int error_nomem;
|
||
|
diff --git a/finger@.1 b/finger@.1
|
||
|
new file mode 100644
|
||
|
index 0000000..93b6288
|
||
|
--- /dev/null
|
||
|
+++ b/finger@.1
|
||
|
@@ -0,0 +1,45 @@
|
||
|
+.TH finger@ 1
|
||
|
+.SH NAME
|
||
|
+finger@ \- get user information from a host
|
||
|
+.SH SYNTAX
|
||
|
+.B finger@
|
||
|
+[
|
||
|
+.I host
|
||
|
+[
|
||
|
+.I user
|
||
|
+]
|
||
|
+]
|
||
|
+.SH DESCRIPTION
|
||
|
+.B finger@
|
||
|
+connects to TCP port 79 (Finger) on
|
||
|
+.IR host ,
|
||
|
+sends
|
||
|
+.I user
|
||
|
+(with an extra CR)
|
||
|
+to
|
||
|
+.IR host ,
|
||
|
+and prints any data it receives.
|
||
|
+It removes CR and converts unprintable characters to a visible format.
|
||
|
+Some computers respond to port 79 with information about
|
||
|
+.IR user .
|
||
|
+
|
||
|
+If
|
||
|
+.I user
|
||
|
+is not supplied,
|
||
|
+.B finger@
|
||
|
+sends a blank line to
|
||
|
+.IR host .
|
||
|
+Some computers respond with information about
|
||
|
+all the users who are logged in.
|
||
|
+
|
||
|
+If
|
||
|
+.I host
|
||
|
+is not supplied,
|
||
|
+.B finger@
|
||
|
+connects to the local host.
|
||
|
+.SH "SEE ALSO"
|
||
|
+addcr(1),
|
||
|
+cat(1),
|
||
|
+delcr(1),
|
||
|
+finger(1),
|
||
|
+tcpclient(1)
|
||
|
diff --git a/fixcr.1 b/fixcr.1
|
||
|
new file mode 100644
|
||
|
index 0000000..ebb8b53
|
||
|
--- /dev/null
|
||
|
+++ b/fixcr.1
|
||
|
@@ -0,0 +1,11 @@
|
||
|
+.TH fixcr 1
|
||
|
+.SH NAME
|
||
|
+fixcr \- make sure that there is a CR before each LF
|
||
|
+.SH SYNOPSIS
|
||
|
+.B fixcr
|
||
|
+.SH DESCRIPTION
|
||
|
+.B fixcr
|
||
|
+inserts CR at the end of each line of input where a CR is not already present.
|
||
|
+It does not insert CR at the end of a partial final line.
|
||
|
+.SH "SEE ALSO"
|
||
|
+addcr(1)
|
||
|
diff --git a/fmt_xlong.c b/fmt_xlong.c
|
||
|
new file mode 100644
|
||
|
index 0000000..332fc9a
|
||
|
--- /dev/null
|
||
|
+++ b/fmt_xlong.c
|
||
|
@@ -0,0 +1,22 @@
|
||
|
+#include "fmt.h"
|
||
|
+
|
||
|
+char tohex(char num) {
|
||
|
+ if (num<10)
|
||
|
+ return num+'0';
|
||
|
+ else if (num<16)
|
||
|
+ return num-10+'a';
|
||
|
+ else
|
||
|
+ return -1;
|
||
|
+}
|
||
|
+
|
||
|
+unsigned int fmt_xlong(register char *s,register unsigned long u)
|
||
|
+{
|
||
|
+ register unsigned int len; register unsigned long q;
|
||
|
+ len = 1; q = u;
|
||
|
+ while (q > 15) { ++len; q /= 16; }
|
||
|
+ if (s) {
|
||
|
+ s += len;
|
||
|
+ do { *--s = tohex(u % 16); u /= 16; } while(u); /* handles u == 0 */
|
||
|
+ }
|
||
|
+ return len;
|
||
|
+}
|
||
|
diff --git a/haveip6.h1 b/haveip6.h1
|
||
|
new file mode 100644
|
||
|
index 0000000..8b13789
|
||
|
--- /dev/null
|
||
|
+++ b/haveip6.h1
|
||
|
@@ -0,0 +1 @@
|
||
|
+
|
||
|
diff --git a/haveip6.h2 b/haveip6.h2
|
||
|
new file mode 100644
|
||
|
index 0000000..5564de9
|
||
|
--- /dev/null
|
||
|
+++ b/haveip6.h2
|
||
|
@@ -0,0 +1 @@
|
||
|
+#define LIBC_HAS_IP6 1
|
||
|
diff --git a/hier.c b/hier.c
|
||
|
index 5663ada..546cc6d 100644
|
||
|
--- a/hier.c
|
||
|
+++ b/hier.c
|
||
|
@@ -4,6 +4,9 @@ void hier()
|
||
|
{
|
||
|
h(auto_home,-1,-1,02755);
|
||
|
d(auto_home,"bin",-1,-1,02755);
|
||
|
+ d(auto_home,"man",-1,-1,02755);
|
||
|
+ d(auto_home,"man/man1",-1,-1,02755);
|
||
|
+ d(auto_home,"man/man5",-1,-1,02755);
|
||
|
|
||
|
c(auto_home,"bin","tcpserver",-1,-1,0755);
|
||
|
c(auto_home,"bin","tcprules",-1,-1,0755);
|
||
|
@@ -22,4 +25,20 @@ void hier()
|
||
|
c(auto_home,"bin","delcr",-1,-1,0755);
|
||
|
c(auto_home,"bin","fixcrio",-1,-1,0755);
|
||
|
c(auto_home,"bin","rblsmtpd",-1,-1,0755);
|
||
|
+
|
||
|
+ c(auto_home,"man/man1","tcpclient.1",-1,-1,0644);
|
||
|
+ c(auto_home,"man/man1","tcpserver.1",-1,-1,0644);
|
||
|
+ c(auto_home,"man/man1","tcprules.1",-1,-1,0644);
|
||
|
+ c(auto_home,"man/man1","tcprulescheck.1",-1,-1,0644);
|
||
|
+ c(auto_home,"man/man1","fixcr.1",-1,-1,0644);
|
||
|
+ c(auto_home,"man/man1","addcr.1",-1,-1,0644);
|
||
|
+ c(auto_home,"man/man1","delcr.1",-1,-1,0644);
|
||
|
+ c(auto_home,"man/man1","who@.1",-1,-1,0644);
|
||
|
+ c(auto_home,"man/man1","date@.1",-1,-1,0644);
|
||
|
+ c(auto_home,"man/man1","finger@.1",-1,-1,0644);
|
||
|
+ c(auto_home,"man/man1","http@.1",-1,-1,0644);
|
||
|
+ c(auto_home,"man/man1","mconnect.1",-1,-1,0644);
|
||
|
+ c(auto_home,"man/man1","argv0.1",-1,-1,0644);
|
||
|
+ c(auto_home,"man/man1","recordio.1",-1,-1,0644);
|
||
|
+ c(auto_home,"man/man5","tcp-environ.5",-1,-1,0644);
|
||
|
}
|
||
|
diff --git a/http@.1 b/http@.1
|
||
|
new file mode 100644
|
||
|
index 0000000..4861b34
|
||
|
--- /dev/null
|
||
|
+++ b/http@.1
|
||
|
@@ -0,0 +1,52 @@
|
||
|
+.TH http@ 1
|
||
|
+.SH NAME
|
||
|
+http@ \- get a web page from a host through HTTP
|
||
|
+.SH SYNTAX
|
||
|
+.B http@
|
||
|
+[
|
||
|
+.I host
|
||
|
+[
|
||
|
+.I page
|
||
|
+[
|
||
|
+.I port
|
||
|
+]
|
||
|
+]
|
||
|
+]
|
||
|
+.SH DESCRIPTION
|
||
|
+.B http@
|
||
|
+connects to
|
||
|
+.I port
|
||
|
+on
|
||
|
+.IR host ,
|
||
|
+sends
|
||
|
+.B GET /\fIpage
|
||
|
+(with an extra CR)
|
||
|
+to
|
||
|
+.IR host ,
|
||
|
+and prints any data it receives,
|
||
|
+removing CR from the end of each line.
|
||
|
+
|
||
|
+If
|
||
|
+.I port
|
||
|
+is not supplied,
|
||
|
+.B http@
|
||
|
+uses port 80 (HTTP).
|
||
|
+
|
||
|
+If
|
||
|
+.I page
|
||
|
+is not supplied,
|
||
|
+.B http@
|
||
|
+sends
|
||
|
+.B GET /
|
||
|
+to
|
||
|
+.IR host .
|
||
|
+
|
||
|
+If
|
||
|
+.I host
|
||
|
+is not supplied,
|
||
|
+.B http@
|
||
|
+connects to the local host.
|
||
|
+.SH "SEE ALSO"
|
||
|
+addcr(1),
|
||
|
+delcr(1),
|
||
|
+tcpclient(1)
|
||
|
diff --git a/ip4.h b/ip4.h
|
||
|
index 64a7c1e..b906557 100644
|
||
|
--- a/ip4.h
|
||
|
+++ b/ip4.h
|
||
|
@@ -6,4 +6,6 @@ extern unsigned int ip4_fmt(char *,char *);
|
||
|
|
||
|
#define IP4_FMT 20
|
||
|
|
||
|
+extern const char ip4loopback[4]; /* = {127,0,0,1}; */
|
||
|
+
|
||
|
#endif
|
||
|
diff --git a/ip6.h b/ip6.h
|
||
|
new file mode 100644
|
||
|
index 0000000..88ff120
|
||
|
--- /dev/null
|
||
|
+++ b/ip6.h
|
||
|
@@ -0,0 +1,28 @@
|
||
|
+#ifndef IP6_H
|
||
|
+#define IP6_H
|
||
|
+
|
||
|
+#include "byte.h"
|
||
|
+
|
||
|
+extern unsigned int scan_ip6(const char *src,char *ip);
|
||
|
+extern unsigned int fmt_ip6(char *dest,const char *ip);
|
||
|
+
|
||
|
+extern unsigned int scan_ip6_flat(const char *src,char *);
|
||
|
+extern unsigned int fmt_ip6_flat(char *dest,const char *);
|
||
|
+
|
||
|
+/*
|
||
|
+ ip6 address syntax: (h = hex digit), no leading '0' required
|
||
|
+ 1. hhhh:hhhh:hhhh:hhhh:hhhh:hhhh:hhhh:hhhh
|
||
|
+ 2. any number of 0000 may be abbreviated as "::", but only once
|
||
|
+ flat ip6 address syntax:
|
||
|
+ hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
|
||
|
+ */
|
||
|
+
|
||
|
+#define IP6_FMT 40
|
||
|
+
|
||
|
+extern const unsigned char V4mappedprefix[12]; /*={0,0,0,0,0,0,0,0,0,0,0xff,0xff}; */
|
||
|
+extern const unsigned char V6loopback[16]; /*={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}; */
|
||
|
+extern const unsigned char V6any[16]; /*={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; */
|
||
|
+
|
||
|
+#define ip6_isv4mapped(ip) (byte_equal(ip,12,V4mappedprefix))
|
||
|
+
|
||
|
+#endif
|
||
|
diff --git a/ip6_fmt.c b/ip6_fmt.c
|
||
|
new file mode 100644
|
||
|
index 0000000..d7c010a
|
||
|
--- /dev/null
|
||
|
+++ b/ip6_fmt.c
|
||
|
@@ -0,0 +1,64 @@
|
||
|
+#include "fmt.h"
|
||
|
+#include "byte.h"
|
||
|
+#include "ip4.h"
|
||
|
+#include "ip6.h"
|
||
|
+
|
||
|
+unsigned int ip6_fmt(char *s,char ip[16])
|
||
|
+{
|
||
|
+ unsigned long len,temp, k, pos0=0,len0=0, pos1=0, compr=0;
|
||
|
+
|
||
|
+ for (k=0; k<16; k+=2) {
|
||
|
+ if (ip[k]==0 && ip[k+1]==0) {
|
||
|
+ if (!compr) {
|
||
|
+ compr=1;
|
||
|
+ pos1=k;
|
||
|
+ }
|
||
|
+ if (k==14) { k=16; goto last; }
|
||
|
+ } else if (compr) {
|
||
|
+ last:
|
||
|
+ if ((temp=k-pos1) > len0) {
|
||
|
+ len0=temp;
|
||
|
+ pos0=pos1;
|
||
|
+ }
|
||
|
+ compr=0;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ for (len=0,k=0; k<16; k+=2) {
|
||
|
+ if (k==12 && ip6_isv4mapped(ip)) {
|
||
|
+ len += ip4_fmt(s,ip+12);
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ if (pos0==k && len0) {
|
||
|
+ if (k==0) { ++len; if (s) *s++ = ':'; }
|
||
|
+ ++len; if (s) *s++ = ':';
|
||
|
+ k += len0-2;
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+ temp = ((unsigned long) (unsigned char) ip[k] << 8) +
|
||
|
+ (unsigned long) (unsigned char) ip[k+1];
|
||
|
+ temp = fmt_xlong(s,temp); len += temp; if (s) s += temp;
|
||
|
+ if (k<14) { ++len; if (s) *s++ = ':'; }
|
||
|
+ }
|
||
|
+
|
||
|
+ return len;
|
||
|
+}
|
||
|
+
|
||
|
+static char tohex(char num) {
|
||
|
+ if (num<10)
|
||
|
+ return num+'0';
|
||
|
+ else if (num<16)
|
||
|
+ return num-10+'a';
|
||
|
+ else
|
||
|
+ return -1;
|
||
|
+}
|
||
|
+
|
||
|
+unsigned int ip6_fmt_flat(char *s,char ip[16])
|
||
|
+{
|
||
|
+ int i;
|
||
|
+ for (i=0; i<16; i++) {
|
||
|
+ *s++=tohex((unsigned char)ip[i] >> 4);
|
||
|
+ *s++=tohex((unsigned char)ip[i] & 15);
|
||
|
+ }
|
||
|
+ return 32;
|
||
|
+}
|
||
|
diff --git a/mconnect.1 b/mconnect.1
|
||
|
new file mode 100644
|
||
|
index 0000000..6648367
|
||
|
--- /dev/null
|
||
|
+++ b/mconnect.1
|
||
|
@@ -0,0 +1,36 @@
|
||
|
+.TH mconnect 1
|
||
|
+.SH NAME
|
||
|
+mconnect \- connect to the SMTP server on a host
|
||
|
+.SH SYNTAX
|
||
|
+.B mconnect
|
||
|
+[
|
||
|
+.I host
|
||
|
+[
|
||
|
+.I port
|
||
|
+]
|
||
|
+]
|
||
|
+.SH DESCRIPTION
|
||
|
+.B mconnect
|
||
|
+connects to
|
||
|
+.I port
|
||
|
+on
|
||
|
+.IR host .
|
||
|
+It sends its input to
|
||
|
+.IR host ,
|
||
|
+adding a CR to each line.
|
||
|
+Meanwhile it prints anything it receives from
|
||
|
+.IR host .
|
||
|
+
|
||
|
+If
|
||
|
+.I port
|
||
|
+is not supplied,
|
||
|
+.B mconnect
|
||
|
+uses port 25 (SMTP).
|
||
|
+
|
||
|
+If
|
||
|
+.I host
|
||
|
+is not supplied,
|
||
|
+.B mconnect
|
||
|
+connects to the local host.
|
||
|
+.SH "SEE ALSO"
|
||
|
+tcpclient(1)
|
||
|
diff --git a/old-rules.c b/old-rules.c
|
||
|
new file mode 100644
|
||
|
index 0000000..7225115
|
||
|
--- /dev/null
|
||
|
+++ b/old-rules.c
|
||
|
@@ -0,0 +1,101 @@
|
||
|
+#include "alloc.h"
|
||
|
+#include "stralloc.h"
|
||
|
+#include "open.h"
|
||
|
+#include "cdb.h"
|
||
|
+#include "rules.h"
|
||
|
+
|
||
|
+stralloc rules_name = {0};
|
||
|
+
|
||
|
+static struct cdb c;
|
||
|
+
|
||
|
+static int dorule(void (*callback)(char *,unsigned int))
|
||
|
+{
|
||
|
+ char *data;
|
||
|
+ unsigned int datalen;
|
||
|
+
|
||
|
+ switch(cdb_find(&c,rules_name.s,rules_name.len)) {
|
||
|
+ case -1: return -1;
|
||
|
+ case 0: return 0;
|
||
|
+ }
|
||
|
+
|
||
|
+ datalen = cdb_datalen(&c);
|
||
|
+ data = alloc(datalen);
|
||
|
+ if (!data) return -1;
|
||
|
+ if (cdb_read(&c,data,datalen,cdb_datapos(&c)) == -1) {
|
||
|
+ alloc_free(data);
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+
|
||
|
+ callback(data,datalen);
|
||
|
+ alloc_free(data);
|
||
|
+ return 1;
|
||
|
+}
|
||
|
+
|
||
|
+static int doit(void (*callback)(char *,unsigned int),char *ip,char *host,char *info)
|
||
|
+{
|
||
|
+ int r;
|
||
|
+
|
||
|
+ if (info) {
|
||
|
+ if (!stralloc_copys(&rules_name,info)) return -1;
|
||
|
+ if (!stralloc_cats(&rules_name,"@")) return -1;
|
||
|
+ if (!stralloc_cats(&rules_name,ip)) return -1;
|
||
|
+ r = dorule(callback);
|
||
|
+ if (r) return r;
|
||
|
+
|
||
|
+ if (host) {
|
||
|
+ if (!stralloc_copys(&rules_name,info)) return -1;
|
||
|
+ if (!stralloc_cats(&rules_name,"@=")) return -1;
|
||
|
+ if (!stralloc_cats(&rules_name,host)) return -1;
|
||
|
+ r = dorule(callback);
|
||
|
+ if (r) return r;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ if (!stralloc_copys(&rules_name,ip)) return -1;
|
||
|
+ r = dorule(callback);
|
||
|
+ if (r) return r;
|
||
|
+
|
||
|
+ if (host) {
|
||
|
+ if (!stralloc_copys(&rules_name,"=")) return -1;
|
||
|
+ if (!stralloc_cats(&rules_name,host)) return -1;
|
||
|
+ r = dorule(callback);
|
||
|
+ if (r) return r;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (!stralloc_copys(&rules_name,ip)) return -1;
|
||
|
+ while (rules_name.len > 0) {
|
||
|
+ if (ip[rules_name.len - 1] == '.' ||
|
||
|
+ (ip[rules_name.len-1]==':' && rules_name.len>1)) {
|
||
|
+ r = dorule(callback);
|
||
|
+ if (r) return r;
|
||
|
+ }
|
||
|
+ --rules_name.len;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (host) {
|
||
|
+ while (*host) {
|
||
|
+ if (*host == '.') {
|
||
|
+ if (!stralloc_copys(&rules_name,"=")) return -1;
|
||
|
+ if (!stralloc_cats(&rules_name,host)) return -1;
|
||
|
+ r = dorule(callback);
|
||
|
+ if (r) return r;
|
||
|
+ }
|
||
|
+ ++host;
|
||
|
+ }
|
||
|
+ if (!stralloc_copys(&rules_name,"=")) return -1;
|
||
|
+ r = dorule(callback);
|
||
|
+ if (r) return r;
|
||
|
+ }
|
||
|
+
|
||
|
+ rules_name.len = 0;
|
||
|
+ return dorule(callback);
|
||
|
+}
|
||
|
+
|
||
|
+int rules(void (*callback)(char *,unsigned int),int fd,char *ip,char *host,char *info)
|
||
|
+{
|
||
|
+ int r;
|
||
|
+ cdb_init(&c,fd);
|
||
|
+ r = doit(callback,ip,host,info);
|
||
|
+ cdb_free(&c);
|
||
|
+ return r;
|
||
|
+}
|
||
|
diff --git a/pathexec.h b/pathexec.h
|
||
|
index 6fcbb89..bef93b4 100644
|
||
|
--- a/pathexec.h
|
||
|
+++ b/pathexec.h
|
||
|
@@ -2,7 +2,7 @@
|
||
|
#define PATHEXEC_H
|
||
|
|
||
|
extern void pathexec_run(char *,char **,char **);
|
||
|
-extern int pathexec_env(char *,char *);
|
||
|
+extern int pathexec_env(const char *,const char *);
|
||
|
extern void pathexec(char **);
|
||
|
|
||
|
#endif
|
||
|
diff --git a/pathexec_env.c b/pathexec_env.c
|
||
|
index 48bba7e..157e71b 100644
|
||
|
--- a/pathexec_env.c
|
||
|
+++ b/pathexec_env.c
|
||
|
@@ -8,7 +8,7 @@
|
||
|
static stralloc plus;
|
||
|
static stralloc tmp;
|
||
|
|
||
|
-int pathexec_env(char *s,char *t)
|
||
|
+int pathexec_env(const char *s,const char *t)
|
||
|
{
|
||
|
if (!s) return 1;
|
||
|
if (!stralloc_copys(&tmp,s)) return 0;
|
||
|
@@ -22,7 +22,6 @@ int pathexec_env(char *s,char *t)
|
||
|
|
||
|
void pathexec(char **argv)
|
||
|
{
|
||
|
- char *path;
|
||
|
char **e;
|
||
|
unsigned int elen;
|
||
|
unsigned int i;
|
||
|
diff --git a/recordio.1 b/recordio.1
|
||
|
new file mode 100644
|
||
|
index 0000000..e056776
|
||
|
--- /dev/null
|
||
|
+++ b/recordio.1
|
||
|
@@ -0,0 +1,75 @@
|
||
|
+.TH recordio 1
|
||
|
+.SH NAME
|
||
|
+recordio \- record the input and output of a program
|
||
|
+.SH SYNTAX
|
||
|
+.B recordio
|
||
|
+.I program
|
||
|
+[
|
||
|
+.I arg ...
|
||
|
+]
|
||
|
+.SH DESCRIPTION
|
||
|
+.B recordio
|
||
|
+runs
|
||
|
+.I program
|
||
|
+with the given arguments.
|
||
|
+It prints lines to stderr
|
||
|
+showing the input and output of
|
||
|
+.IR program .
|
||
|
+
|
||
|
+At the beginning of each line on stderr,
|
||
|
+.B recordio
|
||
|
+inserts the
|
||
|
+.I program
|
||
|
+process ID,
|
||
|
+along with
|
||
|
+.B <
|
||
|
+for input or
|
||
|
+.B >
|
||
|
+for output.
|
||
|
+At the end of each line it inserts a space, a plus sign, or [EOF];
|
||
|
+a space indicates that there was a newline in the input or output,
|
||
|
+and [EOF] indicates the end of input or output.
|
||
|
+
|
||
|
+.B recordio
|
||
|
+prints every packet of input and output immediately.
|
||
|
+It does not attempt to combine packets into coherent stderr lines.
|
||
|
+For example,
|
||
|
+
|
||
|
+.EX
|
||
|
+ recordio sh -c 'cat /dev/fd/8 2>&1' > /dev/null
|
||
|
+.EE
|
||
|
+
|
||
|
+could produce
|
||
|
+
|
||
|
+.EX
|
||
|
+ 5135 > cat: /dev/fd/8: Bad file descriptor
|
||
|
+.br
|
||
|
+ 5135 > [EOF]
|
||
|
+.EE
|
||
|
+
|
||
|
+or
|
||
|
+
|
||
|
+.EX
|
||
|
+ 5135 > cat: +
|
||
|
+.br
|
||
|
+ 5135 > /dev/fd/8+
|
||
|
+.br
|
||
|
+ 5135 > : +
|
||
|
+.br
|
||
|
+ 5135 > Bad file descriptor
|
||
|
+.br
|
||
|
+ 5135 > [EOF]
|
||
|
+.EE
|
||
|
+
|
||
|
+.B recordio
|
||
|
+uses several lines for long packets
|
||
|
+to guarantee that each line is printed atomically to stderr.
|
||
|
+
|
||
|
+.B recordio
|
||
|
+runs as a child of
|
||
|
+.IR program .
|
||
|
+It exits when it sees the end of
|
||
|
+.IR program 's
|
||
|
+output.
|
||
|
+.SH "SEE ALSO"
|
||
|
+tcpserver(1)
|
||
|
diff --git a/remoteinfo.h b/remoteinfo.h
|
||
|
index 2ca779d..0884cc1 100644
|
||
|
--- a/remoteinfo.h
|
||
|
+++ b/remoteinfo.h
|
||
|
@@ -5,5 +5,6 @@
|
||
|
#include "uint16.h"
|
||
|
|
||
|
extern int remoteinfo(stralloc *,char *,uint16,char *,uint16,unsigned int);
|
||
|
+extern int remoteinfo6(stralloc *,char *,uint16,char *,uint16,unsigned int,uint32);
|
||
|
|
||
|
#endif
|
||
|
diff --git a/remoteinfo6.c b/remoteinfo6.c
|
||
|
new file mode 100644
|
||
|
index 0000000..cf3b7c1
|
||
|
--- /dev/null
|
||
|
+++ b/remoteinfo6.c
|
||
|
@@ -0,0 +1,98 @@
|
||
|
+#include "fmt.h"
|
||
|
+#include "buffer.h"
|
||
|
+#include "socket.h"
|
||
|
+#include "error.h"
|
||
|
+#include "iopause.h"
|
||
|
+#include "timeoutconn.h"
|
||
|
+#include "remoteinfo.h"
|
||
|
+
|
||
|
+static struct taia now;
|
||
|
+static struct taia deadline;
|
||
|
+
|
||
|
+static int mywrite(int fd,char *buf,int len)
|
||
|
+{
|
||
|
+ iopause_fd x;
|
||
|
+
|
||
|
+ x.fd = fd;
|
||
|
+ x.events = IOPAUSE_WRITE;
|
||
|
+ for (;;) {
|
||
|
+ taia_now(&now);
|
||
|
+ iopause(&x,1,&deadline,&now);
|
||
|
+ if (x.revents) break;
|
||
|
+ if (taia_less(&deadline,&now)) {
|
||
|
+ errno = error_timeout;
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ return write(fd,buf,len);
|
||
|
+}
|
||
|
+
|
||
|
+static int myread(int fd,char *buf,int len)
|
||
|
+{
|
||
|
+ iopause_fd x;
|
||
|
+
|
||
|
+ x.fd = fd;
|
||
|
+ x.events = IOPAUSE_READ;
|
||
|
+ for (;;) {
|
||
|
+ taia_now(&now);
|
||
|
+ iopause(&x,1,&deadline,&now);
|
||
|
+ if (x.revents) break;
|
||
|
+ if (taia_less(&deadline,&now)) {
|
||
|
+ errno = error_timeout;
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ return read(fd,buf,len);
|
||
|
+}
|
||
|
+
|
||
|
+static int doit(stralloc *out,int s,char ipremote[16],uint16 portremote,char iplocal[16],uint16 portlocal,unsigned int timeout,uint32 netif)
|
||
|
+{
|
||
|
+ buffer b;
|
||
|
+ char bspace[128];
|
||
|
+ char strnum[FMT_ULONG];
|
||
|
+ int numcolons;
|
||
|
+ char ch;
|
||
|
+
|
||
|
+ if (socket_bind6(s,iplocal,0,netif) == -1) return -1;
|
||
|
+ if (timeoutconn6(s,ipremote,113,timeout,netif) == -1) return -1;
|
||
|
+
|
||
|
+ buffer_init(&b,mywrite,s,bspace,sizeof bspace);
|
||
|
+ buffer_put(&b,strnum,fmt_ulong(strnum,portremote));
|
||
|
+ buffer_put(&b," , ",3);
|
||
|
+ buffer_put(&b,strnum,fmt_ulong(strnum,portlocal));
|
||
|
+ buffer_put(&b,"\r\n",2);
|
||
|
+ if (buffer_flush(&b) == -1) return -1;
|
||
|
+
|
||
|
+ buffer_init(&b,myread,s,bspace,sizeof bspace);
|
||
|
+ numcolons = 0;
|
||
|
+ for (;;) {
|
||
|
+ if (buffer_get(&b,&ch,1) != 1) return -1;
|
||
|
+ if ((ch == ' ') || (ch == '\t') || (ch == '\r')) continue;
|
||
|
+ if (ch == '\n') return 0;
|
||
|
+ if (numcolons < 3) {
|
||
|
+ if (ch == ':') ++numcolons;
|
||
|
+ }
|
||
|
+ else {
|
||
|
+ if (!stralloc_append(out,&ch)) return -1;
|
||
|
+ if (out->len > 256) return 0;
|
||
|
+ }
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+int remoteinfo6(stralloc *out,char ipremote[16],uint16 portremote,char iplocal[16],uint16 portlocal,unsigned int timeout,uint32 netif)
|
||
|
+{
|
||
|
+ int s;
|
||
|
+ int r;
|
||
|
+
|
||
|
+ if (!stralloc_copys(out,"")) return -1;
|
||
|
+
|
||
|
+ taia_now(&now);
|
||
|
+ taia_uint(&deadline,timeout);
|
||
|
+ taia_add(&deadline,&now,&deadline);
|
||
|
+
|
||
|
+ s = socket_tcp6();
|
||
|
+ if (s == -1) return -1;
|
||
|
+ r = doit(out,s,ipremote,portremote,iplocal,portlocal,timeout,netif);
|
||
|
+ close(s);
|
||
|
+ return r;
|
||
|
+}
|
||
|
diff --git a/rules.c b/rules.c
|
||
|
index 1840360..4fc2354 100644
|
||
|
--- a/rules.c
|
||
|
+++ b/rules.c
|
||
|
@@ -64,7 +64,7 @@ static int doit(void (*callback)(char *,unsigned int),char *ip,char *host,char *
|
||
|
|
||
|
if (!stralloc_copys(&rules_name,ip)) return -1;
|
||
|
while (rules_name.len > 0) {
|
||
|
- if (ip[rules_name.len - 1] == '.') {
|
||
|
+ if (ip[rules_name.len - 1] == '.' || ip[rules_name.len - 1] == ':') {
|
||
|
r = dorule(callback);
|
||
|
if (r) return r;
|
||
|
}
|
||
|
diff --git a/scan_ip6.c b/scan_ip6.c
|
||
|
new file mode 100644
|
||
|
index 0000000..ee239fd
|
||
|
--- /dev/null
|
||
|
+++ b/scan_ip6.c
|
||
|
@@ -0,0 +1,87 @@
|
||
|
+#include "scan.h"
|
||
|
+#include "ip4.h"
|
||
|
+#include "ip6.h"
|
||
|
+
|
||
|
+/*
|
||
|
+ * IPv6 addresses are really ugly to parse.
|
||
|
+ * Syntax: (h = hex digit)
|
||
|
+ * 1. hhhh:hhhh:hhhh:hhhh:hhhh:hhhh:hhhh:hhhh
|
||
|
+ * 2. any number of 0000 may be abbreviated as "::", but only once
|
||
|
+ * 3. The last two words may be written as IPv4 address
|
||
|
+ */
|
||
|
+
|
||
|
+unsigned int scan_ip6(const char *s,char ip[16])
|
||
|
+{
|
||
|
+ unsigned int i;
|
||
|
+ unsigned int len=0;
|
||
|
+ unsigned long u;
|
||
|
+
|
||
|
+ char suffix[16];
|
||
|
+ int prefixlen=0;
|
||
|
+ int suffixlen=0;
|
||
|
+
|
||
|
+ if ((i=ip4_scan((char*)s,ip+12))) {
|
||
|
+ for (len=0; len<12; ++len) ip[len]=V4mappedprefix[len];
|
||
|
+ return i;
|
||
|
+ }
|
||
|
+ for (i=0; i<16; i++) ip[i]=0;
|
||
|
+ for (;;) {
|
||
|
+ if (*s == ':') {
|
||
|
+ len++;
|
||
|
+ if (s[1] == ':') { /* Found "::", skip to part 2 */
|
||
|
+ s+=2;
|
||
|
+ len++;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ s++;
|
||
|
+ }
|
||
|
+ i = scan_xlong((char*)s,&u);
|
||
|
+ if (!i) return 0;
|
||
|
+ if (prefixlen==12 && s[i]=='.') {
|
||
|
+ /* the last 4 bytes may be written as IPv4 address */
|
||
|
+ i=ip4_scan((char*)s,ip+12);
|
||
|
+ if (i)
|
||
|
+ return i+len;
|
||
|
+ else
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+ ip[prefixlen++] = (u >> 8);
|
||
|
+ ip[prefixlen++] = (u & 255);
|
||
|
+ s += i; len += i;
|
||
|
+ if (prefixlen==16)
|
||
|
+ return len;
|
||
|
+ }
|
||
|
+
|
||
|
+/* part 2, after "::" */
|
||
|
+ for (;;) {
|
||
|
+ if (*s == ':') {
|
||
|
+ if (suffixlen==0)
|
||
|
+ break;
|
||
|
+ s++;
|
||
|
+ len++;
|
||
|
+ } else if (suffixlen!=0)
|
||
|
+ break;
|
||
|
+ i = scan_xlong((char*)s,&u);
|
||
|
+ if (!i) {
|
||
|
+ len--;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ if (suffixlen+prefixlen<=12 && s[i]=='.') {
|
||
|
+ int j=ip4_scan((char*)s,suffix+suffixlen);
|
||
|
+ if (j) {
|
||
|
+ suffixlen+=4;
|
||
|
+ len+=j;
|
||
|
+ break;
|
||
|
+ } else
|
||
|
+ prefixlen=12-suffixlen; /* make end-of-loop test true */
|
||
|
+ }
|
||
|
+ suffix[suffixlen++] = (u >> 8);
|
||
|
+ suffix[suffixlen++] = (u & 255);
|
||
|
+ s += i; len += i;
|
||
|
+ if (prefixlen+suffixlen==16)
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ for (i=0; i<suffixlen; i++)
|
||
|
+ ip[16-suffixlen+i] = suffix[i];
|
||
|
+ return len;
|
||
|
+}
|
||
|
diff --git a/scan_xlong.c b/scan_xlong.c
|
||
|
new file mode 100644
|
||
|
index 0000000..6e46d74
|
||
|
--- /dev/null
|
||
|
+++ b/scan_xlong.c
|
||
|
@@ -0,0 +1,23 @@
|
||
|
+#include "scan.h"
|
||
|
+
|
||
|
+static int fromhex(unsigned char c) {
|
||
|
+ if (c>='0' && c<='9')
|
||
|
+ return c-'0';
|
||
|
+ else if (c>='A' && c<='F')
|
||
|
+ return c-'A'+10;
|
||
|
+ else if (c>='a' && c<='f')
|
||
|
+ return c-'a'+10;
|
||
|
+ return -1;
|
||
|
+}
|
||
|
+
|
||
|
+unsigned int scan_xlong(char *src,unsigned long *dest) {
|
||
|
+ register const char *tmp=src;
|
||
|
+ register int l=0;
|
||
|
+ register unsigned char c;
|
||
|
+ while ((c=fromhex(*tmp))<16) {
|
||
|
+ l=(l<<4)+c;
|
||
|
+ ++tmp;
|
||
|
+ }
|
||
|
+ *dest=l;
|
||
|
+ return tmp-src;
|
||
|
+}
|
||
|
diff --git a/socket.h b/socket.h
|
||
|
index 80fb260..4fba762 100644
|
||
|
--- a/socket.h
|
||
|
+++ b/socket.h
|
||
|
@@ -2,21 +2,52 @@
|
||
|
#define SOCKET_H
|
||
|
|
||
|
#include "uint16.h"
|
||
|
+#include "uint32.h"
|
||
|
|
||
|
extern int socket_tcp(void);
|
||
|
extern int socket_udp(void);
|
||
|
+extern int socket_tcp6(void);
|
||
|
+extern int socket_udp6(void);
|
||
|
|
||
|
-extern int socket_connect4(int,char *,uint16);
|
||
|
+extern int socket_connect4(int,const char *,uint16);
|
||
|
+extern int socket_connect6(int s,const char *ip,uint16 port,uint32 scope_id);
|
||
|
extern int socket_connected(int);
|
||
|
-extern int socket_bind4(int,char *,uint16);
|
||
|
-extern int socket_bind4_reuse(int,char *,uint16);
|
||
|
+extern int socket_bind4(int,const char *,uint16);
|
||
|
+extern int socket_bind4_reuse(int,const char *,uint16);
|
||
|
+extern int socket_bind6(int s,const char *ip,uint16 port,uint32 scope_id);
|
||
|
+extern int socket_bind6_reuse(int s,const char *ip,uint16 port,uint32 scope_id);
|
||
|
extern int socket_listen(int,int);
|
||
|
extern int socket_accept4(int,char *,uint16 *);
|
||
|
+extern int socket_accept6(int s,char *ip,uint16 *port,uint32 *scope_id);
|
||
|
extern int socket_recv4(int,char *,int,char *,uint16 *);
|
||
|
-extern int socket_send4(int,char *,int,char *,uint16);
|
||
|
+extern int socket_send4(int,const char *,int,const char *,uint16);
|
||
|
+extern int socket_recv6(int s,char *buf,unsigned int len,char *ip,uint16 *port,uint32 *scope_id);
|
||
|
+extern int socket_send6(int s,const char *buf,unsigned int len,const char *ip,uint16 port,uint32 scope_id);
|
||
|
extern int socket_local4(int,char *,uint16 *);
|
||
|
extern int socket_remote4(int,char *,uint16 *);
|
||
|
+extern int socket_local6(int s,char *ip,uint16 *port,uint32 *scope_id);
|
||
|
+extern int socket_remote6(int s,char *ip,uint16 *port,uint32 *scope_id);
|
||
|
+
|
||
|
+/* enable sending udp packets to the broadcast address */
|
||
|
+extern int socket_broadcast(int);
|
||
|
+/* join a multicast group on the given interface */
|
||
|
+extern int socket_mcjoin4(int,char *,char *);
|
||
|
+extern int socket_mcjoin6(int,char *,int);
|
||
|
+/* leave a multicast group on the given interface */
|
||
|
+extern int socket_mcleave4(int,char *);
|
||
|
+extern int socket_mcleave6(int,char *);
|
||
|
+/* set multicast TTL/hop count for outgoing packets */
|
||
|
+extern int socket_mcttl4(int,char);
|
||
|
+extern int socket_mcttl6(int,char);
|
||
|
+/* enable multicast loopback */
|
||
|
+extern int socket_mcloop4(int,char);
|
||
|
+extern int socket_mcloop6(int,char);
|
||
|
+
|
||
|
+extern const char* socket_getifname(uint32 interface);
|
||
|
+extern uint32 socket_getifidx(const char *ifname);
|
||
|
|
||
|
extern void socket_tryreservein(int,int);
|
||
|
|
||
|
+extern int noipv6;
|
||
|
+
|
||
|
#endif
|
||
|
diff --git a/socket_accept6.c b/socket_accept6.c
|
||
|
new file mode 100644
|
||
|
index 0000000..a8a9a07
|
||
|
--- /dev/null
|
||
|
+++ b/socket_accept6.c
|
||
|
@@ -0,0 +1,44 @@
|
||
|
+#include <sys/types.h>
|
||
|
+#include <sys/param.h>
|
||
|
+#include <sys/socket.h>
|
||
|
+#include <netinet/in.h>
|
||
|
+#include "byte.h"
|
||
|
+#include "socket.h"
|
||
|
+#include "ip6.h"
|
||
|
+#include "haveip6.h"
|
||
|
+#include "error.h"
|
||
|
+
|
||
|
+int socket_accept6(int s,char ip[16],uint16 *port,uint32 *scope_id)
|
||
|
+{
|
||
|
+#ifdef LIBC_HAS_IP6
|
||
|
+ struct sockaddr_in6 sa;
|
||
|
+#else
|
||
|
+ struct sockaddr_in sa;
|
||
|
+#endif
|
||
|
+ unsigned int dummy = sizeof sa;
|
||
|
+ int fd;
|
||
|
+
|
||
|
+ fd = accept(s,(struct sockaddr *) &sa,&dummy);
|
||
|
+ if (fd == -1) return -1;
|
||
|
+
|
||
|
+#ifdef LIBC_HAS_IP6
|
||
|
+ if (sa.sin6_family==AF_INET) {
|
||
|
+ struct sockaddr_in *sa4=(struct sockaddr_in*)&sa;
|
||
|
+ byte_copy(ip,12,V4mappedprefix);
|
||
|
+ byte_copy(ip+12,4,(char *) &sa4->sin_addr);
|
||
|
+ uint16_unpack_big((char *) &sa4->sin_port,port);
|
||
|
+ return fd;
|
||
|
+ }
|
||
|
+ byte_copy(ip,16,(char *) &sa.sin6_addr);
|
||
|
+ uint16_unpack_big((char *) &sa.sin6_port,port);
|
||
|
+ if (scope_id) *scope_id=sa.sin6_scope_id;
|
||
|
+
|
||
|
+ return fd;
|
||
|
+#else
|
||
|
+ byte_copy(ip,12,V4mappedprefix);
|
||
|
+ byte_copy(ip+12,4,(char *) &sa.sin_addr);
|
||
|
+ uint16_unpack_big((char *) &sa.sin_port,port);
|
||
|
+ if (scope_id) *scope_id=0;
|
||
|
+ return fd;
|
||
|
+#endif
|
||
|
+}
|
||
|
diff --git a/socket_bind.c b/socket_bind.c
|
||
|
index 20830a4..067b4a8 100644
|
||
|
--- a/socket_bind.c
|
||
|
+++ b/socket_bind.c
|
||
|
@@ -5,7 +5,7 @@
|
||
|
#include "byte.h"
|
||
|
#include "socket.h"
|
||
|
|
||
|
-int socket_bind4(int s,char ip[4],uint16 port)
|
||
|
+int socket_bind4(int s,const char ip[4],uint16 port)
|
||
|
{
|
||
|
struct sockaddr_in sa;
|
||
|
|
||
|
@@ -17,7 +17,7 @@ int socket_bind4(int s,char ip[4],uint16 port)
|
||
|
return bind(s,(struct sockaddr *) &sa,sizeof sa);
|
||
|
}
|
||
|
|
||
|
-int socket_bind4_reuse(int s,char ip[4],uint16 port)
|
||
|
+int socket_bind4_reuse(int s,const char ip[4],uint16 port)
|
||
|
{
|
||
|
int opt = 1;
|
||
|
setsockopt(s,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof opt);
|
||
|
diff --git a/socket_bind6.c b/socket_bind6.c
|
||
|
new file mode 100644
|
||
|
index 0000000..8a5a7cd
|
||
|
--- /dev/null
|
||
|
+++ b/socket_bind6.c
|
||
|
@@ -0,0 +1,45 @@
|
||
|
+#include <sys/types.h>
|
||
|
+#include <sys/param.h>
|
||
|
+#include <sys/socket.h>
|
||
|
+#include <netinet/in.h>
|
||
|
+#include "byte.h"
|
||
|
+#include "socket.h"
|
||
|
+#include "ip6.h"
|
||
|
+#include "haveip6.h"
|
||
|
+#include "error.h"
|
||
|
+
|
||
|
+int socket_bind6(int s,const char ip[16],uint16 port,uint32 scope_id)
|
||
|
+{
|
||
|
+#ifdef LIBC_HAS_IP6
|
||
|
+ struct sockaddr_in6 sa;
|
||
|
+
|
||
|
+ if (noipv6) {
|
||
|
+#endif
|
||
|
+ int i;
|
||
|
+ for (i=0; i<16; i++)
|
||
|
+ if (ip[i]!=0) break;
|
||
|
+ if (i==16 || ip6_isv4mapped(ip))
|
||
|
+ return socket_bind4(s,ip+12,port);
|
||
|
+#ifdef LIBC_HAS_IP6
|
||
|
+ }
|
||
|
+ byte_zero(&sa,sizeof sa);
|
||
|
+ sa.sin6_family = AF_INET6;
|
||
|
+ uint16_pack_big((char *) &sa.sin6_port,port);
|
||
|
+/* implicit: sa.sin6_flowinfo = 0; */
|
||
|
+ byte_copy((char *) &sa.sin6_addr,16,ip);
|
||
|
+ sa.sin6_scope_id=scope_id;
|
||
|
+
|
||
|
+ return bind(s,(struct sockaddr *) &sa,sizeof sa);
|
||
|
+#else
|
||
|
+ errno=error_proto;
|
||
|
+ return -1;
|
||
|
+#endif
|
||
|
+}
|
||
|
+
|
||
|
+int socket_bind6_reuse(int s,const char ip[16],uint16 port,uint32 scope_id)
|
||
|
+{
|
||
|
+ int opt = 1;
|
||
|
+ setsockopt(s,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof opt);
|
||
|
+ return socket_bind6(s,ip,port,scope_id);
|
||
|
+}
|
||
|
+
|
||
|
diff --git a/socket_conn.c b/socket_conn.c
|
||
|
index 35adac4..dcc93ac 100644
|
||
|
--- a/socket_conn.c
|
||
|
+++ b/socket_conn.c
|
||
|
@@ -6,7 +6,7 @@
|
||
|
#include "byte.h"
|
||
|
#include "socket.h"
|
||
|
|
||
|
-int socket_connect4(int s,char ip[4],uint16 port)
|
||
|
+int socket_connect4(int s,const char ip[4],uint16 port)
|
||
|
{
|
||
|
struct sockaddr_in sa;
|
||
|
|
||
|
diff --git a/socket_conn6.c b/socket_conn6.c
|
||
|
new file mode 100644
|
||
|
index 0000000..0ad886d
|
||
|
--- /dev/null
|
||
|
+++ b/socket_conn6.c
|
||
|
@@ -0,0 +1,38 @@
|
||
|
+#include <sys/param.h>
|
||
|
+#include <sys/types.h>
|
||
|
+#include <sys/socket.h>
|
||
|
+#include <netinet/in.h>
|
||
|
+#include <errno.h>
|
||
|
+#include "byte.h"
|
||
|
+#include "socket.h"
|
||
|
+#include "ip6.h"
|
||
|
+#include "haveip6.h"
|
||
|
+#include "uint32.h"
|
||
|
+#include "ip4.h"
|
||
|
+
|
||
|
+int socket_connect6(int s,const char ip[16],uint16 port,uint32 scope_id)
|
||
|
+{
|
||
|
+#ifdef LIBC_HAS_IP6
|
||
|
+ struct sockaddr_in6 sa;
|
||
|
+
|
||
|
+ if (noipv6) {
|
||
|
+#endif
|
||
|
+ if (ip6_isv4mapped(ip))
|
||
|
+ return socket_connect4(s,ip+12,port);
|
||
|
+ if (byte_equal(ip,16,V6loopback))
|
||
|
+ return socket_connect4(s,ip4loopback,port);
|
||
|
+#ifdef LIBC_HAS_IP6
|
||
|
+ }
|
||
|
+ byte_zero(&sa,sizeof sa);
|
||
|
+ sa.sin6_family = PF_INET6;
|
||
|
+ uint16_pack_big((char *) &sa.sin6_port,port);
|
||
|
+ sa.sin6_flowinfo = 0;
|
||
|
+ sa.sin6_scope_id = scope_id;
|
||
|
+ byte_copy((char *) &sa.sin6_addr,16,ip);
|
||
|
+
|
||
|
+ return connect(s,(struct sockaddr *) &sa,sizeof sa);
|
||
|
+#else
|
||
|
+ errno=EPROTONOSUPPORT;
|
||
|
+ return -1;
|
||
|
+#endif
|
||
|
+}
|
||
|
diff --git a/socket_getifidx.c b/socket_getifidx.c
|
||
|
new file mode 100644
|
||
|
index 0000000..452d6d7
|
||
|
--- /dev/null
|
||
|
+++ b/socket_getifidx.c
|
||
|
@@ -0,0 +1,8 @@
|
||
|
+#include <sys/types.h>
|
||
|
+#include <sys/socket.h>
|
||
|
+#include <net/if.h>
|
||
|
+#include "socket.h"
|
||
|
+
|
||
|
+uint32 socket_getifidx(const char* ifname) {
|
||
|
+ return if_nametoindex(ifname);
|
||
|
+}
|
||
|
diff --git a/socket_getifname.c b/socket_getifname.c
|
||
|
new file mode 100644
|
||
|
index 0000000..77edff9
|
||
|
--- /dev/null
|
||
|
+++ b/socket_getifname.c
|
||
|
@@ -0,0 +1,14 @@
|
||
|
+#include <sys/types.h>
|
||
|
+#include <sys/socket.h>
|
||
|
+#include <net/if.h>
|
||
|
+#include "socket.h"
|
||
|
+
|
||
|
+static char ifname[IFNAMSIZ];
|
||
|
+
|
||
|
+const char* socket_getifname(uint32 interface) {
|
||
|
+ char *tmp=if_indextoname(interface,ifname);
|
||
|
+ if (tmp)
|
||
|
+ return tmp;
|
||
|
+ else
|
||
|
+ return "[unknown]";
|
||
|
+}
|
||
|
diff --git a/socket_ip4loopback.c b/socket_ip4loopback.c
|
||
|
new file mode 100644
|
||
|
index 0000000..1bbbe95
|
||
|
--- /dev/null
|
||
|
+++ b/socket_ip4loopback.c
|
||
|
@@ -0,0 +1,2 @@
|
||
|
+
|
||
|
+const char ip4loopback[4] = {127,0,0,1};
|
||
|
diff --git a/socket_local6.c b/socket_local6.c
|
||
|
new file mode 100644
|
||
|
index 0000000..23427c3
|
||
|
--- /dev/null
|
||
|
+++ b/socket_local6.c
|
||
|
@@ -0,0 +1,39 @@
|
||
|
+#include <sys/types.h>
|
||
|
+#include <sys/param.h>
|
||
|
+#include <sys/socket.h>
|
||
|
+#include <netinet/in.h>
|
||
|
+#include "byte.h"
|
||
|
+#include "socket.h"
|
||
|
+#include "ip6.h"
|
||
|
+#include "haveip6.h"
|
||
|
+#include "error.h"
|
||
|
+
|
||
|
+int socket_local6(int s,char ip[16],uint16 *port,uint32 *scope_id)
|
||
|
+{
|
||
|
+#ifdef LIBC_HAS_IP6
|
||
|
+ struct sockaddr_in6 sa;
|
||
|
+#else
|
||
|
+ struct sockaddr_in sa;
|
||
|
+#endif
|
||
|
+ unsigned int dummy = sizeof sa;
|
||
|
+
|
||
|
+ if (getsockname(s,(struct sockaddr *) &sa,&dummy) == -1) return -1;
|
||
|
+#ifdef LIBC_HAS_IP6
|
||
|
+ if (sa.sin6_family==AF_INET) {
|
||
|
+ struct sockaddr_in *sa4=(struct sockaddr_in*)&sa;
|
||
|
+ byte_copy(ip,12,V4mappedprefix);
|
||
|
+ byte_copy(ip+12,4,(char *) &sa4->sin_addr);
|
||
|
+ uint16_unpack_big((char *) &sa4->sin_port,port);
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+ byte_copy(ip,16,(char *) &sa.sin6_addr);
|
||
|
+ uint16_unpack_big((char *) &sa.sin6_port,port);
|
||
|
+ if (scope_id) *scope_id=sa.sin6_scope_id;
|
||
|
+#else
|
||
|
+ byte_copy(ip,12,V4mappedprefix);
|
||
|
+ byte_copy(ip+12,4,(char *) &sa.sin_addr);
|
||
|
+ uint16_unpack_big((char *) &sa.sin_port,port);
|
||
|
+ if (scope_id) *scope_id=0;
|
||
|
+#endif
|
||
|
+ return 0;
|
||
|
+}
|
||
|
diff --git a/socket_recv6.c b/socket_recv6.c
|
||
|
new file mode 100644
|
||
|
index 0000000..a86ca96
|
||
|
--- /dev/null
|
||
|
+++ b/socket_recv6.c
|
||
|
@@ -0,0 +1,44 @@
|
||
|
+#include <sys/types.h>
|
||
|
+#include <sys/param.h>
|
||
|
+#include <sys/socket.h>
|
||
|
+#include <netinet/in.h>
|
||
|
+#include "byte.h"
|
||
|
+#include "socket.h"
|
||
|
+#include "ip6.h"
|
||
|
+#include "haveip6.h"
|
||
|
+#include "error.h"
|
||
|
+
|
||
|
+int socket_recv6(int s,char *buf,unsigned int len,char ip[16],uint16 *port,uint32 *scope_id)
|
||
|
+{
|
||
|
+#ifdef LIBC_HAS_IP6
|
||
|
+ struct sockaddr_in6 sa;
|
||
|
+#else
|
||
|
+ struct sockaddr_in sa;
|
||
|
+#endif
|
||
|
+ unsigned int dummy = sizeof sa;
|
||
|
+ int r;
|
||
|
+
|
||
|
+ byte_zero(&sa,dummy);
|
||
|
+ r = recvfrom(s,buf,len,0,(struct sockaddr *) &sa,&dummy);
|
||
|
+ if (r == -1) return -1;
|
||
|
+
|
||
|
+#ifdef LIBC_HAS_IP6
|
||
|
+ if (noipv6) {
|
||
|
+ struct sockaddr_in *sa4=(struct sockaddr_in *)&sa;
|
||
|
+ byte_copy(ip,12,V4mappedprefix);
|
||
|
+ byte_copy(ip+12,4,(char *) &sa4->sin_addr);
|
||
|
+ uint16_unpack_big((char *) &sa4->sin_port,port);
|
||
|
+ return r;
|
||
|
+ }
|
||
|
+ byte_copy(ip,16,(char *) &sa.sin6_addr);
|
||
|
+ uint16_unpack_big((char *) &sa.sin6_port,port);
|
||
|
+ if (scope_id) *scope_id=sa.sin6_scope_id;
|
||
|
+#else
|
||
|
+ byte_copy(ip,12,(char *)V4mappedprefix);
|
||
|
+ byte_copy(ip+12,4,(char *) &sa.sin_addr);
|
||
|
+ uint16_unpack_big((char *) &sa.sin_port,port);
|
||
|
+ if (scope_id) *scope_id=0;
|
||
|
+#endif
|
||
|
+
|
||
|
+ return r;
|
||
|
+}
|
||
|
diff --git a/socket_remote6.c b/socket_remote6.c
|
||
|
new file mode 100644
|
||
|
index 0000000..e60a539
|
||
|
--- /dev/null
|
||
|
+++ b/socket_remote6.c
|
||
|
@@ -0,0 +1,39 @@
|
||
|
+#include <sys/types.h>
|
||
|
+#include <sys/param.h>
|
||
|
+#include <sys/socket.h>
|
||
|
+#include <netinet/in.h>
|
||
|
+#include "byte.h"
|
||
|
+#include "socket.h"
|
||
|
+#include "ip6.h"
|
||
|
+#include "haveip6.h"
|
||
|
+#include "error.h"
|
||
|
+
|
||
|
+int socket_remote6(int s,char ip[16],uint16 *port,uint32 *scope_id)
|
||
|
+{
|
||
|
+#ifdef LIBC_HAS_IP6
|
||
|
+ struct sockaddr_in6 sa;
|
||
|
+#else
|
||
|
+ struct sockaddr_in sa;
|
||
|
+#endif
|
||
|
+ unsigned int dummy = sizeof sa;
|
||
|
+
|
||
|
+ if (getpeername(s,(struct sockaddr *) &sa,&dummy) == -1) return -1;
|
||
|
+#ifdef LIBC_HAS_IP6
|
||
|
+ if (sa.sin6_family==AF_INET) {
|
||
|
+ struct sockaddr_in *sa4=(struct sockaddr_in*)&sa;
|
||
|
+ byte_copy(ip,12,V4mappedprefix);
|
||
|
+ byte_copy(ip+12,4,(char *) &sa4->sin_addr);
|
||
|
+ uint16_unpack_big((char *) &sa4->sin_port,port);
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+ byte_copy(ip,16,(char *) &sa.sin6_addr);
|
||
|
+ uint16_unpack_big((char *) &sa.sin6_port,port);
|
||
|
+ if (scope_id) *scope_id=sa.sin6_scope_id;
|
||
|
+#else
|
||
|
+ byte_copy(ip,12,V4mappedprefix);
|
||
|
+ byte_copy(ip+12,4,(char *) &sa.sin_addr);
|
||
|
+ uint16_unpack_big((char *) &sa.sin_port,port);
|
||
|
+ if (scope_id) *scope_id=0;
|
||
|
+#endif
|
||
|
+ return 0;
|
||
|
+}
|
||
|
diff --git a/socket_send6.c b/socket_send6.c
|
||
|
new file mode 100644
|
||
|
index 0000000..4b2d1e8
|
||
|
--- /dev/null
|
||
|
+++ b/socket_send6.c
|
||
|
@@ -0,0 +1,40 @@
|
||
|
+#include <sys/types.h>
|
||
|
+#include <sys/param.h>
|
||
|
+#include <sys/socket.h>
|
||
|
+#include <netinet/in.h>
|
||
|
+#include "byte.h"
|
||
|
+#include "socket.h"
|
||
|
+#include "ip4.h"
|
||
|
+#include "ip6.h"
|
||
|
+#include "haveip6.h"
|
||
|
+#include "error.h"
|
||
|
+
|
||
|
+int socket_send6(int s,const char *buf,unsigned int len,const char ip[16],uint16 port,uint32 scope_id)
|
||
|
+{
|
||
|
+#ifdef LIBC_HAS_IP6
|
||
|
+ struct sockaddr_in6 sa;
|
||
|
+#else
|
||
|
+ struct sockaddr_in sa;
|
||
|
+#endif
|
||
|
+
|
||
|
+ byte_zero(&sa,sizeof sa);
|
||
|
+#ifdef LIBC_HAS_IP6
|
||
|
+ if (noipv6) {
|
||
|
+#endif
|
||
|
+ if (ip6_isv4mapped(ip))
|
||
|
+ return socket_send4(s,buf,len,ip+12,port);
|
||
|
+ if (byte_equal(ip,16,V6loopback))
|
||
|
+ return socket_send4(s,buf,len,ip4loopback,port);
|
||
|
+#ifdef LIBC_HAS_IP6
|
||
|
+ errno=error_proto;
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ sa.sin6_family = AF_INET6;
|
||
|
+ uint16_pack_big((char *) &sa.sin6_port,port);
|
||
|
+ byte_copy((char *) &sa.sin6_addr,16,ip);
|
||
|
+ return sendto(s,buf,len,0,(struct sockaddr *) &sa,sizeof sa);
|
||
|
+#else
|
||
|
+ errno=error_proto;
|
||
|
+ return -1;
|
||
|
+#endif
|
||
|
+}
|
||
|
diff --git a/socket_tcp6.c b/socket_tcp6.c
|
||
|
new file mode 100644
|
||
|
index 0000000..74099e2
|
||
|
--- /dev/null
|
||
|
+++ b/socket_tcp6.c
|
||
|
@@ -0,0 +1,44 @@
|
||
|
+#include <sys/types.h>
|
||
|
+#include <sys/param.h>
|
||
|
+#include <sys/socket.h>
|
||
|
+#include <netinet/in.h>
|
||
|
+#include <errno.h>
|
||
|
+#include "ndelay.h"
|
||
|
+#include "socket.h"
|
||
|
+#include "haveip6.h"
|
||
|
+#include "error.h"
|
||
|
+
|
||
|
+#ifdef LIBC_HAS_IP6
|
||
|
+int noipv6=0;
|
||
|
+#else
|
||
|
+int noipv6=1;
|
||
|
+#endif
|
||
|
+
|
||
|
+int socket_tcp6(void)
|
||
|
+{
|
||
|
+#ifdef LIBC_HAS_IP6
|
||
|
+ int s;
|
||
|
+
|
||
|
+ if (noipv6) goto compat;
|
||
|
+ s = socket(PF_INET6,SOCK_STREAM,0);
|
||
|
+ if (s == -1) {
|
||
|
+ if (errno == EINVAL || errno == EAFNOSUPPORT) {
|
||
|
+compat:
|
||
|
+ s=socket(AF_INET,SOCK_STREAM,0);
|
||
|
+ noipv6=1;
|
||
|
+ if (s==-1) return -1;
|
||
|
+ } else
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ if (ndelay_on(s) == -1) { close(s); return -1; }
|
||
|
+#ifdef IPV6_V6ONLY
|
||
|
+ {
|
||
|
+ int zero=0;
|
||
|
+ setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,(void*)&zero,sizeof(zero));
|
||
|
+ }
|
||
|
+#endif
|
||
|
+ return s;
|
||
|
+#else
|
||
|
+ return socket_tcp();
|
||
|
+#endif
|
||
|
+}
|
||
|
diff --git a/socket_udp6.c b/socket_udp6.c
|
||
|
new file mode 100644
|
||
|
index 0000000..3769b1d
|
||
|
--- /dev/null
|
||
|
+++ b/socket_udp6.c
|
||
|
@@ -0,0 +1,38 @@
|
||
|
+#include <sys/types.h>
|
||
|
+#include <sys/socket.h>
|
||
|
+#include <netinet/in.h>
|
||
|
+#include <errno.h>
|
||
|
+#include "haveip6.h"
|
||
|
+#include "socket.h"
|
||
|
+
|
||
|
+#ifndef EAFNOSUPPORT
|
||
|
+#define EAFNOSUPPORT EINVAL
|
||
|
+#endif
|
||
|
+
|
||
|
+int socket_udp6(void)
|
||
|
+{
|
||
|
+#ifdef LIBC_HAS_IP6
|
||
|
+ int s;
|
||
|
+
|
||
|
+ if (noipv6) goto compat;
|
||
|
+ s = socket(PF_INET6,SOCK_DGRAM,0);
|
||
|
+ if (s == -1) {
|
||
|
+ if (errno == EINVAL || errno == EAFNOSUPPORT) {
|
||
|
+compat:
|
||
|
+ s=socket(AF_INET,SOCK_DGRAM,0);
|
||
|
+ noipv6=1;
|
||
|
+ if (s==-1) return -1;
|
||
|
+ } else
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+#ifdef IPV6_V6ONLY
|
||
|
+ {
|
||
|
+ int zero=0;
|
||
|
+ setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,(void*)&zero,sizeof(zero));
|
||
|
+ }
|
||
|
+#endif
|
||
|
+ return s;
|
||
|
+#else
|
||
|
+ return socket_udp();
|
||
|
+#endif
|
||
|
+}
|
||
|
diff --git a/socket_v4mappedprefix.c b/socket_v4mappedprefix.c
|
||
|
new file mode 100644
|
||
|
index 0000000..dbed824
|
||
|
--- /dev/null
|
||
|
+++ b/socket_v4mappedprefix.c
|
||
|
@@ -0,0 +1,2 @@
|
||
|
+
|
||
|
+const unsigned char V4mappedprefix[12]={0,0,0,0,0,0,0,0,0,0,0xff,0xff};
|
||
|
diff --git a/socket_v6any.c b/socket_v6any.c
|
||
|
new file mode 100644
|
||
|
index 0000000..c6d0cbb
|
||
|
--- /dev/null
|
||
|
+++ b/socket_v6any.c
|
||
|
@@ -0,0 +1,2 @@
|
||
|
+
|
||
|
+const unsigned char V6any[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||
|
diff --git a/socket_v6loopback.c b/socket_v6loopback.c
|
||
|
new file mode 100644
|
||
|
index 0000000..b81ee65
|
||
|
--- /dev/null
|
||
|
+++ b/socket_v6loopback.c
|
||
|
@@ -0,0 +1,2 @@
|
||
|
+
|
||
|
+const unsigned char V6loopback[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
|
||
|
diff --git a/str.h b/str.h
|
||
|
index ab4aedd..a2a4b75 100644
|
||
|
--- a/str.h
|
||
|
+++ b/str.h
|
||
|
@@ -1,13 +1,13 @@
|
||
|
#ifndef STR_H
|
||
|
#define STR_H
|
||
|
|
||
|
-extern unsigned int str_copy(char *,char *);
|
||
|
-extern int str_diff(char *,char *);
|
||
|
-extern int str_diffn(char *,char *,unsigned int);
|
||
|
-extern unsigned int str_len(char *);
|
||
|
-extern unsigned int str_chr(char *,int);
|
||
|
-extern unsigned int str_rchr(char *,int);
|
||
|
-extern int str_start(char *,char *);
|
||
|
+extern unsigned int str_copy(char *,const char *);
|
||
|
+extern int str_diff(const char *,const char *);
|
||
|
+extern int str_diffn(const char *,const char *,unsigned int);
|
||
|
+extern unsigned int str_len(const char *);
|
||
|
+extern unsigned int str_chr(const char *,int);
|
||
|
+extern unsigned int str_rchr(const char *,int);
|
||
|
+extern int str_start(const char *,const char *);
|
||
|
|
||
|
#define str_equal(s,t) (!str_diff((s),(t)))
|
||
|
|
||
|
diff --git a/str_chr.c b/str_chr.c
|
||
|
index 886d6b6..042dfa2 100644
|
||
|
--- a/str_chr.c
|
||
|
+++ b/str_chr.c
|
||
|
@@ -1,9 +1,9 @@
|
||
|
#include "str.h"
|
||
|
|
||
|
-unsigned int str_chr(register char *s,int c)
|
||
|
+unsigned int str_chr(register const char *s,int c)
|
||
|
{
|
||
|
register char ch;
|
||
|
- register char *t;
|
||
|
+ register const char *t;
|
||
|
|
||
|
ch = c;
|
||
|
t = s;
|
||
|
diff --git a/str_diff.c b/str_diff.c
|
||
|
index 037dcdf..071e7f5 100644
|
||
|
--- a/str_diff.c
|
||
|
+++ b/str_diff.c
|
||
|
@@ -1,6 +1,6 @@
|
||
|
#include "str.h"
|
||
|
|
||
|
-int str_diff(register char *s,register char *t)
|
||
|
+int str_diff(register const char *s,register const char *t)
|
||
|
{
|
||
|
register char x;
|
||
|
|
||
|
diff --git a/str_len.c b/str_len.c
|
||
|
index 5bd3f62..8411ebf 100644
|
||
|
--- a/str_len.c
|
||
|
+++ b/str_len.c
|
||
|
@@ -1,8 +1,8 @@
|
||
|
#include "str.h"
|
||
|
|
||
|
-unsigned int str_len(char *s)
|
||
|
+unsigned int str_len(const char *s)
|
||
|
{
|
||
|
- register char *t;
|
||
|
+ register const char *t;
|
||
|
|
||
|
t = s;
|
||
|
for (;;) {
|
||
|
diff --git a/str_start.c b/str_start.c
|
||
|
index 43430bb..757189d 100644
|
||
|
--- a/str_start.c
|
||
|
+++ b/str_start.c
|
||
|
@@ -1,6 +1,6 @@
|
||
|
#include "str.h"
|
||
|
|
||
|
-int str_start(register char *s,register char *t)
|
||
|
+int str_start(register const char *s,register const char *t)
|
||
|
{
|
||
|
register char x;
|
||
|
|
||
|
diff --git a/stralloc.h b/stralloc.h
|
||
|
index 7866812..cc17048 100644
|
||
|
--- a/stralloc.h
|
||
|
+++ b/stralloc.h
|
||
|
@@ -9,18 +9,20 @@ extern int stralloc_ready(stralloc *,unsigned int);
|
||
|
extern int stralloc_readyplus(stralloc *,unsigned int);
|
||
|
extern int stralloc_copy(stralloc *,stralloc *);
|
||
|
extern int stralloc_cat(stralloc *,stralloc *);
|
||
|
-extern int stralloc_copys(stralloc *,char *);
|
||
|
-extern int stralloc_cats(stralloc *,char *);
|
||
|
-extern int stralloc_copyb(stralloc *,char *,unsigned int);
|
||
|
-extern int stralloc_catb(stralloc *,char *,unsigned int);
|
||
|
+extern int stralloc_copys(stralloc *,const char *);
|
||
|
+extern int stralloc_cats(stralloc *,const char *);
|
||
|
+extern int stralloc_copyb(stralloc *,const char *,unsigned int);
|
||
|
+extern int stralloc_catb(stralloc *,const char *,unsigned int);
|
||
|
extern int stralloc_append(stralloc *,char *); /* beware: this takes a pointer to 1 char */
|
||
|
-extern int stralloc_starts(stralloc *,char *);
|
||
|
+extern int stralloc_starts(stralloc *,const char *);
|
||
|
|
||
|
#define stralloc_0(sa) stralloc_append(sa,"")
|
||
|
|
||
|
extern int stralloc_catulong0(stralloc *,unsigned long,unsigned int);
|
||
|
extern int stralloc_catlong0(stralloc *,long,unsigned int);
|
||
|
|
||
|
+extern void stralloc_free(stralloc *);
|
||
|
+
|
||
|
#define stralloc_catlong(sa,l) (stralloc_catlong0((sa),(l),0))
|
||
|
#define stralloc_catuint0(sa,i,n) (stralloc_catulong0((sa),(i),(n)))
|
||
|
#define stralloc_catint0(sa,i,n) (stralloc_catlong0((sa),(i),(n)))
|
||
|
diff --git a/stralloc_catb.c b/stralloc_catb.c
|
||
|
index b739bed..b606e32 100644
|
||
|
--- a/stralloc_catb.c
|
||
|
+++ b/stralloc_catb.c
|
||
|
@@ -1,7 +1,7 @@
|
||
|
#include "stralloc.h"
|
||
|
#include "byte.h"
|
||
|
|
||
|
-int stralloc_catb(stralloc *sa,char *s,unsigned int n)
|
||
|
+int stralloc_catb(stralloc *sa,const char *s,unsigned int n)
|
||
|
{
|
||
|
if (!sa->s) return stralloc_copyb(sa,s,n);
|
||
|
if (!stralloc_readyplus(sa,n + 1)) return 0;
|
||
|
diff --git a/stralloc_cats.c b/stralloc_cats.c
|
||
|
index 8b11e94..92cb66e 100644
|
||
|
--- a/stralloc_cats.c
|
||
|
+++ b/stralloc_cats.c
|
||
|
@@ -2,7 +2,7 @@
|
||
|
#include "str.h"
|
||
|
#include "stralloc.h"
|
||
|
|
||
|
-int stralloc_cats(stralloc *sa,char *s)
|
||
|
+int stralloc_cats(stralloc *sa,const char *s)
|
||
|
{
|
||
|
return stralloc_catb(sa,s,str_len(s));
|
||
|
}
|
||
|
diff --git a/stralloc_opyb.c b/stralloc_opyb.c
|
||
|
index 46b99fc..593029d 100644
|
||
|
--- a/stralloc_opyb.c
|
||
|
+++ b/stralloc_opyb.c
|
||
|
@@ -1,7 +1,7 @@
|
||
|
#include "stralloc.h"
|
||
|
#include "byte.h"
|
||
|
|
||
|
-int stralloc_copyb(stralloc *sa,char *s,unsigned int n)
|
||
|
+int stralloc_copyb(stralloc *sa,const char *s,unsigned int n)
|
||
|
{
|
||
|
if (!stralloc_ready(sa,n + 1)) return 0;
|
||
|
byte_copy(sa->s,n,s);
|
||
|
diff --git a/stralloc_opys.c b/stralloc_opys.c
|
||
|
index 78594b0..860c7e0 100644
|
||
|
--- a/stralloc_opys.c
|
||
|
+++ b/stralloc_opys.c
|
||
|
@@ -2,7 +2,7 @@
|
||
|
#include "str.h"
|
||
|
#include "stralloc.h"
|
||
|
|
||
|
-int stralloc_copys(stralloc *sa,char *s)
|
||
|
+int stralloc_copys(stralloc *sa,const char *s)
|
||
|
{
|
||
|
return stralloc_copyb(sa,s,str_len(s));
|
||
|
}
|
||
|
diff --git a/tcp-environ.5 b/tcp-environ.5
|
||
|
new file mode 100644
|
||
|
index 0000000..fecad70
|
||
|
--- /dev/null
|
||
|
+++ b/tcp-environ.5
|
||
|
@@ -0,0 +1,66 @@
|
||
|
+.TH tcp-environ 5
|
||
|
+.SH NAME
|
||
|
+tcp-environ \- TCP-related environment variables
|
||
|
+.SH DESCRIPTION
|
||
|
+The following environment variables
|
||
|
+describe a TCP connection.
|
||
|
+They are set up by
|
||
|
+.BR tcp-env ,
|
||
|
+.BR tcpclient ,
|
||
|
+and
|
||
|
+.BR tcpserver .
|
||
|
+Note that
|
||
|
+.BR TCPLOCALHOST ,
|
||
|
+.BR TCPREMOTEHOST ,
|
||
|
+and
|
||
|
+.B TCPREMOTEINFO
|
||
|
+can contain arbitrary characters.
|
||
|
+.TP 5
|
||
|
+PROTO
|
||
|
+The string
|
||
|
+.BR TCP .
|
||
|
+.TP 5
|
||
|
+TCPLOCALHOST
|
||
|
+The domain name of the local host,
|
||
|
+with uppercase letters converted to lowercase.
|
||
|
+If there is no currently available domain name
|
||
|
+for the local IP address,
|
||
|
+.B TCPLOCALHOST
|
||
|
+is not set.
|
||
|
+.TP 5
|
||
|
+TCPLOCALIP
|
||
|
+The IP address of the local host, in dotted-decimal form.
|
||
|
+.TP 5
|
||
|
+TCPLOCALPORT
|
||
|
+The local TCP port number, in decimal.
|
||
|
+.TP 5
|
||
|
+TCPREMOTEHOST
|
||
|
+The domain name of the remote host,
|
||
|
+with uppercase letters converted to lowercase.
|
||
|
+If there is no currently available domain name
|
||
|
+for the remote IP address,
|
||
|
+.B TCPREMOTEHOST
|
||
|
+is not set.
|
||
|
+.TP 5
|
||
|
+TCPREMOTEINFO
|
||
|
+A connection-specific string, perhaps a username,
|
||
|
+supplied by the remote host
|
||
|
+via 931/1413/IDENT/TAP.
|
||
|
+If the remote host did not supply connection information,
|
||
|
+.B TCPREMOTEINFO
|
||
|
+is not set.
|
||
|
+.TP 5
|
||
|
+TCPREMOTEIP
|
||
|
+The IP address of the remote host.
|
||
|
+.TP 5
|
||
|
+TCPREMOTEPORT
|
||
|
+The remote TCP port number.
|
||
|
+.TP 5
|
||
|
+TCPINTERFACE
|
||
|
+The interface name ("eth0") for IPv6 connections using link-local
|
||
|
+addresses.
|
||
|
+.SH "SEE ALSO"
|
||
|
+tcpclient(1),
|
||
|
+tcpserver(1),
|
||
|
+tcp-env(1),
|
||
|
+tcp(4)
|
||
|
diff --git a/tcpcat.1 b/tcpcat.1
|
||
|
new file mode 100644
|
||
|
index 0000000..4c51ed5
|
||
|
--- /dev/null
|
||
|
+++ b/tcpcat.1
|
||
|
@@ -0,0 +1,20 @@
|
||
|
+.TH tcpcat 1
|
||
|
+.SH NAME
|
||
|
+tcpcat \- print data from a TCP port
|
||
|
+.SH SYNTAX
|
||
|
+.B tcpcat
|
||
|
+.I host
|
||
|
+.I port
|
||
|
+.SH DESCRIPTION
|
||
|
+.B tcpcat
|
||
|
+connects to
|
||
|
+.I port
|
||
|
+on
|
||
|
+.I host
|
||
|
+and prints any data it receives.
|
||
|
+
|
||
|
+.B tcpcat
|
||
|
+can be used to transfer binary data.
|
||
|
+It does no conversions.
|
||
|
+.SH "SEE ALSO"
|
||
|
+tcpclient(1)
|
||
|
diff --git a/tcpclient.1 b/tcpclient.1
|
||
|
new file mode 100644
|
||
|
index 0000000..f82f6b3
|
||
|
--- /dev/null
|
||
|
+++ b/tcpclient.1
|
||
|
@@ -0,0 +1,173 @@
|
||
|
+.TH tcpclient 1
|
||
|
+.SH NAME
|
||
|
+tcpclient \- create an outgoing TCP connection
|
||
|
+.SH SYNOPSIS
|
||
|
+.B tcpclient
|
||
|
+[
|
||
|
+.B \-46hHrRdDqQv
|
||
|
+]
|
||
|
+[
|
||
|
+.B \-i\fIlocalip
|
||
|
+]
|
||
|
+[
|
||
|
+.B \-p\fIlocalport
|
||
|
+]
|
||
|
+[
|
||
|
+.B \-T\fItimeoutconn
|
||
|
+]
|
||
|
+[
|
||
|
+.B \-l\fIlocalname
|
||
|
+]
|
||
|
+[
|
||
|
+.B \-t\fItimeoutinfo
|
||
|
+]
|
||
|
+[
|
||
|
+.B \-I\fIinterface
|
||
|
+]
|
||
|
+.I host
|
||
|
+.I port
|
||
|
+.I program
|
||
|
+[
|
||
|
+.I arg ...
|
||
|
+]
|
||
|
+.SH DESCRIPTION
|
||
|
+.B tcpclient
|
||
|
+attempts to connect to a TCP server.
|
||
|
+If it is successful, it runs
|
||
|
+.I program
|
||
|
+with the given arguments,
|
||
|
+with descriptor 6 reading from the network
|
||
|
+and descriptor 7 writing to the network.
|
||
|
+
|
||
|
+The server's address is given by
|
||
|
+.I host
|
||
|
+and
|
||
|
+.IR port .
|
||
|
+.I host
|
||
|
+may be 0, referring to the local machine,
|
||
|
+or a dotted-decimal IP address,
|
||
|
+or a host name;
|
||
|
+if a host has several IP addresses,
|
||
|
+.B tcpclient
|
||
|
+tries each in turn.
|
||
|
+.I port
|
||
|
+may be a numeric port number
|
||
|
+or a port name.
|
||
|
+
|
||
|
+.B tcpclient
|
||
|
+sets up several environment variables,
|
||
|
+as described in
|
||
|
+.B tcp-environ(5).
|
||
|
+.SH OPTIONS
|
||
|
+.TP
|
||
|
+.B \-i\fIlocalip
|
||
|
+Use
|
||
|
+.I localip
|
||
|
+as the IP address for the local side of the connection;
|
||
|
+quit if
|
||
|
+.I localip
|
||
|
+is not available.
|
||
|
+.TP
|
||
|
+.B \-p\fIlocalport
|
||
|
+Use
|
||
|
+.I localport
|
||
|
+as the port number for the local side of the connection;
|
||
|
+quit if
|
||
|
+.I localport
|
||
|
+is not available.
|
||
|
+.TP
|
||
|
+.B \-I\fIinterface
|
||
|
+Use
|
||
|
+.I interface
|
||
|
+as the local network interface. This is only defined for IPv6 sockets
|
||
|
+and needed if you use link-local IPv6 addresses.
|
||
|
+.TP
|
||
|
+.B \-T\fItimeoutconn
|
||
|
+Give up on the
|
||
|
+connection attempt
|
||
|
+after
|
||
|
+.I timeoutconn
|
||
|
+seconds. Default: 60.
|
||
|
+This timeout applies to each IP address tried.
|
||
|
+.TP
|
||
|
+.B \-d
|
||
|
+(Default.)
|
||
|
+Delay sending data for a fraction of a second whenever the
|
||
|
+remote host is responding slowly,
|
||
|
+to make better use of the network.
|
||
|
+.TP
|
||
|
+.B \-D
|
||
|
+Never delay sending data;
|
||
|
+enable TCP_NODELAY.
|
||
|
+This is appropriate for interactive connections.
|
||
|
+.TP
|
||
|
+.B \-q
|
||
|
+Quiet.
|
||
|
+Do not print any messages.
|
||
|
+.TP
|
||
|
+.B \-Q
|
||
|
+(Default.)
|
||
|
+Print error messages.
|
||
|
+.TP
|
||
|
+.B \-v
|
||
|
+Verbose.
|
||
|
+Print all available messages.
|
||
|
+.SH "DATA-GATHERING OPTIONS"
|
||
|
+.TP
|
||
|
+.B \-h
|
||
|
+(Default.)
|
||
|
+Look up the remote host name for
|
||
|
+.BR TCPREMOTEHOST .
|
||
|
+.TP
|
||
|
+.B \-H
|
||
|
+Do not look up the remote host name;
|
||
|
+unset
|
||
|
+.BR TCPREMOTEHOST .
|
||
|
+.TP
|
||
|
+.B \-l\fIlocalname
|
||
|
+Do not look up the local host name;
|
||
|
+use
|
||
|
+.I localname
|
||
|
+for
|
||
|
+.BR TCPLOCALHOST .
|
||
|
+.TP
|
||
|
+.B \-r
|
||
|
+(Default.)
|
||
|
+Attempt to obtain
|
||
|
+.B TCPREMOTEINFO
|
||
|
+from the remote host.
|
||
|
+.TP
|
||
|
+.B \-R
|
||
|
+Do not attempt to obtain
|
||
|
+.B TCPREMOTEINFO
|
||
|
+from the remote host.
|
||
|
+.TP
|
||
|
+.B \-t\fItimeoutinfo
|
||
|
+Give up on the
|
||
|
+.B TCPREMOTEINFO
|
||
|
+connection attempt
|
||
|
+after
|
||
|
+.I timeoutinfo
|
||
|
+seconds. Default: 26.
|
||
|
+.TP
|
||
|
+.B \-4
|
||
|
+Fall back to IPv4 sockets. This is necessary for terminally broken
|
||
|
+systems like OpenBSD which will not let IPv6 sockets connect to
|
||
|
+V4-mapped IPv6 addresses. Please note that this also applies to DNS
|
||
|
+lookups, so you will have to use an DNS resolver with an IPv6 address to
|
||
|
+connect to IPv6 systems. Use \fBDNSCACHEIP\fR to set the DNS resolver
|
||
|
+IP dynamically.
|
||
|
+.TP
|
||
|
+.B \-6
|
||
|
+Force IPv6 mode in UCSPI environment variables, even for
|
||
|
+IPv4 connections. This will set \fB$PROTO\fR to \fBTCP6\fR and put
|
||
|
+IPv4-mapped IPv6 addresses in \fBTCPLOCALIP\fR and \fBTCPREMOTEIP\fR.
|
||
|
+.SH "SEE ALSO"
|
||
|
+date@(1),
|
||
|
+finger@(1),
|
||
|
+http@(1),
|
||
|
+mconnect(1),
|
||
|
+tcpcat(1),
|
||
|
+tcpserver(1),
|
||
|
+who@(1),
|
||
|
+tcp-environ(5)
|
||
|
diff --git a/tcpclient.c b/tcpclient.c
|
||
|
index 9f6d7f2..77b1ad5 100644
|
||
|
--- a/tcpclient.c
|
||
|
+++ b/tcpclient.c
|
||
|
@@ -9,6 +9,7 @@
|
||
|
#include "scan.h"
|
||
|
#include "str.h"
|
||
|
#include "ip4.h"
|
||
|
+#include "ip6.h"
|
||
|
#include "uint16.h"
|
||
|
#include "socket.h"
|
||
|
#include "fd.h"
|
||
|
@@ -20,6 +21,7 @@
|
||
|
#include "timeoutconn.h"
|
||
|
#include "remoteinfo.h"
|
||
|
#include "dns.h"
|
||
|
+#include "byte.h"
|
||
|
|
||
|
#define FATAL "tcpclient: fatal: "
|
||
|
#define CONNECT "tcpclient: unable to connect to "
|
||
|
@@ -31,27 +33,30 @@ void nomem(void)
|
||
|
void usage(void)
|
||
|
{
|
||
|
strerr_die1x(100,"tcpclient: usage: tcpclient \
|
||
|
-[ -hHrRdDqQv ] \
|
||
|
+[ -46hHrRdDqQv ] \
|
||
|
[ -i localip ] \
|
||
|
[ -p localport ] \
|
||
|
[ -T timeoutconn ] \
|
||
|
[ -l localname ] \
|
||
|
[ -t timeoutinfo ] \
|
||
|
+[ -I interface ] \
|
||
|
host port program");
|
||
|
}
|
||
|
|
||
|
+int forcev6 = 0;
|
||
|
int verbosity = 1;
|
||
|
int flagdelay = 1;
|
||
|
int flagremoteinfo = 1;
|
||
|
int flagremotehost = 1;
|
||
|
unsigned long itimeout = 26;
|
||
|
unsigned long ctimeout[2] = { 2, 58 };
|
||
|
+uint32 netif = 0;
|
||
|
|
||
|
-char iplocal[4] = { 0,0,0,0 };
|
||
|
+char iplocal[16] = { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 };
|
||
|
uint16 portlocal = 0;
|
||
|
char *forcelocal = 0;
|
||
|
|
||
|
-char ipremote[4];
|
||
|
+char ipremote[16];
|
||
|
uint16 portremote;
|
||
|
|
||
|
char *hostname;
|
||
|
@@ -61,12 +66,13 @@ static stralloc moreaddresses;
|
||
|
static stralloc tmp;
|
||
|
static stralloc fqdn;
|
||
|
char strnum[FMT_ULONG];
|
||
|
-char ipstr[IP4_FMT];
|
||
|
+char ipstr[IP6_FMT];
|
||
|
|
||
|
char seed[128];
|
||
|
|
||
|
main(int argc,char **argv)
|
||
|
{
|
||
|
+ int fakev4=0;
|
||
|
unsigned long u;
|
||
|
int opt;
|
||
|
char *x;
|
||
|
@@ -80,8 +86,10 @@ main(int argc,char **argv)
|
||
|
close(7);
|
||
|
sig_ignore(sig_pipe);
|
||
|
|
||
|
- while ((opt = getopt(argc,argv,"dDvqQhHrRi:p:t:T:l:")) != opteof)
|
||
|
+ while ((opt = getopt(argc,argv,"46dDvqQhHrRi:p:t:T:l:I:")) != opteof)
|
||
|
switch(opt) {
|
||
|
+ case '4': noipv6 = 1; break;
|
||
|
+ case '6': forcev6 = 1; break;
|
||
|
case 'd': flagdelay = 1; break;
|
||
|
case 'D': flagdelay = 0; break;
|
||
|
case 'v': verbosity = 2; break;
|
||
|
@@ -97,7 +105,8 @@ main(int argc,char **argv)
|
||
|
if (optarg[j] == '+') ++j;
|
||
|
scan_ulong(optarg + j,&ctimeout[1]);
|
||
|
break;
|
||
|
- case 'i': if (!ip4_scan(optarg,iplocal)) usage(); break;
|
||
|
+ case 'i': if (!scan_ip6(optarg,iplocal)) usage(); break;
|
||
|
+ case 'I': netif=socket_getifidx(optarg); break;
|
||
|
case 'p': scan_ulong(optarg,&u); portlocal = u; break;
|
||
|
default: usage();
|
||
|
}
|
||
|
@@ -108,8 +117,8 @@ main(int argc,char **argv)
|
||
|
|
||
|
hostname = *argv;
|
||
|
if (!hostname) usage();
|
||
|
- if (str_equal(hostname,"")) hostname = "127.0.0.1";
|
||
|
- if (str_equal(hostname,"0")) hostname = "127.0.0.1";
|
||
|
+ if (!hostname[0] || str_equal(hostname,"0"))
|
||
|
+ hostname = (noipv6?"127.0.0.1":"::1");
|
||
|
|
||
|
x = *++argv;
|
||
|
if (!x) usage();
|
||
|
@@ -127,33 +136,36 @@ main(int argc,char **argv)
|
||
|
if (!*++argv) usage();
|
||
|
|
||
|
if (!stralloc_copys(&tmp,hostname)) nomem();
|
||
|
- if (dns_ip4_qualify(&addresses,&fqdn,&tmp) == -1)
|
||
|
+ if (dns_ip6_qualify(&addresses,&fqdn,&tmp) == -1)
|
||
|
strerr_die4sys(111,FATAL,"temporarily unable to figure out IP address for ",hostname,": ");
|
||
|
- if (addresses.len < 4)
|
||
|
+ if (addresses.len < 16)
|
||
|
strerr_die3x(111,FATAL,"no IP address for ",hostname);
|
||
|
|
||
|
- if (addresses.len == 4) {
|
||
|
+ if (addresses.len == 16) {
|
||
|
ctimeout[0] += ctimeout[1];
|
||
|
ctimeout[1] = 0;
|
||
|
}
|
||
|
|
||
|
for (cloop = 0;cloop < 2;++cloop) {
|
||
|
if (!stralloc_copys(&moreaddresses,"")) nomem();
|
||
|
- for (j = 0;j + 4 <= addresses.len;j += 4) {
|
||
|
- s = socket_tcp();
|
||
|
+ for (j = 0;j + 16 <= addresses.len;j += 4) {
|
||
|
+ s = socket_tcp6();
|
||
|
if (s == -1)
|
||
|
strerr_die2sys(111,FATAL,"unable to create socket: ");
|
||
|
- if (socket_bind4(s,iplocal,portlocal) == -1)
|
||
|
+ if (socket_bind6(s,iplocal,portlocal,netif) == -1)
|
||
|
strerr_die2sys(111,FATAL,"unable to bind socket: ");
|
||
|
- if (timeoutconn(s,addresses.s + j,portremote,ctimeout[cloop]) == 0)
|
||
|
+ if (timeoutconn6(s,addresses.s + j,portremote,ctimeout[cloop],netif) == 0)
|
||
|
goto CONNECTED;
|
||
|
close(s);
|
||
|
if (!cloop && ctimeout[1] && (errno == error_timeout)) {
|
||
|
- if (!stralloc_catb(&moreaddresses,addresses.s + j,4)) nomem();
|
||
|
+ if (!stralloc_catb(&moreaddresses,addresses.s + j,16)) nomem();
|
||
|
}
|
||
|
else {
|
||
|
strnum[fmt_ulong(strnum,portremote)] = 0;
|
||
|
- ipstr[ip4_fmt(ipstr,addresses.s + j)] = 0;
|
||
|
+ if (ip6_isv4mapped(addresses.s+j))
|
||
|
+ ipstr[ip4_fmt(ipstr,addresses.s + j + 12)] = 0;
|
||
|
+ else
|
||
|
+ ipstr[ip6_fmt(ipstr,addresses.s + j)] = 0;
|
||
|
strerr_warn5(CONNECT,ipstr," port ",strnum,": ",&strerr_sys);
|
||
|
}
|
||
|
}
|
||
|
@@ -169,37 +181,46 @@ main(int argc,char **argv)
|
||
|
if (!flagdelay)
|
||
|
socket_tcpnodelay(s); /* if it fails, bummer */
|
||
|
|
||
|
- if (!pathexec_env("PROTO","TCP")) nomem();
|
||
|
-
|
||
|
- if (socket_local4(s,iplocal,&portlocal) == -1)
|
||
|
+ if (socket_local6(s,iplocal,&portlocal,&netif) == -1)
|
||
|
strerr_die2sys(111,FATAL,"unable to get local address: ");
|
||
|
|
||
|
+ if (!forcev6 && (ip6_isv4mapped(iplocal) || byte_equal(iplocal,16,V6any)))
|
||
|
+ fakev4=1;
|
||
|
+
|
||
|
+ if (!pathexec_env("PROTO",fakev4?"TCP":"TCP6")) nomem();
|
||
|
+
|
||
|
strnum[fmt_ulong(strnum,portlocal)] = 0;
|
||
|
if (!pathexec_env("TCPLOCALPORT",strnum)) nomem();
|
||
|
- ipstr[ip4_fmt(ipstr,iplocal)] = 0;
|
||
|
+ if (fakev4)
|
||
|
+ ipstr[ip4_fmt(ipstr,iplocal+12)] = 0;
|
||
|
+ else
|
||
|
+ ipstr[ip6_fmt(ipstr,iplocal)] = 0;
|
||
|
if (!pathexec_env("TCPLOCALIP",ipstr)) nomem();
|
||
|
|
||
|
x = forcelocal;
|
||
|
if (!x)
|
||
|
- if (dns_name4(&tmp,iplocal) == 0) {
|
||
|
+ if (dns_name6(&tmp,iplocal) == 0) {
|
||
|
if (!stralloc_0(&tmp)) nomem();
|
||
|
x = tmp.s;
|
||
|
}
|
||
|
if (!pathexec_env("TCPLOCALHOST",x)) nomem();
|
||
|
|
||
|
- if (socket_remote4(s,ipremote,&portremote) == -1)
|
||
|
+ if (socket_remote6(s,ipremote,&portremote,&netif) == -1)
|
||
|
strerr_die2sys(111,FATAL,"unable to get remote address: ");
|
||
|
|
||
|
strnum[fmt_ulong(strnum,portremote)] = 0;
|
||
|
if (!pathexec_env("TCPREMOTEPORT",strnum)) nomem();
|
||
|
- ipstr[ip4_fmt(ipstr,ipremote)] = 0;
|
||
|
+ if (fakev4)
|
||
|
+ ipstr[ip4_fmt(ipstr,ipremote+12)] = 0;
|
||
|
+ else
|
||
|
+ ipstr[ip6_fmt(ipstr,ipremote)] = 0;
|
||
|
if (!pathexec_env("TCPREMOTEIP",ipstr)) nomem();
|
||
|
if (verbosity >= 2)
|
||
|
strerr_warn4("tcpclient: connected to ",ipstr," port ",strnum,0);
|
||
|
|
||
|
x = 0;
|
||
|
if (flagremotehost)
|
||
|
- if (dns_name4(&tmp,ipremote) == 0) {
|
||
|
+ if (dns_name6(&tmp,ipremote) == 0) {
|
||
|
if (!stralloc_0(&tmp)) nomem();
|
||
|
x = tmp.s;
|
||
|
}
|
||
|
@@ -207,7 +228,7 @@ main(int argc,char **argv)
|
||
|
|
||
|
x = 0;
|
||
|
if (flagremoteinfo)
|
||
|
- if (remoteinfo(&tmp,ipremote,portremote,iplocal,portlocal,itimeout) == 0) {
|
||
|
+ if (remoteinfo6(&tmp,ipremote,portremote,iplocal,portlocal,itimeout,netif) == 0) {
|
||
|
if (!stralloc_0(&tmp)) nomem();
|
||
|
x = tmp.s;
|
||
|
}
|
||
|
diff --git a/tcprules.1 b/tcprules.1
|
||
|
new file mode 100644
|
||
|
index 0000000..084165b
|
||
|
--- /dev/null
|
||
|
+++ b/tcprules.1
|
||
|
@@ -0,0 +1,221 @@
|
||
|
+.TH tcprules 1
|
||
|
+.SH NAME
|
||
|
+tcprules \- compile rules for tcpserver
|
||
|
+.SH SYNOPSIS
|
||
|
+.B tcprules
|
||
|
+.I rules.cdb
|
||
|
+.I rules.tmp
|
||
|
+.SH OVERVIEW
|
||
|
+.B tcpserver
|
||
|
+optionally follows rules to decide whether a TCP connection is acceptable.
|
||
|
+For example, a rule of
|
||
|
+
|
||
|
+.EX
|
||
|
+ 18.23.0.32:deny
|
||
|
+.EE
|
||
|
+
|
||
|
+prohibits connections from IP address 18.23.0.32.
|
||
|
+
|
||
|
+.B tcprules
|
||
|
+reads rules from its standard input
|
||
|
+and writes them into
|
||
|
+.I rules.cdb
|
||
|
+in a binary format suited
|
||
|
+for quick access by
|
||
|
+.BR tcpserver .
|
||
|
+
|
||
|
+.B tcprules
|
||
|
+can be used while
|
||
|
+.B tcpserver
|
||
|
+is running:
|
||
|
+it ensures that
|
||
|
+.I rules.cdb
|
||
|
+is updated atomically.
|
||
|
+It does this by first writing the rules to
|
||
|
+.I rules.tmp
|
||
|
+and then moving
|
||
|
+.I rules.tmp
|
||
|
+on top of
|
||
|
+.IR rules.cdb .
|
||
|
+If
|
||
|
+.I rules.tmp
|
||
|
+already exists, it is destroyed.
|
||
|
+The directories containing
|
||
|
+.I rules.cdb
|
||
|
+and
|
||
|
+.I rules.tmp
|
||
|
+must be writable to
|
||
|
+.BR tcprules ;
|
||
|
+they must also be on the same filesystem.
|
||
|
+
|
||
|
+If there is a problem with the input,
|
||
|
+.B tcprules
|
||
|
+complains and leaves
|
||
|
+.I rules.cdb
|
||
|
+alone.
|
||
|
+
|
||
|
+The binary
|
||
|
+.I rules.cdb
|
||
|
+format is portable across machines.
|
||
|
+.SH "RULE FORMAT"
|
||
|
+A rule takes up one line.
|
||
|
+A file containing rules
|
||
|
+may also contain comments: lines beginning with # are ignored.
|
||
|
+
|
||
|
+Each rule contains an
|
||
|
+.BR address ,
|
||
|
+a colon,
|
||
|
+and a list of
|
||
|
+.BR instructions ,
|
||
|
+with no extra spaces.
|
||
|
+When
|
||
|
+.B tcpserver
|
||
|
+receives a connection from that address,
|
||
|
+it follows the instructions.
|
||
|
+.SH "ADDRESSES"
|
||
|
+.B tcpserver
|
||
|
+starts by looking for a rule with address
|
||
|
+.IR TCPREMOTEINFO\fB@\fITCPREMOTEIP .
|
||
|
+If it doesn't find one, or if
|
||
|
+.I TCPREMOTEINFO
|
||
|
+is not set, it tries the address
|
||
|
+.IR TCPREMOTEIP .
|
||
|
+If that doesn't work, it tries shorter and shorter prefixes of
|
||
|
+.I TCPREMOTEIP
|
||
|
+ending with a dot.
|
||
|
+If none of them work, it tries the empty string.
|
||
|
+
|
||
|
+For example, here are some rules:
|
||
|
+
|
||
|
+.EX
|
||
|
+ joe@127.0.0.1:first
|
||
|
+.br
|
||
|
+ 18.23.0.32:second
|
||
|
+.br
|
||
|
+ 127.:third
|
||
|
+.br
|
||
|
+ :fourth
|
||
|
+.br
|
||
|
+ ::1:fifth
|
||
|
+.EE
|
||
|
+
|
||
|
+If
|
||
|
+.I TCPREMOTEIP
|
||
|
+is
|
||
|
+.BR 10.119.75.38 ,
|
||
|
+.B tcpserver
|
||
|
+will follow the
|
||
|
+.B fourth
|
||
|
+instructions.
|
||
|
+
|
||
|
+If
|
||
|
+.I TCPREMOTEIP
|
||
|
+is
|
||
|
+.BR ::1 ,
|
||
|
+.B tcpserver
|
||
|
+will follow the
|
||
|
+.B fifth
|
||
|
+instructions. Note that you cannot detect IPv4 mapped addresses by
|
||
|
+matching "::ffff", as those addresses will be converted to IPv4 before
|
||
|
+looking at the rules.
|
||
|
+
|
||
|
+If
|
||
|
+.I TCPREMOTEIP
|
||
|
+is
|
||
|
+.BR 18.23.0.32 ,
|
||
|
+.B tcpserver
|
||
|
+will follow the
|
||
|
+.B second
|
||
|
+instructions.
|
||
|
+
|
||
|
+If
|
||
|
+.I TCPREMOTEINFO
|
||
|
+is
|
||
|
+.B bill
|
||
|
+and
|
||
|
+.I TCPREMOTEIP
|
||
|
+is
|
||
|
+.BR 127.0.0.1 ,
|
||
|
+.B tcpserver
|
||
|
+will follow the
|
||
|
+.B third
|
||
|
+instructions.
|
||
|
+
|
||
|
+If
|
||
|
+.I TCPREMOTEINFO
|
||
|
+is
|
||
|
+.B joe
|
||
|
+and
|
||
|
+.I TCPREMOTEIP
|
||
|
+is
|
||
|
+.BR 127.0.0.1 ,
|
||
|
+.B tcpserver
|
||
|
+will follow the
|
||
|
+.B first
|
||
|
+instructions.
|
||
|
+.SH "ADDRESS RANGES"
|
||
|
+.B tcprules
|
||
|
+treats
|
||
|
+.B 1.2.3.37-53:ins
|
||
|
+as an abbreviation
|
||
|
+for the rules
|
||
|
+.BR 1.2.3.37:ins ,
|
||
|
+.BR 1.2.3.38:ins ,
|
||
|
+and so on up through
|
||
|
+.BR 1.2.3.53:ins .
|
||
|
+Similarly,
|
||
|
+.BR 10.2-3.:ins
|
||
|
+is an abbreviation for
|
||
|
+.B 10.2.:ins
|
||
|
+and
|
||
|
+.BR 10.3.:ins .
|
||
|
+.SH "INSTRUCTIONS"
|
||
|
+The instructions in a rule must begin with either
|
||
|
+.B allow
|
||
|
+or
|
||
|
+.BR deny .
|
||
|
+.B deny
|
||
|
+tells
|
||
|
+.B tcpserver
|
||
|
+to drop the connection without running anything.
|
||
|
+For example, the rule
|
||
|
+
|
||
|
+.EX
|
||
|
+ :deny
|
||
|
+.EE
|
||
|
+
|
||
|
+tells
|
||
|
+.B tcpserver
|
||
|
+to drop all connections that aren't handled by more specific rules.
|
||
|
+
|
||
|
+The instructions may continue with some environment variables,
|
||
|
+in the format
|
||
|
+.IR ,VAR="VALUE" .
|
||
|
+.B tcpserver
|
||
|
+adds
|
||
|
+.I VAR=VALUE
|
||
|
+to the current environment.
|
||
|
+For example,
|
||
|
+
|
||
|
+.EX
|
||
|
+ 10.0.:allow,RELAYCLIENT="@fix.me"
|
||
|
+.EE
|
||
|
+
|
||
|
+adds
|
||
|
+.B RELAYCLIENT=@fix.me
|
||
|
+to the environment.
|
||
|
+The quotes here may be replaced by any repeated character:
|
||
|
+
|
||
|
+.EX
|
||
|
+ 10.0.:allow,RELAYCLIENT=/@fix.me/
|
||
|
+.EE
|
||
|
+
|
||
|
+Any number of variables may be listed:
|
||
|
+
|
||
|
+.EX
|
||
|
+ 127.0.0.1:allow,RELAYCLIENT="",TCPLOCALHOST="movie.edu"
|
||
|
+.EE
|
||
|
+.SH "SEE ALSO"
|
||
|
+tcprulescheck(1),
|
||
|
+tcpserver(1),
|
||
|
+tcp-environ(5)
|
||
|
diff --git a/tcprules.c b/tcprules.c
|
||
|
index a684ac5..83519c8 100644
|
||
|
--- a/tcprules.c
|
||
|
+++ b/tcprules.c
|
||
|
@@ -123,8 +123,15 @@ main(int argc,char **argv)
|
||
|
}
|
||
|
line.len = len; /* for die_bad() */
|
||
|
|
||
|
- colon = byte_chr(x,len,':');
|
||
|
- if (colon == len) continue;
|
||
|
+ colon = 0;
|
||
|
+ for (;;) {
|
||
|
+ int tmp;
|
||
|
+ tmp = byte_chr(x + colon,len - colon,':');
|
||
|
+ colon += tmp;
|
||
|
+ if (colon == len) continue;
|
||
|
+ if (byte_equal(x+colon+1,4,"deny") || byte_equal(x+colon+1,5,"allow")) break;
|
||
|
+ ++colon;
|
||
|
+ }
|
||
|
|
||
|
if (!stralloc_copyb(&address,x,colon)) nomem();
|
||
|
if (!stralloc_copys(&data,"")) nomem();
|
||
|
diff --git a/tcprulescheck.1 b/tcprulescheck.1
|
||
|
new file mode 100644
|
||
|
index 0000000..3f0de24
|
||
|
--- /dev/null
|
||
|
+++ b/tcprulescheck.1
|
||
|
@@ -0,0 +1,25 @@
|
||
|
+.TH tcprulescheck 1
|
||
|
+.SH NAME
|
||
|
+tcprulescheck \- try out rules for tcpserver
|
||
|
+.SH SYNTAX
|
||
|
+.B tcprulescheck
|
||
|
+.I rules.cdb
|
||
|
+.I tcpremoteip
|
||
|
+[
|
||
|
+.I tcpremoteinfo
|
||
|
+]
|
||
|
+.SH DESCRIPTION
|
||
|
+.B tcprulescheck
|
||
|
+says what
|
||
|
+.B tcpserver
|
||
|
+will do with a connection from
|
||
|
+IP address
|
||
|
+.IR tcpremoteip ,
|
||
|
+following the rules compiled into
|
||
|
+.I rules.cdb
|
||
|
+by
|
||
|
+.BR tcprules .
|
||
|
+.SH "SEE ALSO"
|
||
|
+tcprules(1),
|
||
|
+tcpserver(1),
|
||
|
+tcp-environ(5)
|
||
|
diff --git a/tcpserver.1 b/tcpserver.1
|
||
|
new file mode 100644
|
||
|
index 0000000..72c5ca0
|
||
|
--- /dev/null
|
||
|
+++ b/tcpserver.1
|
||
|
@@ -0,0 +1,266 @@
|
||
|
+.TH tcpserver 1
|
||
|
+.SH NAME
|
||
|
+tcpserver \- accept incoming TCP connections
|
||
|
+.SH SYNOPSIS
|
||
|
+.B tcpserver
|
||
|
+[
|
||
|
+.B \-146jpPhHrRoOdDqQv
|
||
|
+]
|
||
|
+[
|
||
|
+.B \-c\fIlimit
|
||
|
+]
|
||
|
+[
|
||
|
+.B \-x\fIrules.cdb
|
||
|
+]
|
||
|
+[
|
||
|
+.B \-B\fIbanner
|
||
|
+]
|
||
|
+[
|
||
|
+.B \-g\fIgid
|
||
|
+]
|
||
|
+[
|
||
|
+.B \-u\fIuid
|
||
|
+]
|
||
|
+[
|
||
|
+.B \-b\fIbacklog
|
||
|
+]
|
||
|
+[
|
||
|
+.B \-l\fIlocalname
|
||
|
+]
|
||
|
+[
|
||
|
+.B \-t\fItimeout
|
||
|
+]
|
||
|
+[
|
||
|
+.B \-I\fIinterface
|
||
|
+]
|
||
|
+.I host
|
||
|
+.I port
|
||
|
+.I program
|
||
|
+[
|
||
|
+.I arg ...
|
||
|
+]
|
||
|
+.SH DESCRIPTION
|
||
|
+.B tcpserver
|
||
|
+waits for connections from TCP clients.
|
||
|
+For each connection, it runs
|
||
|
+.I program
|
||
|
+with the given arguments,
|
||
|
+with descriptor 0 reading from the network
|
||
|
+and descriptor 1 writing to the network.
|
||
|
+
|
||
|
+The server's address is given by
|
||
|
+.I host
|
||
|
+and
|
||
|
+.IR port .
|
||
|
+.I host
|
||
|
+can be 0, allowing connections from any host;
|
||
|
+or a particular IP address,
|
||
|
+allowing connections only to that address;
|
||
|
+or a host name, allowing connections to the first IP address
|
||
|
+for that host.
|
||
|
+.I port
|
||
|
+may be a numeric port number
|
||
|
+or a port name.
|
||
|
+If
|
||
|
+.I port
|
||
|
+is 0,
|
||
|
+.B tcpserver
|
||
|
+will choose a free port.
|
||
|
+
|
||
|
+.B tcpserver
|
||
|
+sets up several environment variables,
|
||
|
+as described in
|
||
|
+.B tcp-environ(5).
|
||
|
+
|
||
|
+.B tcpserver
|
||
|
+exits when it receives SIGTERM.
|
||
|
+.SH "OPTIONS"
|
||
|
+.TP
|
||
|
+.B \-c\fIlimit
|
||
|
+Do not handle more than
|
||
|
+.I limit
|
||
|
+simultaneous connections.
|
||
|
+If there are
|
||
|
+.I limit
|
||
|
+simultaneous copies of
|
||
|
+.I program
|
||
|
+running, defer acceptance of a new connection
|
||
|
+until one copy finishes.
|
||
|
+.I limit
|
||
|
+must be a positive integer.
|
||
|
+Default: 40.
|
||
|
+.TP
|
||
|
+.B \-x\fIrules.cdb
|
||
|
+Follow the rules compiled into
|
||
|
+.I rules.cdb
|
||
|
+by
|
||
|
+.BR tcprules .
|
||
|
+These rules may specify setting environment variables
|
||
|
+or rejecting connections from bad sources.
|
||
|
+
|
||
|
+.B tcpserver
|
||
|
+does not read
|
||
|
+.I rules.cdb
|
||
|
+into memory;
|
||
|
+you can rerun
|
||
|
+.B tcprules
|
||
|
+to change
|
||
|
+.BR tcpserver 's
|
||
|
+behavior on the fly.
|
||
|
+.TP
|
||
|
+.B \-B\fIbanner
|
||
|
+Write
|
||
|
+.I banner
|
||
|
+to the network immediately after each connection is made.
|
||
|
+.B tcpserver
|
||
|
+writes
|
||
|
+.I banner
|
||
|
+before looking up
|
||
|
+.BR TCPREMOTEHOST ,
|
||
|
+before looking up
|
||
|
+.BR TCPREMOTEINFO ,
|
||
|
+and before checking
|
||
|
+.IR rules.cdb .
|
||
|
+
|
||
|
+This feature can be used to reduce latency in protocols
|
||
|
+where the client waits for a greeting from the server.
|
||
|
+.TP
|
||
|
+.B \-g\fIgid
|
||
|
+Switch group ID to
|
||
|
+.I gid
|
||
|
+after preparing to receive connections.
|
||
|
+.I gid
|
||
|
+must be a positive integer.
|
||
|
+.TP
|
||
|
+.B \-u\fIuid
|
||
|
+Switch user ID to
|
||
|
+.I uid
|
||
|
+after preparing to receive connections.
|
||
|
+.I uid
|
||
|
+must be a positive integer.
|
||
|
+.TP
|
||
|
+.B \-1
|
||
|
+After preparing to receive connections,
|
||
|
+print the local port number to standard output.
|
||
|
+.TP
|
||
|
+.B \-4
|
||
|
+Fall back to IPv4 sockets. This is necessary for terminally broken
|
||
|
+systems like OpenBSD which will not let IPv6 sockets connect to
|
||
|
+V4-mapped IPv6 addresses. Please note that this also applies to DNS
|
||
|
+lookups, so you will have to use an DNS resolver with an IPv6 address to
|
||
|
+accept IPv6 connections. Use \fBDNSCACHEIP\fR to set the DNS resolver
|
||
|
+IP dynamically.
|
||
|
+.TP
|
||
|
+.B \-6
|
||
|
+Force IPv6 mode in UCSPI environment variables, even for
|
||
|
+IPv4 connections. This will set \fB$PROTO\fR to \fBTCP6\fR and put
|
||
|
+IPv4-mapped IPv6 addresses in \fBTCPLOCALIP\fR and \fBTCPREMOTEIP\fR.
|
||
|
+.TP
|
||
|
+.B \-I\fIinterface
|
||
|
+Bind to the network interface
|
||
|
+.I interface
|
||
|
+("eth0" on Linux, for example). This is only defined and needed for
|
||
|
+IPv6 link-local addresses.
|
||
|
+.TP
|
||
|
+.B \-b\fIbacklog
|
||
|
+Allow up to
|
||
|
+.I backlog
|
||
|
+simultaneous SYN_RECEIVEDs.
|
||
|
+Default: 20.
|
||
|
+On some systems,
|
||
|
+.I backlog
|
||
|
+is silently limited to 5.
|
||
|
+See
|
||
|
+.BR listen (2)
|
||
|
+for more details.
|
||
|
+.TP
|
||
|
+.B \-o
|
||
|
+Leave IP options alone.
|
||
|
+If the client is sending packets along an IP source route,
|
||
|
+send packets back along the same route.
|
||
|
+.TP
|
||
|
+.B \-O
|
||
|
+(Default.)
|
||
|
+Kill IP options.
|
||
|
+A client can still use source routing to connect and to send data,
|
||
|
+but packets will be sent back along the default route.
|
||
|
+.TP
|
||
|
+.B \-d
|
||
|
+(Default.)
|
||
|
+Delay sending data for a fraction of a second whenever the
|
||
|
+remote host is responding slowly,
|
||
|
+to make better use of the network.
|
||
|
+.TP
|
||
|
+.B \-D
|
||
|
+Never delay sending data;
|
||
|
+enable TCP_NODELAY.
|
||
|
+This is appropriate for interactive connections.
|
||
|
+.TP
|
||
|
+.B \-q
|
||
|
+Quiet.
|
||
|
+Do not print any messages.
|
||
|
+.TP
|
||
|
+.B \-Q
|
||
|
+(Default.)
|
||
|
+Print error messages.
|
||
|
+.TP
|
||
|
+.B \-v
|
||
|
+Verbose.
|
||
|
+Print all available messages.
|
||
|
+.SH "DATA-GATHERING OPTIONS"
|
||
|
+.TP
|
||
|
+.B \-p
|
||
|
+Paranoid.
|
||
|
+After looking up the remote host name,
|
||
|
+look up the IP addresses for that name,
|
||
|
+and make sure one of them matches
|
||
|
+.BR TCPREMOTEIP .
|
||
|
+If none of them do,
|
||
|
+unset
|
||
|
+.BR TCPREMOTEHOST .
|
||
|
+.TP
|
||
|
+.B \-P
|
||
|
+(Default.)
|
||
|
+Not paranoid.
|
||
|
+.TP
|
||
|
+.B \-h
|
||
|
+(Default.)
|
||
|
+Look up the remote host name and set
|
||
|
+.BR TCPREMOTEHOST .
|
||
|
+.TP
|
||
|
+.B \-H
|
||
|
+Do not look up the remote host name.
|
||
|
+.TP
|
||
|
+.B \-l\fIlocalname
|
||
|
+Do not look up the local host name;
|
||
|
+use
|
||
|
+.I localname
|
||
|
+for
|
||
|
+.BR TCPLOCALHOST .
|
||
|
+.TP
|
||
|
+.B \-r
|
||
|
+(Default.)
|
||
|
+Attempt to obtain
|
||
|
+.B TCPREMOTEINFO
|
||
|
+from the remote host.
|
||
|
+.TP
|
||
|
+.B \-R
|
||
|
+Do not attempt to obtain
|
||
|
+.B TCPREMOTEINFO
|
||
|
+from the remote host.
|
||
|
+.TP
|
||
|
+.B \-t\fItimeout
|
||
|
+Give up on the
|
||
|
+.B TCPREMOTEINFO
|
||
|
+connection attempt
|
||
|
+after
|
||
|
+.I timeout
|
||
|
+seconds. Default: 26.
|
||
|
+.SH "SEE ALSO"
|
||
|
+argv0(1),
|
||
|
+fixcr(1),
|
||
|
+recordio(1),
|
||
|
+tcpclient(1),
|
||
|
+tcprules(1),
|
||
|
+listen(2),
|
||
|
+tcp-environ(5)
|
||
|
diff --git a/tcpserver.c b/tcpserver.c
|
||
|
index 979a0be..aab637f 100644
|
||
|
--- a/tcpserver.c
|
||
|
+++ b/tcpserver.c
|
||
|
@@ -7,6 +7,7 @@
|
||
|
#include "fmt.h"
|
||
|
#include "scan.h"
|
||
|
#include "ip4.h"
|
||
|
+#include "ip6.h"
|
||
|
#include "fd.h"
|
||
|
#include "exit.h"
|
||
|
#include "env.h"
|
||
|
@@ -28,6 +29,7 @@
|
||
|
#include "sig.h"
|
||
|
#include "dns.h"
|
||
|
|
||
|
+int forcev6 = 0;
|
||
|
int verbosity = 1;
|
||
|
int flagkillopts = 1;
|
||
|
int flagdelay = 1;
|
||
|
@@ -36,20 +38,21 @@ int flagremoteinfo = 1;
|
||
|
int flagremotehost = 1;
|
||
|
int flagparanoid = 0;
|
||
|
unsigned long timeout = 26;
|
||
|
+uint32 netif = 0;
|
||
|
|
||
|
static stralloc tcpremoteinfo;
|
||
|
|
||
|
uint16 localport;
|
||
|
char localportstr[FMT_ULONG];
|
||
|
-char localip[4];
|
||
|
-char localipstr[IP4_FMT];
|
||
|
+char localip[16];
|
||
|
+char localipstr[IP6_FMT];
|
||
|
static stralloc localhostsa;
|
||
|
char *localhost = 0;
|
||
|
|
||
|
uint16 remoteport;
|
||
|
char remoteportstr[FMT_ULONG];
|
||
|
-char remoteip[4];
|
||
|
-char remoteipstr[IP4_FMT];
|
||
|
+char remoteip[16];
|
||
|
+char remoteipstr[IP6_FMT];
|
||
|
static stralloc remotehostsa;
|
||
|
char *remotehost = 0;
|
||
|
|
||
|
@@ -96,12 +99,12 @@ void safecats(char *s)
|
||
|
if (ch < 33) ch = '?';
|
||
|
if (ch > 126) ch = '?';
|
||
|
if (ch == '%') ch = '?'; /* logger stupidity */
|
||
|
- if (ch == ':') ch = '?';
|
||
|
+/* if (ch == ':') ch = '?'; */
|
||
|
append(&ch);
|
||
|
}
|
||
|
cats("...");
|
||
|
}
|
||
|
-void env(char *s,char *t)
|
||
|
+void env(const char *s,const char *t)
|
||
|
{
|
||
|
if (!pathexec_env(s,t)) drop_nomem();
|
||
|
}
|
||
|
@@ -135,9 +138,16 @@ void found(char *data,unsigned int datalen)
|
||
|
|
||
|
void doit(int t)
|
||
|
{
|
||
|
+ int fakev4=0;
|
||
|
int j;
|
||
|
+ uint32 scope_id;
|
||
|
|
||
|
- remoteipstr[ip4_fmt(remoteipstr,remoteip)] = 0;
|
||
|
+ if (!forcev6 && ip6_isv4mapped(remoteip))
|
||
|
+ fakev4=1;
|
||
|
+ if (fakev4)
|
||
|
+ remoteipstr[ip4_fmt(remoteipstr,remoteip+12)] = 0;
|
||
|
+ else
|
||
|
+ remoteipstr[ip6_fmt(remoteipstr,remoteip)] = 0;
|
||
|
|
||
|
if (verbosity >= 2) {
|
||
|
strnum[fmt_ulong(strnum,getpid())] = 0;
|
||
|
@@ -155,30 +165,40 @@ void doit(int t)
|
||
|
strerr_die2sys(111,DROP,"unable to print banner: ");
|
||
|
}
|
||
|
|
||
|
- if (socket_local4(t,localip,&localport) == -1)
|
||
|
+ if (socket_local6(t,localip,&localport,&scope_id) == -1)
|
||
|
strerr_die2sys(111,DROP,"unable to get local address: ");
|
||
|
|
||
|
- localipstr[ip4_fmt(localipstr,localip)] = 0;
|
||
|
+ if (fakev4)
|
||
|
+ localipstr[ip4_fmt(localipstr,localip+12)] = 0;
|
||
|
+ else
|
||
|
+ localipstr[ip6_fmt(localipstr,localip)] = 0;
|
||
|
remoteportstr[fmt_ulong(remoteportstr,remoteport)] = 0;
|
||
|
|
||
|
if (!localhost)
|
||
|
- if (dns_name4(&localhostsa,localip) == 0)
|
||
|
+ if (dns_name6(&localhostsa,localip) == 0)
|
||
|
if (localhostsa.len) {
|
||
|
if (!stralloc_0(&localhostsa)) drop_nomem();
|
||
|
localhost = localhostsa.s;
|
||
|
}
|
||
|
- env("PROTO","TCP");
|
||
|
+ env("PROTO",fakev4?"TCP":"TCP6");
|
||
|
env("TCPLOCALIP",localipstr);
|
||
|
+ localipstr[ip6_fmt(localipstr,localip)]=0;
|
||
|
+ env("TCP6LOCALIP",localipstr);
|
||
|
+
|
||
|
env("TCPLOCALPORT",localportstr);
|
||
|
+ env("TCP6LOCALPORT",localportstr);
|
||
|
env("TCPLOCALHOST",localhost);
|
||
|
+ env("TCP6LOCALHOST",localhost);
|
||
|
+ if (!fakev4 && scope_id)
|
||
|
+ env("TCP6INTERFACE",socket_getifname(scope_id));
|
||
|
|
||
|
if (flagremotehost)
|
||
|
- if (dns_name4(&remotehostsa,remoteip) == 0)
|
||
|
+ if (dns_name6(&remotehostsa,remoteip) == 0)
|
||
|
if (remotehostsa.len) {
|
||
|
if (flagparanoid)
|
||
|
- if (dns_ip4(&tmp,&remotehostsa) == 0)
|
||
|
- for (j = 0;j + 4 <= tmp.len;j += 4)
|
||
|
- if (byte_equal(remoteip,4,tmp.s + j)) {
|
||
|
+ if (dns_ip6(&tmp,&remotehostsa) == 0)
|
||
|
+ for (j = 0;j + 16 <= tmp.len;j += 16)
|
||
|
+ if (byte_equal(remoteip,16,tmp.s + j)) {
|
||
|
flagparanoid = 0;
|
||
|
break;
|
||
|
}
|
||
|
@@ -188,15 +208,20 @@ void doit(int t)
|
||
|
}
|
||
|
}
|
||
|
env("TCPREMOTEIP",remoteipstr);
|
||
|
+ remoteipstr[ip6_fmt(remoteipstr,remoteip)]=0;
|
||
|
+ env("TCP6REMOTEIP",remoteipstr);
|
||
|
env("TCPREMOTEPORT",remoteportstr);
|
||
|
+ env("TCP6REMOTEPORT",remoteportstr);
|
||
|
env("TCPREMOTEHOST",remotehost);
|
||
|
+ env("TCP6REMOTEHOST",remotehost);
|
||
|
|
||
|
if (flagremoteinfo) {
|
||
|
- if (remoteinfo(&tcpremoteinfo,remoteip,remoteport,localip,localport,timeout) == -1)
|
||
|
+ if (remoteinfo6(&tcpremoteinfo,remoteip,remoteport,localip,localport,timeout,netif) == -1)
|
||
|
flagremoteinfo = 0;
|
||
|
if (!stralloc_0(&tcpremoteinfo)) drop_nomem();
|
||
|
}
|
||
|
env("TCPREMOTEINFO",flagremoteinfo ? tcpremoteinfo.s : 0);
|
||
|
+ env("TCP6REMOTEINFO",flagremoteinfo ? tcpremoteinfo.s : 0);
|
||
|
|
||
|
if (fnrules) {
|
||
|
int fdrules;
|
||
|
@@ -206,7 +231,15 @@ void doit(int t)
|
||
|
if (!flagallownorules) drop_rules();
|
||
|
}
|
||
|
else {
|
||
|
- if (rules(found,fdrules,remoteipstr,remotehost,flagremoteinfo ? tcpremoteinfo.s : 0) == -1) drop_rules();
|
||
|
+ int fakev4=0;
|
||
|
+ char* temp;
|
||
|
+ if (!forcev6 && ip6_isv4mapped(remoteip))
|
||
|
+ fakev4=1;
|
||
|
+ if (fakev4)
|
||
|
+ temp=remoteipstr+7;
|
||
|
+ else
|
||
|
+ temp=remoteipstr;
|
||
|
+ if (rules(found,fdrules,temp,remotehost,flagremoteinfo ? tcpremoteinfo.s : 0) == -1) drop_rules();
|
||
|
close(fdrules);
|
||
|
}
|
||
|
}
|
||
|
@@ -240,7 +273,7 @@ void usage(void)
|
||
|
{
|
||
|
strerr_warn1("\
|
||
|
tcpserver: usage: tcpserver \
|
||
|
-[ -1UXpPhHrRoOdDqQv ] \
|
||
|
+[ -461UXpPhHrRoOdDqQv ] \
|
||
|
[ -c limit ] \
|
||
|
[ -x rules.cdb ] \
|
||
|
[ -B banner ] \
|
||
|
@@ -249,6 +282,7 @@ tcpserver: usage: tcpserver \
|
||
|
[ -b backlog ] \
|
||
|
[ -l localname ] \
|
||
|
[ -t timeout ] \
|
||
|
+[ -I interface ] \
|
||
|
host port program",0);
|
||
|
_exit(100);
|
||
|
}
|
||
|
@@ -299,8 +333,8 @@ main(int argc,char **argv)
|
||
|
unsigned long u;
|
||
|
int s;
|
||
|
int t;
|
||
|
-
|
||
|
- while ((opt = getopt(argc,argv,"dDvqQhHrR1UXx:t:u:g:l:b:B:c:pPoO")) != opteof)
|
||
|
+
|
||
|
+ while ((opt = getopt(argc,argv,"46dDvqQhHrR1UXx:t:u:g:l:b:B:c:I:pPoO")) != opteof)
|
||
|
switch(opt) {
|
||
|
case 'b': scan_ulong(optarg,&backlog); break;
|
||
|
case 'c': scan_ulong(optarg,&limit); break;
|
||
|
@@ -325,7 +359,10 @@ main(int argc,char **argv)
|
||
|
x = env_get("GID"); if (x) scan_ulong(x,&gid); break;
|
||
|
case 'u': scan_ulong(optarg,&uid); break;
|
||
|
case 'g': scan_ulong(optarg,&gid); break;
|
||
|
+ case 'I': netif=socket_getifidx(optarg); break;
|
||
|
case '1': flag1 = 1; break;
|
||
|
+ case '4': noipv6 = 1; break;
|
||
|
+ case '6': forcev6 = 1; break;
|
||
|
case 'l': localhost = optarg; break;
|
||
|
default: usage();
|
||
|
}
|
||
|
@@ -337,8 +374,7 @@ main(int argc,char **argv)
|
||
|
|
||
|
hostname = *argv++;
|
||
|
if (!hostname) usage();
|
||
|
- if (str_equal(hostname,"")) hostname = "0.0.0.0";
|
||
|
- if (str_equal(hostname,"0")) hostname = "0.0.0.0";
|
||
|
+ if (str_equal(hostname,"")) hostname = "0";
|
||
|
|
||
|
x = *argv++;
|
||
|
if (!x) usage();
|
||
|
@@ -348,7 +384,7 @@ main(int argc,char **argv)
|
||
|
se = getservbyname(x,"tcp");
|
||
|
if (!se)
|
||
|
strerr_die3x(111,FATAL,"unable to figure out port number for ",x);
|
||
|
- localport = ntohs(se->s_port);
|
||
|
+ uint16_unpack_big((char*)&se->s_port,&localport);
|
||
|
}
|
||
|
|
||
|
if (!*argv) usage();
|
||
|
@@ -358,20 +394,26 @@ main(int argc,char **argv)
|
||
|
sig_catch(sig_term,sigterm);
|
||
|
sig_ignore(sig_pipe);
|
||
|
|
||
|
- if (!stralloc_copys(&tmp,hostname))
|
||
|
- strerr_die2x(111,FATAL,"out of memory");
|
||
|
- if (dns_ip4_qualify(&addresses,&fqdn,&tmp) == -1)
|
||
|
- strerr_die4sys(111,FATAL,"temporarily unable to figure out IP address for ",hostname,": ");
|
||
|
- if (addresses.len < 4)
|
||
|
- strerr_die3x(111,FATAL,"no IP address for ",hostname);
|
||
|
- byte_copy(localip,4,addresses.s);
|
||
|
-
|
||
|
- s = socket_tcp();
|
||
|
+ if (str_equal(hostname,"0")) {
|
||
|
+ byte_zero(localip,sizeof localip);
|
||
|
+ } else {
|
||
|
+ if (!stralloc_copys(&tmp,hostname))
|
||
|
+ strerr_die2x(111,FATAL,"out of memory");
|
||
|
+ if (dns_ip6_qualify(&addresses,&fqdn,&tmp) == -1)
|
||
|
+ strerr_die4sys(111,FATAL,"temporarily unable to figure out IP address for ",hostname,": ");
|
||
|
+ if (addresses.len < 16)
|
||
|
+ strerr_die3x(111,FATAL,"no IP address for ",hostname);
|
||
|
+ byte_copy(localip,16,addresses.s);
|
||
|
+ if (ip6_isv4mapped(localip))
|
||
|
+ noipv6=1;
|
||
|
+ }
|
||
|
+
|
||
|
+ s = socket_tcp6();
|
||
|
if (s == -1)
|
||
|
strerr_die2sys(111,FATAL,"unable to create socket: ");
|
||
|
- if (socket_bind4_reuse(s,localip,localport) == -1)
|
||
|
+ if (socket_bind6_reuse(s,localip,localport,netif) == -1)
|
||
|
strerr_die2sys(111,FATAL,"unable to bind: ");
|
||
|
- if (socket_local4(s,localip,&localport) == -1)
|
||
|
+ if (socket_local6(s,localip,&localport,&netif) == -1)
|
||
|
strerr_die2sys(111,FATAL,"unable to get local address: ");
|
||
|
if (socket_listen(s,backlog) == -1)
|
||
|
strerr_die2sys(111,FATAL,"unable to listen: ");
|
||
|
@@ -399,7 +441,7 @@ main(int argc,char **argv)
|
||
|
while (numchildren >= limit) sig_pause();
|
||
|
|
||
|
sig_unblock(sig_child);
|
||
|
- t = socket_accept4(s,remoteip,&remoteport);
|
||
|
+ t = socket_accept6(s,remoteip,&remoteport,&netif);
|
||
|
sig_block(sig_child);
|
||
|
|
||
|
if (t == -1) continue;
|
||
|
diff --git a/timeoutconn.h b/timeoutconn.h
|
||
|
index 7f9dcc9..01e6a75 100644
|
||
|
--- a/timeoutconn.h
|
||
|
+++ b/timeoutconn.h
|
||
|
@@ -2,7 +2,9 @@
|
||
|
#define TIMEOUTCONN_H
|
||
|
|
||
|
#include "uint16.h"
|
||
|
+#include "uint32.h"
|
||
|
|
||
|
extern int timeoutconn(int,char *,uint16,unsigned int);
|
||
|
+extern int timeoutconn6(int,char *,uint16,unsigned int,uint32);
|
||
|
|
||
|
#endif
|
||
|
diff --git a/timeoutconn6.c b/timeoutconn6.c
|
||
|
new file mode 100644
|
||
|
index 0000000..75e9f5a
|
||
|
--- /dev/null
|
||
|
+++ b/timeoutconn6.c
|
||
|
@@ -0,0 +1,34 @@
|
||
|
+#include "ndelay.h"
|
||
|
+#include "socket.h"
|
||
|
+#include "iopause.h"
|
||
|
+#include "error.h"
|
||
|
+#include "timeoutconn.h"
|
||
|
+
|
||
|
+int timeoutconn6(int s,char ip[16],uint16 port,unsigned int timeout,uint32 netif)
|
||
|
+{
|
||
|
+ struct taia now;
|
||
|
+ struct taia deadline;
|
||
|
+ iopause_fd x;
|
||
|
+
|
||
|
+ if (socket_connect6(s,ip,port,netif) == -1) {
|
||
|
+ if ((errno != error_wouldblock) && (errno != error_inprogress)) return -1;
|
||
|
+ x.fd = s;
|
||
|
+ x.events = IOPAUSE_WRITE;
|
||
|
+ taia_now(&now);
|
||
|
+ taia_uint(&deadline,timeout);
|
||
|
+ taia_add(&deadline,&now,&deadline);
|
||
|
+ for (;;) {
|
||
|
+ taia_now(&now);
|
||
|
+ iopause(&x,1,&deadline,&now);
|
||
|
+ if (x.revents) break;
|
||
|
+ if (taia_less(&deadline,&now)) {
|
||
|
+ errno = error_timeout; /* note that connect attempt is continuing */
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ if (!socket_connected(s)) return -1;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (ndelay_off(s) == -1) return -1;
|
||
|
+ return 0;
|
||
|
+}
|
||
|
diff --git a/tryip6.c b/tryip6.c
|
||
|
new file mode 100644
|
||
|
index 0000000..e0d7cfb
|
||
|
--- /dev/null
|
||
|
+++ b/tryip6.c
|
||
|
@@ -0,0 +1,8 @@
|
||
|
+#include <sys/types.h>
|
||
|
+#include <sys/socket.h>
|
||
|
+#include <netinet/in.h>
|
||
|
+
|
||
|
+main() {
|
||
|
+ struct sockaddr_in6 sa;
|
||
|
+ sa.sin6_family = PF_INET6;
|
||
|
+}
|
||
|
diff --git a/who@.1 b/who@.1
|
||
|
new file mode 100644
|
||
|
index 0000000..0c13f84
|
||
|
--- /dev/null
|
||
|
+++ b/who@.1
|
||
|
@@ -0,0 +1,32 @@
|
||
|
+.TH who@ 1
|
||
|
+.SH NAME
|
||
|
+who@ \- print list of active users on a host
|
||
|
+.SH SYNTAX
|
||
|
+.B who@
|
||
|
+[
|
||
|
+.I host
|
||
|
+]
|
||
|
+.SH DESCRIPTION
|
||
|
+.B who@
|
||
|
+connects to TCP port 11 (Systat) on
|
||
|
+.I host
|
||
|
+and prints any data it receives.
|
||
|
+It removes CR and converts unprintable characters to a visible format.
|
||
|
+
|
||
|
+If
|
||
|
+.I host
|
||
|
+is not supplied,
|
||
|
+.B who@
|
||
|
+connects to the local host.
|
||
|
+
|
||
|
+Some computers respond to port 11 with a list of active users.
|
||
|
+For example, they may be running
|
||
|
+
|
||
|
+.EX
|
||
|
+ tcpserver 0 11 who &
|
||
|
+.EE
|
||
|
+.SH "SEE ALSO"
|
||
|
+cat(1),
|
||
|
+delcr(1),
|
||
|
+tcpclient(1),
|
||
|
+tcpserver(1)
|
||
|
--
|
||
|
1.6.0.3
|
||
|
|