Subversion Repositories vgwhois

Rev

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);