[savepoint] default tip
authorMatthias Förste <foerste@schlittermann.de>
Mon, 29 Aug 2022 16:04:38 +0200
changeset 6 7e4d3e9075c6
parent 5 0b0e57cd2ce9
[savepoint]
dnsproxy
--- a/dnsproxy	Mon Aug 26 14:20:16 2013 +0200
+++ b/dnsproxy	Mon Aug 29 16:04:38 2022 +0200
@@ -30,7 +30,8 @@
 
 my $opts = {
     listen => ['127.0.0.2'],
-    port   => 53
+    port   => 53,
+    tcp_timeout => 30,
 };
 
 GetOptions(
@@ -50,11 +51,12 @@
 my $resolver = Net::DNS::Resolver->new;
 my %args     = (
     host         => $opts->{listen},
-    port         => "$opts->{port}/udp",
+    port         => [ "$opts->{port}/udp", "$opts->{port}/tcp" ],
     log_file     => 'Sys::Syslog',
     syslog_ident => $ME,
     pid_file     => "/var/run/$ME.pid",
-    background   => 1
+    background   => 1,
+    no_client_stdout => 1
 );
 $args{log_level} = $opts->{verbose} if defined $opts->{verbose};
 dnsproxy->run(%args);
@@ -64,32 +66,90 @@
     my $self = shift;
     my $prop = $self->{server};
 
-    die 'Sorry, udp only!' unless $prop->{udp_true};
+    my $data;
+    if ($prop->{udp_true}) {
+        $data = $prop->{udp_data};
+    # assuming tcp
+    } else {
+
+        #use Socket qw(IPPROTO_TCP);
+        use Fcntl qw(O_NONBLOCK);
 
-    my ($q, $e) = Net::DNS::Packet->new(\$prop->{udp_data});
-    die "Sorry: $e" unless defined $q;
+        $prop->{client}->sockopt(O_NONBLOCK, 0)
+            or die "Can't sockopt: $!";
+        $prop->{client}->recv($data, 0)
+            or die "Can't recv: $!";
+        my $l = unpack 'n', substr($data, 0, 2);
+        substr($data, 0, 2) = '';
+        die "Incomplete data" unless $l = length $data;
+#        eval {
+#
+#            local $SIG{'ALRM'} = sub { die "Timed Out!\n" };
+#            my $timeout = 30; # give the client 30 seconds to send its data
+#
+#            my $previous_alarm = alarm($opts->{tcp_timeout});
+#            # first 2 bytes are the length for tcp queries
+#$self->log(1, __LINE__);
+#            my $r = read STDIN, my $l, 2;
+#$self->log(1, __LINE__);
+#            die "Error reading data: $!" unless defined $r and $r == 2;
+#            die "No data received" unless $r;
+#$self->log(1, __LINE__);
+#            my $len = unpack('n', $l);
+#            $r = read STDIN, $data, unpack('n', $len);
+#$self->log(1, __LINE__);
+#            die "Error reading data: $!" unless defined $r and $r == $len;
+#            die "No data received" unless $r;
+#$self->log(1, "$r/$len");
+#$self->log(1, __LINE__);
+#            alarm($previous_alarm);
+#
+#        };
+#
+#        if ($@) {
+#            $self->log(1, $@);
+#            print STDERR $@;
+#            return;
+#        }
+#
+    }
 
-    my $r;
-    my @q = $q->question;
-    die 'Sorry, single question only!' unless @q == 1;
+    my ($request, $e) = Net::DNS::Packet->new(\$data);
+    unless (defined $request) {
+        $self->log(1, "Sorry: $e");
+        return;
+    }
+
+    my $reply;
+    my @q = $request->question;
+    unless (@q == 1) {
+        $self->log(1, "Sorry: $e");
+        return;
+    }
 
     # we don't know when shell may fix their dns servers so we answer for them
     if ($q[0]->qtype eq 'AAAA' and $q[0]->qname =~ /(^|\.)shell\.com/) {
-        $r = $q;
-        $r->header->qr(1);
-        $r->header->ra(1);
+        $reply = $request;
+        $reply->header->qr(1);
+        $reply->header->ra(1);
 
         # everything else is just forwarded to our regular resolver
     } else {
-        $r = $resolver->send($q);
+        $reply = $resolver->send($request);
     }
 
     # trigger parsing of nonquestion sections because 'data' would return only
     # the question section(s) otherwise (TODO: Bug report against
     # Net::DNS::Packet)
-    $r->string;
+    $reply->string;
 
-    $prop->{client}->send($r->data, 0);
+    if ($prop->{udp_true}) {
+        $prop->{client}->send($reply->data, 0);
+    # assuming tcp
+    } else {
+        my $d = $reply->data;
+        print pack('n', length $d), $d;
+    }
 
 }