Upnpsync
upnpsync是个小脚本。主要用来同步路由器的UPnP转发信息和Cable Modem的转发信息。
最近在Time Warner的Cable Modem后面搞了个无线路由。之后又给这个路由刷了dd-wrt。 虽然一切都不错,但是对于要用UPnP进行端口转发的程序来说,因为它只会通过UPnP让路由转发,没有通知Cable Modem,导致它即使设置了端口转发,外网还是无法连接到它监听的端口。
网络结构是:
Internet <-> <74.73.xx.xx> [Time Warner Cable Modem] <192.168.0.1> <-> <192.168.0.x> [DLink Wireless Router] <192.168.1.1> <-> <192.168.1.x> [My Computer]
Time Warnar那个破Modem居然连配置都没法配,所有配置界面都锁死了,直接filter了23,80端口……
幸好它居然留着UPnP。端口扫描扫出来5555和8081俩端口,尝试了一下,http://192.168.0.1:5555/ 就是它的UPnP地址……
于是搞了个小脚本,可以根据无线路由上UPnP的端口转发信息,在Cable Modem上用UPnP自动配好对应的端口转发~
#!/usr/bin/perl
sub get_external($) {
my ($url) = @_;
$_ = `upnpc -u $url -s | grep External`;
/ExternalIPAddress = ([0-9\.]+)+/;
return $1;
}
sub get_fwd_list($) {
my ($url) = @_;
$_ = `upnpc -u $url -l | grep '\\\->'`;
foreach $line(split(/\n/))
{
if ($line =~ m/\s+(\d+)\s+([A-Za-z]+)\s+(\d+)->([0-9\.]+):(\d+)\s+'(.*)'\s+'(.*)'/)
{
# print "No.$1 Proto:$2 Ext.Port:$3 LocalIP:$4 LocalPort:$5 Desc:$6 Note:$7\n";
$result[$1] = {"proto"=>$2, "extport"=>$3, "localip"=>$4, "localport"=>$5, "desc"=>$6, "note"=>$7};
}
}
return @result;
}
$router_ip = "192.168.1.1";
$modem_ip = "192.168.0.1";
$router_upnp = "http://192.168.1.1:1780/InternetGatewayDevice.xml";
$modem_upnp = "http://192.168.0.1:5555/";
$router_external = get_external($router_upnp);
$modem_external = get_external($modem_upnp);
@router_fwd = get_fwd_list($router_upnp);
@modem_fwd = get_fwd_list($modem_upnp);
print "Modem External IP: $modem_external\n";
print "Router External IP: $router_external\n";
foreach $router_pair (@router_fwd)
{
$proto = $router_pair->{"proto"};
$extport = $router_pair->{"extport"};
$found = 0;
$good_pair = "";
print "Router: $proto $router_external:$extport -> $router_pair->{'localip'}:$router_pair->{'localport'}";
foreach $modem_pair (@modem_fwd)
{
if ($modem_pair->{"proto"} eq $proto
and $modem_pair->{"localport"} == $extport)
{
$found = 1;
$good_pair = $modem_pair;
if ($modem_pair->{"localip"} ne $router_external)
{
$modem_local = $modem_pair->{"localip"};
print "\nWarning: Modem forwarding to strange IP: $modem_local\n";
}
}
}
if (not $found)
{
print "... Not found!\n";
$ret = `upnpc -u $modem_upnp -a $router_external $extport $extport $proto`;
if ($? != 0)
{
print "ERROR adding port forwarding pair!\n";
print $ret;
} else {
print "Added forwarding $proto $modem_external:$extport->$router_external:$extport\n";
}
} else {
print "... Found\n";
print "Modem: $good_pair->{'proto'} $modem_external:$good_pair->{'extport'} -> $good_pair->{'localip'}:$good_pair->{'localport'}\n";
}
}
这里的router_ip和modem_ip都是对内IP,应该都很清楚。
router_upnp和modem_upnp都是对应设备的UPnP地址。可以通过在计算机与该设备直连的情况下,用upnpc -l发现出来(自动发现还是不太靠谱啊……)。