diff options
Diffstat (limited to 'usr.sbin/faithd/test/faithd.rb')
-rw-r--r-- | usr.sbin/faithd/test/faithd.rb | 312 |
1 files changed, 312 insertions, 0 deletions
diff --git a/usr.sbin/faithd/test/faithd.rb b/usr.sbin/faithd/test/faithd.rb new file mode 100644 index 0000000..683b504 --- /dev/null +++ b/usr.sbin/faithd/test/faithd.rb @@ -0,0 +1,312 @@ +# faithd, ruby version. requires v6-enabled ruby. +# +# highly experimental (not working right at all) and very limited +# functionality. +# +# $Id: faithd.rb,v 1.1.1.1 1999/08/08 23:29:31 itojun Exp $ +# $FreeBSD$ + +require "socket" +require "thread" + +# XXX should be derived from system headers +IPPROTO_IPV6 = 41 +IPV6_FAITH = 29 +DEBUG = true +DEBUG_LOOPBACK = true + +# TODO: OOB data handling +def tcpcopy(s1, s2, m) + STDERR.print "tcpcopy #{s1} #{s2}\n" if DEBUG + buf = "" + while TRUE + begin + buf = s1.sysread(100) + s2.syswrite(buf) + rescue EOFError + break + rescue IOError + break + end + end + STDERR.print "tcpcopy #{s1} #{s2} finished\n" if DEBUG + s1.shutdown(0) + s2.shutdown(1) +end + +def relay_ftp_passiveconn(s6, s4, dport6, dport4) + Thread.start do + d6 = TCPserver.open("::", dport6).accept + d4 = TCPsocket.open(s4.getpeer[3], dport4) + t = [] + t[0] = Thread.start do + tcpcopy(d6, d4) + end + t[1] = Thread.start do + tcpcopy(d4, d6) + end + for i in t + i.join + end + d4.close + d6.close + end +end + +def ftp_parse_2428(line) + if (line[0] != line[line.length - 1]) + return nil + end + t = line.split(line[0 .. 0]) # as string + if (t.size != 4 || t[1] !~ /^[12]$/ || t[3] !~ /^\d+$/) + return nil + end + return t[1 .. 3] +end + +def relay_ftp_command(s6, s4, state) + STDERR.print "relay_ftp_command start\n" if DEBUG + while TRUE + begin + STDERR.print "s6.gets\n" if DEBUG + line = s6.gets + STDERR.print "line is #{line}\n" if DEBUG + if line == nil + return nil + end + + # translate then copy + STDERR.print "line is #{line}\n" if DEBUG + if (line =~ /^EPSV\r\n/i) + STDERR.print "EPSV -> PASV\n" if DEBUG + line = "PASV\n" + state = "EPSV" + elsif (line =~ /^EPRT\s+(.+)\r\n/i) + t = ftp_parse_2428($1) + if t == nil + s6.puts "501 illegal parameter to EPRT\r\n" + next + end + + # some tricks should be here + s6.puts "501 illegal parameter to EPRT\r\n" + next + end + STDERR.print "fail: send #{line} as is\n" if DEBUG + s4.puts(line) + break + rescue EOFError + return nil + rescue IOError + return nil + end + end + STDERR.print "relay_ftp_command finish\n" if DEBUG + return state +end + +def relay_ftp_status(s4, s6, state) + STDERR.print "relay_ftp_status start\n" if DEBUG + while TRUE + begin + line = s4.gets + if line == nil + return nil + end + + # translate then copy + s6.puts(line) + + next if line =~ /^\d\d\d-/ + next if line !~ /^\d/ + + # special post-processing + case line + when /^221 / # result to QUIT + s4.shutdown(0) + s6.shutdown(1) + end + + break if (line =~ /^\d\d\d /) + rescue EOFError + return nil + rescue IOError + return nil + end + end + STDERR.print "relay_ftp_status finish\n" if DEBUG + return state +end + +def relay_ftp(sock, name) + STDERR.print "relay_ftp(#{sock}, #{name})\n" if DEBUG + while TRUE + STDERR.print "relay_ftp(#{sock}, #{name}) accepting\n" if DEBUG + s = sock.accept + STDERR.print "relay_ftp(#{sock}, #{name}) accepted #{s}\n" if DEBUG + Thread.start do + threads = [] + STDERR.print "accepted #{s} -> #{Thread.current}\n" if DEBUG + s6 = s + dest6 = s.addr[3] + if !DEBUG_LOOPBACK + t = s.getsockname.unpack("x8 x12 C4") + dest4 = "#{t[0]}.#{t[1]}.#{t[2]}.#{t[3]}" + port4 = s.addr[1] + else + dest4 = "127.0.0.1" + port4 = "ftp" + end + if DEBUG + STDERR.print "IPv6 dest: #{dest6} IPv4 dest: #{dest4}\n" if DEBUG + end + STDERR.print "connect to #{dest4} #{port4}\n" if DEBUG + s4 = TCPsocket.open(dest4, port4) + STDERR.print "connected to #{dest4} #{port4}, #{s4.addr[1]}\n" if DEBUG + state = 0 + while TRUE + # translate status line + state = relay_ftp_status(s4, s6, state) + break if state == nil + # translate command line + state = relay_ftp_command(s6, s4, state) + break if state == nil + end + STDERR.print "relay_ftp(#{sock}, #{name}) closing s4\n" if DEBUG + s4.close + STDERR.print "relay_ftp(#{sock}, #{name}) closing s6\n" if DEBUG + s6.close + STDERR.print "relay_ftp(#{sock}, #{name}) done\n" if DEBUG + end + end + STDERR.print "relay_ftp(#{sock}, #{name}) finished\n" if DEBUG +end + +def relay_tcp(sock, name) + STDERR.print "relay_tcp(#{sock}, #{name})\n" if DEBUG + while TRUE + STDERR.print "relay_tcp(#{sock}, #{name}) accepting\n" if DEBUG + s = sock.accept + STDERR.print "relay_tcp(#{sock}, #{name}) accepted #{s}\n" if DEBUG + Thread.start do + threads = [] + STDERR.print "accepted #{s} -> #{Thread.current}\n" if DEBUG + s6 = s + dest6 = s.addr[3] + if !DEBUG_LOOPBACK + t = s.getsockname.unpack("x8 x12 C4") + dest4 = "#{t[0]}.#{t[1]}.#{t[2]}.#{t[3]}" + port4 = s.addr[1] + else + dest4 = "127.0.0.1" + port4 = "telnet" + end + if DEBUG + STDERR.print "IPv6 dest: #{dest6} IPv4 dest: #{dest4}\n" if DEBUG + end + STDERR.print "connect to #{dest4} #{port4}\n" if DEBUG + s4 = TCPsocket.open(dest4, port4) + STDERR.print "connected to #{dest4} #{port4}, #{s4.addr[1]}\n" if DEBUG + [0, 1].each do |i| + threads[i] = Thread.start do + if (i == 0) + tcpcopy(s6, s4) + else + tcpcopy(s4, s6) + end + end + end + STDERR.print "relay_tcp(#{sock}, #{name}) wait\n" if DEBUG + for i in threads + STDERR.print "relay_tcp(#{sock}, #{name}) wait #{i}\n" if DEBUG + i.join + STDERR.print "relay_tcp(#{sock}, #{name}) wait #{i} done\n" if DEBUG + end + STDERR.print "relay_tcp(#{sock}, #{name}) closing s4\n" if DEBUG + s4.close + STDERR.print "relay_tcp(#{sock}, #{name}) closing s6\n" if DEBUG + s6.close + STDERR.print "relay_tcp(#{sock}, #{name}) done\n" if DEBUG + end + end + STDERR.print "relay_tcp(#{sock}, #{name}) finished\n" if DEBUG +end + +def usage() + STDERR.print "usage: #{$0} [-f] port...\n" +end + +#------------------------------------------------------------ + +$mode = "tcp" + +while ARGV[0] =~ /^-/ do + case ARGV[0] + when /^-f/ + $mode = "ftp" + else + usage() + exit 0 + end + ARGV.shift +end + +if ARGV.length == 0 + usage() + exit 1 +end + +ftpport = Socket.getservbyname("ftp") + +res = [] +for port in ARGV + t = Socket.getaddrinfo(nil, port, Socket::PF_INET6, Socket::SOCK_STREAM, + nil, Socket::AI_PASSIVE) + if (t.size <= 0) + STDERR.print "FATAL: getaddrinfo failed (port=#{port})\n" + exit 1 + end + res += t +end + +sockpool = [] +names = [] +listenthreads = [] + +res.each do |i| + s = TCPserver.new(i[3], i[1]) + n = Socket.getnameinfo(s.getsockname, Socket::NI_NUMERICHOST|Socket::NI_NUMERICSERV).join(" port ") + if i[6] == IPPROTO_IPV6 + s.setsockopt(i[6], IPV6_FAITH, 1) + end + s.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1) + sockpool.push s + names.push n +end + +if DEBUG + (0 .. sockpool.size - 1).each do |i| + STDERR.print "listen[#{i}]: #{sockpool[i]} #{names[i]}\n" if DEBUG + end +end + +(0 .. sockpool.size - 1).each do |i| + listenthreads[i] = Thread.start do + if DEBUG + STDERR.print "listen[#{i}]: thread #{Thread.current}\n" if DEBUG + end + STDERR.print "listen[#{i}]: thread #{Thread.current}\n" if DEBUG + case $mode + when "tcp" + relay_tcp(sockpool[i], names[i]) + when "ftp" + relay_ftp(sockpool[i], names[i]) + end + end +end + +for i in listenthreads + i.join +end + +exit 0 |