Rev 5 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
2 | daniel-mar | 1 | #!/usr/bin/perl |
2 | |||
3 | # |
||
11 | daniel-mar | 4 | # VGWhoIs (ViaThinkSoft Global WhoIs, a fork of generic Whois / gwhois) |
5 | daniel-mar | 5 | # Subprogram: Teredo Decoder |
2 | daniel-mar | 6 | # |
5 | daniel-mar | 7 | # (c) 2012 by Daniel Marschall, ViaThinkSoft <info@daniel-marschall.de> |
2 | daniel-mar | 8 | # |
5 | daniel-mar | 9 | # License: https://www.gnu.org/licenses/gpl-2.0.html (GPL version 2) |
2 | daniel-mar | 10 | # |
11 | |||
12 | # todo: möglichkeit geben, den prefix-check per CLI zu deaktivieren |
||
13 | |||
14 | use warnings; |
||
15 | use strict; |
||
16 | |||
17 | my $prefix_check = 1; |
||
18 | |||
19 | # install with "cpan Net::IP" |
||
20 | use Net::IP qw(ip_expand_address); |
||
21 | |||
22 | use Net::DNS; |
||
23 | |||
24 | sub parse_teredo_ipv6 { |
||
25 | # See: http://en.wikipedia.org/wiki/Teredo_tunneling#IPv6_addressing |
||
26 | |||
27 | my ($ipv6_addr) = @_; |
||
28 | |||
29 | $ipv6_addr = ip_expand_address($ipv6_addr, 6); |
||
30 | |||
31 | my ($prefix, $teredo_server, $flags, $udp_port, $client_ipv4) |
||
32 | = $ipv6_addr =~ /([0-9a-f]{4}:[0-9a-f]{4}):([0-9a-f]{4}:[0-9a-f]{4}):([0-9a-f]{4}):([0-9a-f]{4}):([0-9a-f]{4}:[0-9a-f]{4})/i; |
||
33 | |||
34 | return ($ipv6_addr, "") if !defined $prefix; |
||
35 | return ($ipv6_addr, $prefix) if $prefix_check && ($prefix ne "2001:0000") && ($prefix ne "3ffe:831f"); |
||
36 | |||
37 | # $teredo_server=~ s/://; |
||
38 | $teredo_server = hex2ip4($teredo_server); |
||
39 | |||
40 | # MSB first, is "CRAAAAUG AAAAAAAA", |
||
41 | # where "C" remains the "Cone NAT" flag |
||
42 | # The "R" bit is reserved for future use |
||
43 | # The "U" bit is for the Universal/Local flag (set to 0). |
||
44 | # The "G" bit is Individual/Group flag (set to 0). |
||
45 | # The A bits are set to a 12-bit randomly generated number |
||
46 | # chosen by the Teredo client to introduce additional protection |
||
47 | # for the Teredo node against IPv6-based scanning attacks. |
||
48 | $flags = hex($flags); |
||
49 | my $flag_cone_nat = ($flags & 0x8000) == 0x8000 ? 1 : 0; |
||
50 | my $flag_reserved = ($flags & 0x4000) == 0x4000 ? 1 : 0; |
||
51 | my $flag_universal_local = ($flags & 0x0200) == 0x0200 ? 1 : 0; |
||
52 | my $flag_individual_group = ($flags & 0x0100) == 0x0100 ? 1 : 0; |
||
53 | my $flag_random_12bit = (($flags & 0x3C00) >> 2) | ($flags & 0x00FF); |
||
54 | |||
55 | $udp_port = hex($udp_port) ^ 0xFFFF; # decode |
||
56 | |||
57 | $client_ipv4 =~ s/://; |
||
58 | $client_ipv4 = sprintf('%x', hex($client_ipv4) ^ 0xFFFFFFFF); # decode |
||
59 | $client_ipv4 = hex2ip4($client_ipv4); |
||
60 | |||
61 | return ($ipv6_addr, $prefix, $teredo_server, $flags, $flag_cone_nat, $flag_reserved, |
||
62 | $flag_universal_local, $flag_individual_group, |
||
63 | $flag_random_12bit, $udp_port, $client_ipv4); |
||
64 | } |
||
65 | |||
66 | sub print_teredo_info { |
||
67 | my ($ipv6_addr, $prefix, $teredo_server, $flags, $flag_cone_nat, $flag_reserved, |
||
68 | $flag_universal_local, $flag_individual_group, |
||
69 | $flag_random_12bit, $udp_port, $client_ipv4) = @_; |
||
70 | |||
71 | if ($prefix_check && ($prefix ne "2001:0000") && ($prefix ne "3ffe:831f")) { |
||
72 | print "Invalid Teredo address $ipv6_addr\n"; |
||
73 | return; |
||
74 | } |
||
75 | |||
76 | my @revdns; |
||
77 | print "Teredo IPv6 address: ", $ipv6_addr, "\n"; |
||
78 | # Is "2001:0000" or "3ffe:831f" (deprecated) |
||
79 | print "Teredo prefix: ", $prefix, "\n"; |
||
80 | print "Teredo server: ", $teredo_server, "\n"; |
||
81 | @revdns = revdns_ipv4($teredo_server); |
||
82 | foreach my $addr (@revdns) { |
||
83 | print " $addr\n"; |
||
84 | } |
||
85 | print "Flags: ", $flags, "\n"; |
||
86 | print " Cone NAT flag: ", $flag_cone_nat, "\n"; |
||
87 | print " Reserved flag: ", $flag_reserved, "\n"; |
||
88 | print " Universal/Local flag: ", $flag_universal_local, "\n"; |
||
89 | print " Individual/Group flag: ", $flag_individual_group, "\n"; |
||
90 | print " Random 12 bits: ", $flag_random_12bit, "\n"; # 0..4095 |
||
91 | print "Client UDP port: ", $udp_port, "\n"; |
||
92 | print "Client public IPv4: ", $client_ipv4, "\n"; |
||
93 | @revdns = revdns_ipv4($client_ipv4); |
||
94 | foreach my $addr (@revdns) { |
||
95 | print " $addr\n"; |
||
96 | } |
||
97 | } |
||
98 | |||
99 | sub hex2ip4 { |
||
100 | my ($hex) = @_; |
||
101 | $hex =~ s/[^0-9a-f]//i; |
||
102 | my ($ip4a, $ip4b, $ip4c, $ip4d) = $hex =~ /([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})/i; |
||
103 | $ip4a = hex($ip4a); |
||
104 | return if !defined $ip4a; |
||
105 | $ip4b = hex($ip4b); |
||
106 | return if !defined $ip4b; |
||
107 | $ip4c = hex($ip4c); |
||
108 | return if !defined $ip4c; |
||
109 | $ip4d = hex($ip4d); |
||
110 | return if !defined $ip4d; |
||
111 | return "$ip4a.$ip4b.$ip4c.$ip4d"; |
||
112 | } |
||
113 | |||
114 | sub revdns_ipv4 { |
||
115 | # Source: http://stackoverflow.com/questions/85487/reverse-dns-lookup-in-perl |
||
116 | |||
117 | my ($ipv4) = @_; |
||
118 | |||
119 | my $res = Net::DNS::Resolver->new; |
||
120 | |||
121 | # create the reverse lookup DNS name (note that the octets in the IP address need to be reversed). |
||
122 | my $target_IP = join('.', reverse split(/\./, $ipv4)).".in-addr.arpa"; |
||
123 | |||
124 | my @out = qw(); |
||
125 | |||
126 | my $query = $res->query("$target_IP", "PTR"); |
||
127 | |||
128 | if ($query) { |
||
129 | foreach my $rr ($query->answer) { |
||
130 | next unless $rr->type eq "PTR"; |
||
131 | push (@out, $rr->rdatastr); |
||
132 | } |
||
133 | } else { |
||
134 | # warn "Reverse DNS query failed: ", $res->errorstring, "\n"; |
||
135 | push (@out, "Reverse DNS query failed: ".$res->errorstring."\n"); |
||
136 | } |
||
137 | |||
138 | return @out; |
||
139 | } |
||
140 | |||
141 | if ($ARGV[0]) { |
||
142 | $_ = join(' ',@ARGV); |
||
143 | } else { |
||
144 | $_ = <>; |
||
145 | chomp; |
||
146 | } |
||
147 | |||
148 | my @info = parse_teredo_ipv6($_); |
||
149 | print_teredo_info(@info); |