Subversion Repositories vgwhois

Rev

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