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