|
Joined: Dec 2002
Posts: 153
Vogon poet
|
OP
Vogon poet
Joined: Dec 2002
Posts: 153 |
I'm in the process of making a DLL-free script that uses the port mapping (forwarding) feature of UPnP-enabled Internet Gateways (routers) for Identd and DCC.
It's already working with Identd (with my NETGEAR router, at least) by opening the Identd port on ^LOGIN and closing it on CONNECT.
The thing is that I need some ideas on how to make it work with DCC sends, since I need to know the port that mIRC is listening on (to open it) before the connection is established, and then which port was used (to close it) after the connection ends or fails.
Thanks to the fact that $send doesn't have a "localport" property, so far, I've only thought of capturing the DCC Send PRIVMSG with a "/debug" window to extract the port mIRC is listening on and then close the port on FILESENT or SENDFAIL (somehow finding out which port was used), but this doesn't convince me entirely.
Can somebody give me a better DLL-free idea?
|
|
|
|
FaiNT
|
FaiNT
|
one, i'm gonna want that script, i could use it.
1st off, once the connection has been made. u dont need the port mapped. so doing it on /debug, and waiting 30 secs won't break the send.
FYI: not sure if u know this but the dcc raw format goes like this: PRIVMSG NICK : $+ $chr(1) $+ DCC SEND filename ipaddress port filesize
with the ip address being in long format.
|
|
|
|
Joined: Dec 2002
Posts: 153
Vogon poet
|
OP
Vogon poet
Joined: Dec 2002
Posts: 153 |
1st off, once the connection has been made. u dont need the port mapped. so doing it on /debug, and waiting 30 secs won't break the send. Thanks. I finished the script yesterday (to some extent) and instead of waiting 30 seconds, I "unmap" the port immediately after the connection is established. Here is the script that works for basic needs with my NETGEAR router: ;UPnP Script v1.0
alias upnp.debugpermanent {
if ($isid) return $false
}
on *:start: {
upnp.start
if ($upnp.debugpermanent) .debug -i upnp.dcc upnp.dccdebug
}
on *:unload: {
unset %upnp.*
}
on *:exit: {
unset %upnp.*
}
on ^*:logon:*: {
if ($readini($mircini,ident,active) == yes) upnp.addPortMapping $readini($mircini,ident,port)
set %upnp.IdentdMap $true
}
on *:error:*: {
if ($readini($mircini,ident,active) == yes) && (%upnp.IdentdMap) upnp.delPortMapping $readini($mircini,ident,port)
}
on *:connect: {
if ($readini($mircini,ident,active) == yes) upnp.delPortMapping $readini($mircini,ident,port)
unset %upnp.IdentdMap
}
alias debug {
if ((%upnp.debuguse) || ($upnp.debugpermanent)) && ($gettok($debug,-1,92) == upnp.dcc) {
linesep $iif($active == Status Window,-s,$active)
echo -a -UPNP- Debug is in use.
linesep $iif($active == Status Window,-s,$active)
}
else {
debug $1-
if ($0 > 0) set %upnp.debugparams $$1-
}
}
alias upnp.dccgetnum {
if (!$isid) return
var %i = 0
if ($$1 == send) {
while (%i <= $send(0)) {
if ($send(%i).wid == $$2) return %i
inc %i
}
}
else {
while (%i <= $chat(0)) {
if ($chat(%i).wid == $$2) return %i
inc %i
}
}
return 0
}
alias upnp.dcccheck {
var %upnp.dccnum = $upnp.dccgetnum($1,$$2)
var %upnp.dccstatus = $iif($1 == send,$send(%upnp.dccnum).status,$chat(%upnp.dccnum).status)
if ($istok(failed:active:sent:inactive,%upnp.dccstatus,58)) || (%upnp.dccnum == 0) {
.timerupnp.dcc $+ $$3 off
upnp.delPortMapping $3
}
}
alias upnp.dccdebug {
tokenize 32 $1-
if ($1 != ->) return
if ($istok($+(:,$chr(1),DCC SEND,/,:,$chr(1),DCC CHAT),$5-6,47)) {
var %upnp.debugport = $remove($9,$chr(1))
upnp.addPortMapping %upnp.debugport
.timerupnp.dcc $+ %upnp.debugport 0 0 upnp.dcccheck $6 $iif($6 == send,$send($send($4,0)).wid,$chat($chat($4,0)).wid) %upnp.debugport
if (!$upnp.debugpermanent) {
unset %upnp.debuguse
.debug off
if (%upnp.debugbefore) {
.debug %upnp.debugparamsbefore
unset %upnp.debugbefore
unset %upnp.debugparamsbefore
}
}
}
return
}
alias dcc {
if ($isid) return
if ($istok(send:chat,$1,58)) && (!$upnp.debugpermanent) {
if ($debug != $null) {
set %upnp.debugparamsbefore %upnp.debugparams
.debug off
set %upnp.debugbefore $true
}
unset %upnp.dccdebuguse
.debug -i upnp.dcc upnp.dccdebug
set %upnp.debuguse $true
}
if ($gettok($debug,-1,92) != upnp.dcc) && ($upnp.debugpermanent) {
.debug -i upnp.dcc upnp.dccdebug
}
dcc $1-
}
alias upnp.start {
unset %upnp.*
var %upnp.discip = 239.255.255.250
var %upnp.disclocalport = $rand(10000,63999)
while (!$portfree(%upnp.disclocalport)) {
%upnp.disclocalport = $rand(10000,63999)
}
echo $color(other) -gs -UPnP- Searching for Internet Gateway...
sockclose upnp.discover
sockudp -kt upnp.discover %upnp.disclocalport %upnp.discip 1900 $+(M-SEARCH * HTTP/1.1,$crlf,Host: 239.255.255.250:1900,$crlf,Man: "ssdp:discover",$crlf,ST: urn:schemas-upnp-org:service:WANIPConnection:1,$crlf,MX: 2,$str($crlf,2))
sockudp -kt upnp.discover %upnp.disclocalport %upnp.discip 1900
sockudp -kt upnp.discover %upnp.disclocalport %upnp.discip 1900 $+(M-SEARCH * HTTP/1.1,$crlf,Host: 239.255.255.250:1900,$crlf,Man: "ssdp:discover",$crlf,ST: urn:schemas-upnp-org:service:WANPPPConnection:1,$crlf,MX: 2,$str($crlf,2))
sockudp -kt upnp.discover %upnp.disclocalport %upnp.discip 1900
}
alias upnp.getLocalInfo {
set %upnp.localprevip $ip
set %upnp.localprevhost $host
unset %upnp.localticks
.localinfo -h
.timerupnp.localip off
set %upnp.localtimeout 5000
set %upnp.localticks $ticks
.timerupnp.localip 0 0 upnp.getLocalInfo.2
}
alias upnp.getLocalInfo.2 {
set %upnp.localip $ip
if (%upnp.localip == $null) {
if ($calc($ticks - %upnp.localticks) > %upnp.localtimeout) {
echo $color(other) -gs -UPnP- Local IP not found
.timerupnp.localip off
if (%upnp.localprevip != $null) {
.localinfo $iif(%upnp.localprevhost == $null,%upnp.localprevip,%upnp.localprevhost) %upnp.localprevip
}
}
}
else {
echo $color(other) -gs -UPnP- Local IP: $ip
.timerupnp.localip off
if (%upnp.localprevip != $null) {
.localinfo $iif(%upnp.localprevhost == $null,%upnp.localprevip,%upnp.localprevhost) %upnp.localprevip
}
}
}
on *:udpread:upnp.discover: {
if ($sockerr > 0) return
sockread %info
while ($sockbr > 0) {
tokenize 32 %info
if ($1 == $null) {
echo $color(other) -gs -UPnP- Internet Gateway with %upnp.st service found at $sock($sockname).saddr
upnp.getLocalInfo
upnp.getDeviceInfo %upnp.discURL
sockclose $sockname
return
}
if ($gettok($1,1,58) == LOCATION) set %upnp.discURL $remove($gettok($1-,2-,58),$chr(32))
if ($gettok($1,1,58) == ST) set %upnp.st $remove($gettok($1-,2-,58),$chr(32))
sockread %info
}
}
alias upnp.getDeviceInfo {
echo $color(other) -gs -UPnP- Getting Service Info...
var %upnp.devip = $gettok($gettok($$1,2,47),1,58)
var %upnp.devport = $gettok($gettok($1,2,47),2,58)
sockclose upnp.devinfo
sockopen upnp.devinfo %upnp.devip %upnp.devport
sockmark upnp.devinfo $+($chr(47),$gettok($1,3-,47))
}
on 1:sockopen:upnp.devinfo: {
if ($sockerr > 0) return
set %upnp.devinfoMode HTTP
set %upnp.getCURL $false
sockwrite -nt $sockname GET $sock($sockname).mark HTTP/1.1
sockwrite -nt $sockname Host: $+($sock($sockname).ip,$chr(58),$sock($sockname).port)
sockwrite -nt $sockname Connection: close
sockwrite -nt $sockname Accept-Language: en
sockwrite -nt $sockname
}
on 1:sockread:upnp.devinfo: {
if ($sockerr > 0) return
sockread %info
while ($sockbr > 0) {
tokenize 32 %info
if (%upnp.devinfoMode == XML) {
if (<URLBase> isin $1-) {
set %upnp.servinfoBase $upnp.getXMLValue($1-,<URLBase>)
echo $color(other) -gs -UPnP- Service Base URL: %upnp.servinfoBase
}
if (!%upnp.getCURL) {
if ($+(<serviceType>,%upnp.st,</serviceType>) isin $1-) set %upnp.getCURL $true
}
if (%upnp.getCURL) {
if (<controlURL> isin $1-) {
set %upnp.servinfoURL $upnp.getXMLValue($1-,<controlURL>)
set %upnp.getCURL $false
echo $color(other) -gs -UPnP- Service Control URL: %upnp.servinfoURL
upnp.getServiceExternalIP $+(%upnp.servinfoBase,%upnp.servinfoURL)
}
}
}
if ($1 == $null) && (%upnp.devinfoMode == HTTP) set %upnp.devinfoMode XML
sockread %info
}
}
alias upnp.getServiceExternalIP {
echo $color(other) -gs -UPnP- Getting Service External IP Address...
var %upnp.servip = $gettok($gettok($$1,2,47),1,58)
var %upnp.servport = $gettok($gettok($1,2,47),2,58)
sockclose upnp.servIP
sockopen upnp.servIP %upnp.servip %upnp.servport
sockmark upnp.servIP $+($chr(47),$gettok($1,3-,47))
}
on 1:sockopen:upnp.servIP: {
if ($sockerr > 0) return
set %upnp.servIPMode HTTP
sockwrite -nt $sockname POST $sock($sockname).mark HTTP/1.1
sockwrite -nt $sockname Host: $+($sock($sockname).ip,$chr(58),$sock($sockname).port)
sockwrite -nt $sockname Connection: close
sockwrite -nt $sockname Content-Length: $iif(PPP isin %upnp.st,273,272)
sockwrite -nt $sockname Content-Type: text/xml; charset="utf-8"
sockwrite -nt $sockname SOAPAction: $+(",%upnp.st,#GetExternalIPAddress")
sockwrite -nt $sockname
sockwrite -nt $sockname <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
sockwrite -nt $sockname <s:Body>
sockwrite -nt $sockname $+(<u:GetExternalIPAddress xmlns:u=",%upnp.st,"></u:GetExternalIPAddress>)
sockwrite -nt $sockname </s:Body>
sockwrite -nt $sockname </s:Envelope>
sockwrite -nt $sockname
}
on 1:sockread:upnp.servIP: {
if ($sockerr > 0) return
sockread %info
while ($sockbr > 0) {
tokenize 32 %info
if (%upnp.servIPMode == XML) {
if (<NewExternalIPAddress> isin $1-) {
set %upnp.externalIP $upnp.getXMLValue($1-,<NewExternalIPAddress>)
echo $color(other) -gs -UPnP- Service External IP Address: %upnp.externalIP
}
}
if ($1 == $null) && (%upnp.servIPMode == HTTP) set %upnp.servIPMode XML
sockread %info
}
}
alias upnp.addPortMapping {
var %upnp.lp = $iif($0 > 1,$2,$$1)
var %upnp.curl = $iif($0 > 1,$1,$+(%upnp.servinfoBase,%upnp.servinfoURL))
if (%upnp.localip == $null) {
echo $color(other) -gs -UPnP- Cannot map port %upnp.lp $+ . Local IP Address is unknown
return
}
echo $color(other) -gs -UPnP- Mapping port %upnp.lp to %upnp.localip $+ ...
var %upnp.pmi = $gettok($gettok(%upnp.curl,2,47),1,58)
var %upnp.pmp = $gettok($gettok(%upnp.curl,2,47),2,58)
set %upnp.pmport %upnp.lp
set %upnp.pmlease 0
sockclose upnp.pm
sockopen upnp.pm %upnp.pmi %upnp.pmp
sockmark upnp.pm $+($chr(47),$gettok(%upnp.curl,3-,47))
}
on 1:sockopen:upnp.pm: {
if ($sockerr > 0) return
set %upnp.pmMode HTTP
sockwrite -nt $sockname POST $sock($sockname).mark HTTP/1.1
sockwrite -nt $sockname Host: $+($sock($sockname).ip,$chr(58),$sock($sockname).port)
sockwrite -nt $sockname Connection: close
sockwrite -nt $sockname Content-Length: $calc(533 + $len(%upnp.st) + ($len(%upnp.pmport) * 4) + ($len(%upnp.localip) * 2) + $len(%upnp.pmlease))
sockwrite -nt $sockname Content-Type: text/xml; charset="utf-8"
sockwrite -nt $sockname SOAPAction: $+(",%upnp.st,#AddPortMapping")
sockwrite -nt $sockname
sockwrite -nt $sockname <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
sockwrite -nt $sockname <s:Body>
sockwrite -nt $sockname $+(<u:AddPortMapping xmlns:u=",%upnp.st,">)
sockwrite -nt $sockname <NewRemoteHost></NewRemoteHost>
sockwrite -nt $sockname $+(<NewExternalPort>,%upnp.pmport,</NewExternalPort>)
sockwrite -nt $sockname <NewProtocol>TCP</NewProtocol>
sockwrite -nt $sockname $+(<NewInternalPort>,%upnp.pmport,</NewInternalPort>)
sockwrite -nt $sockname $+(<NewInternalClient>,%upnp.localip,</NewInternalClient>)
sockwrite -nt $sockname <NewEnabled>1</NewEnabled>
sockwrite -nt $sockname $+(<NewPortMappingDescription>mIRC $chr(40),%upnp.localip,:,%upnp.pmport,$chr(41),$chr(32),%upnp.pmport,$chr(32),TCP</NewPortMappingDescription>)
sockwrite -nt $sockname $+(<NewLeaseDuration>,%upnp.pmlease,</NewLeaseDuration>)
sockwrite -nt $sockname </u:AddPortMapping>
sockwrite -nt $sockname </s:Body>
sockwrite -nt $sockname </s:Envelope>
sockwrite -nt $sockname
}
on 1:sockread:upnp.pm: {
if ($sockerr > 0) return
sockread %info
while ($sockbr > 0) {
tokenize 32 %info
if (%upnp.pmMode == HTTP) {
if (HTTP/1.1 200 * iswm $1-) {
echo $color(other) -gs -UPnP- Port Mapping Added: $+(mIRC $chr(40),%upnp.localip,:,%upnp.pmport,$chr(41),$chr(32),%upnp.pmport,$chr(32),TCP,$chr(32))
sockclose $sockname
return
}
if (HTTP/1.1 500 * iswm $1-) {
echo $color(other) -gs -UPnP- Port Mapping Add Error
sockclose $sockname
return
}
if ($1 == $null) set %upnp.pmMode XML
}
if (%upnp.pmMode == XML) {
;if ($+(<u:AddPortMappingResponse xmlns:u=",%upnp.st,"/>) isin $1-) {
;}
}
sockread %info
}
}
alias upnp.delPortMapping {
var %upnp.lp = $iif($0 > 1,$2,$$1)
var %upnp.curl = $iif($0 > 1,$1,$+(%upnp.servinfoBase,%upnp.servinfoURL))
echo $color(other) -gs -UPnP- Deleting Port Mapping for port %upnp.lp $+ ...
var %upnp.pmdi = $gettok($gettok(%upnp.curl,2,47),1,58)
var %upnp.pmdp = $gettok($gettok(%upnp.curl,2,47),2,58)
set %upnp.pmdport %upnp.lp
sockclose upnp.pmd
sockopen upnp.pmd %upnp.pmdi %upnp.pmdp
sockmark upnp.pmd $+($chr(47),$gettok(%upnp.curl,3-,47))
}
on 1:sockopen:upnp.pmd: {
if ($sockerr > 0) return
set %upnp.pmdMode HTTP
sockwrite -nt $sockname POST $sock($sockname).mark HTTP/1.1
sockwrite -nt $sockname Host: $+($sock($sockname).ip,$chr(58),$sock($sockname).port)
sockwrite -nt $sockname Connection: close
sockwrite -nt $sockname Content-Length: $calc(324 + $len(%upnp.st) + $len(%upnp.pmport))
sockwrite -nt $sockname Content-Tupe: text/xml; charset="utf-8"
sockwrite -nt $sockname SOAPAction: $+(",%upnp.st,#DeletePortMapping")
sockwrite -nt $sockname
sockwrite -nt $sockname <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
sockwrite -nt $sockname <s:Body>
sockwrite -nt $sockname $+(<u:DeletePortMapping xmlns:u=",%upnp.st,">)
sockwrite -nt $sockname <NewRemoteHost></NewRemoteHost>
sockwrite -nt $sockname $+(<NewExternalPort>,%upnp.pmdport,</NewExternalPort>)
sockwrite -nt $sockname <NewProtocol>TCP</NewProtocol>
sockwrite -nt $sockname </u:DeletePortMapping>
sockwrite -nt $sockname </s:Body>
sockwrite -nt $sockname </s:Envelope>
sockwrite -nt $sockname
}
on 1:sockread:upnp.pmd: {
if ($sockerr > 0) return
sockread %info
while ($sockbr > 0) {
tokenize 32 %info
if (%upnp.pmdMode == HTTP) {
if (HTTP/1.1 200 * iswm $1-) {
echo $color(other) -gs -UPnP- Port Mapping Deleted for port %upnp.pmdport
sockclose $sockname
return
}
if (HTTP/1.1 500 * iswm $1-) {
echo $color(other) -gs -UPnP- Port Mapping Delete Error
sockclose $sockname
return
}
if ($1 == $null) set %upnp.pmdMode XML
}
if (%upnp.pmdMode == XML) {
;if ($+(<u:DeletePortMappingResponse xmlns:u=",%upnp.st,"/>) isin $1-) {
;}
}
sockread %info
}
}
alias upnp.getXMLValue {
if (!$isid) return
var %rest = $right($$1-,$calc(0 - ($pos($1-,$2) + $len($2) - 1)))
var %tag = $2
if ($pos(%rest,<) != 1) return $gettok(%rest,1,$asc(<))
else return $null
} The "upnp.addPortMapping <port>" and "upnp.delPortMapping <port>" are the two aliases that do the "magic". Please note that running the initialization commands is VITAL. I added a nice little feature: - If $upnp.debugpermanent (on top of the code) returns $true, then the script will take over and need to be using the output of /debug the whole time. - If $upnp.debugpermanent returns $false, the script will only take over /debug while waiting for the DCC message to be sent (in order to capture the port) and then it will restore /debug to its previous state (if it was activated), which allows it to coexist with other scripts that use /debug. When using this mode, you cannot use the "Resend" button after a DCC transfer fails, and you cannot use the DCC Send toolbar button to initiate a transfer, since mIRC won't trigger the /dcc custom alias. I've tried my best to test it, but it certainly does need a lot more of testing and error checking. For example, using "recycled" DCC Send/Chat windows will generate a conflict if there is a newer DCC Send/Chat window for the same nick. There are some things that should probably be added, like some popup menus to enable/disable it for DCC/Identd, a control list of ports that the script has open (to close them at any given time, because this script uses leases of "0", thanks to my router not supporting non-zero leases), an alias to close all the open ports (using the previous list) on EXIT so the don't stay permanently open, hash tables instead of variables, etc. Also, the XML parser might be a little "weak". - EDIT: Corrected a little important typo bug in "on 1:sockread:upnp.pm:"
Last edited by Strider; 07/04/07 11:23 PM.
|
|
|
|
Joined: Dec 2002
Posts: 153
Vogon poet
|
OP
Vogon poet
Joined: Dec 2002
Posts: 153 |
Oh, also. If everything goes well after the initialization, you will get an output like this one:
-UPnP- Searching for Internet Gateway... -UPnP- Internet Gateway with urn:schemas-upnp-org:service:WANIPConnection:1 service found at 192.168.1.1 -UPnP- Getting Service Info... -UPnP- Local IP: 192.168.111.111 -UPnP- Service Base URL: http://192.168.1.1:80/ -UPnP- Service Control URL: Public_UPNP_C3 -UPnP- Getting Service External IP Address... -UPnP- Service External IP Address: 111.111.111.111
|
|
|
|
Joined: Dec 2002
Posts: 153
Vogon poet
|
OP
Vogon poet
Joined: Dec 2002
Posts: 153 |
In case someone is still interested, I quit working on this script a couple of days after my last post in this topic, but here is my last version: ;UPnP Script v1.22
alias upnp.debugpermanent {
if ($isid) return $false
}
on *:start: {
upnp.start
if ($upnp.debugpermanent) .debug -i upnp.dcc upnp.dccdebug
}
on *:unload: {
unset %upnp.*
}
on *:exit: {
unset %upnp.*
}
on ^*:logon:*: {
if ($serverip == 84.16.238.88) halt
if ($readini($mircini,ident,active) == yes) upnp.addPortMapping TCP $readini($mircini,ident,port)
set %upnp.IdentdMap $true
}
on *:error:*: {
if ($serverip == 84.16.238.88) halt
if ($readini($mircini,ident,active) == yes) && (%upnp.IdentdMap) upnp.delPortMapping TCP $readini($mircini,ident,port)
}
on *:connect: {
if ($serverip == 84.16.238.88) halt
if ($readini($mircini,ident,active) == yes) upnp.delPortMapping TCP $readini($mircini,ident,port)
unset %upnp.IdentdMap
}
alias debug {
if ((%upnp.debuguse) || ($upnp.debugpermanent)) && ($gettok($debug,-1,92) == upnp.dcc) {
linesep $iif($active == Status Window,-s,$active)
echo -a -UPNP- Debug is in use.
linesep $iif($active == Status Window,-s,$active)
}
else {
debug $1-
if ($0 > 0) set %upnp.debugparams $$1-
}
}
alias upnp.dccgetnum {
if (!$isid) return
var %i = 0
if ($$1 == send) {
while (%i <= $send(0)) {
if ($send(%i).wid == $$2) return %i
inc %i
}
}
else {
while (%i <= $chat(0)) {
if ($chat(%i).wid == $$2) return %i
inc %i
}
}
return 0
}
alias upnp.dcccheck {
var %upnp.dccnum = $upnp.dccgetnum($1,$$2)
var %upnp.dccstatus = $iif($1 == send,$send(%upnp.dccnum).status,$chat(%upnp.dccnum).status)
if ($istok(failed:active:sent:inactive,%upnp.dccstatus,58)) || (%upnp.dccnum == 0) {
.timerupnp.dcc $+ $$3 off
upnp.delPortMapping TCP $3
}
}
alias upnp.dccdebug {
tokenize 32 $1-
if ($1 != ->) return
if ($istok($+(:,$chr(1),DCC SEND,/,:,$chr(1),DCC CHAT),$5-6,47)) {
var %upnp.debugport = $remove($9,$chr(1))
upnp.addPortMapping TCP %upnp.debugport
.timerupnp.dcc $+ %upnp.debugport 0 0 upnp.dcccheck $6 $iif($6 == send,$send($send($4,0)).wid,$chat($chat($4,0)).wid) %upnp.debugport
if (!$upnp.debugpermanent) {
unset %upnp.debuguse
.debug off
if (%upnp.debugbefore) {
.debug %upnp.debugparamsbefore
unset %upnp.debugbefore
unset %upnp.debugparamsbefore
}
}
}
return
}
alias dcc {
if ($isid) return
if ($istok(send:chat,$1,58)) && (!$upnp.debugpermanent) {
if ($debug != $null) {
set %upnp.debugparamsbefore %upnp.debugparams
.debug off
set %upnp.debugbefore $true
}
unset %upnp.dccdebuguse
.debug -i upnp.dcc upnp.dccdebug
set %upnp.debuguse $true
}
if ($gettok($debug,-1,92) != upnp.dcc) && ($upnp.debugpermanent) {
.debug -i upnp.dcc upnp.dccdebug
}
dcc $1-
}
alias upnp.start {
unset %upnp.*
var %upnp.discip = 239.255.255.250
var %upnp.disclocalport = $rand(10000,63999)
while (!$portfree(%upnp.disclocalport)) {
%upnp.disclocalport = $rand(10000,63999)
}
echo $color(other) -gs -UPnP- Searching for Internet Gateway...
sockclose upnp.discover
sockudp -kt upnp.discover %upnp.disclocalport %upnp.discip 1900 $+(M-SEARCH * HTTP/1.1,$crlf,Host: 239.255.255.250:1900,$crlf,Man: "ssdp:discover",$crlf,ST: urn:schemas-upnp-org:service:WANIPConnection:1,$crlf,MX: 2,$str($crlf,2))
sockudp -kt upnp.discover %upnp.disclocalport %upnp.discip 1900
sockudp -kt upnp.discover %upnp.disclocalport %upnp.discip 1900 $+(M-SEARCH * HTTP/1.1,$crlf,Host: 239.255.255.250:1900,$crlf,Man: "ssdp:discover",$crlf,ST: urn:schemas-upnp-org:service:WANPPPConnection:1,$crlf,MX: 2,$str($crlf,2))
sockudp -kt upnp.discover %upnp.disclocalport %upnp.discip 1900
}
alias upnp.getLocalInfo {
set %upnp.localprevip $ip
set %upnp.localprevhost $host
unset %upnp.localticks
.localinfo -h
.timerupnp.localip off
set %upnp.localtimeout 5000
set %upnp.localticks $ticks
.timerupnp.localip 0 0 upnp.getLocalInfo.2
}
alias upnp.getLocalInfo.2 {
set %upnp.localip $ip
if (%upnp.localip == $null) {
if ($calc($ticks - %upnp.localticks) > %upnp.localtimeout) {
echo $color(other) -gs -UPnP- Local IP not found
.timerupnp.localip off
if (%upnp.localprevip != $null) {
.localinfo $iif(%upnp.localprevhost == $null,%upnp.localprevip,%upnp.localprevhost) %upnp.localprevip
}
}
}
else {
echo $color(other) -gs -UPnP- Local IP: $ip
.timerupnp.localip off
if (%upnp.localprevip != $null) {
.localinfo $iif(%upnp.localprevhost == $null,%upnp.localprevip,%upnp.localprevhost) %upnp.localprevip
}
}
}
on *:udpread:upnp.discover: {
if ($sockerr > 0) return
sockread %info
while ($sockbr > 0) {
tokenize 32 %info
if ($1 == $null) {
echo $color(other) -gs -UPnP- Internet Gateway with %upnp.st service found at $sock($sockname).saddr
upnp.getLocalInfo
upnp.getDeviceInfo %upnp.discURL
sockclose $sockname
return
}
if ($gettok($1,1,58) == LOCATION) set %upnp.discURL $remove($gettok($1-,2-,58),$chr(32))
if ($gettok($1,1,58) == ST) set %upnp.st $remove($gettok($1-,2-,58),$chr(32))
sockread %info
}
}
alias upnp.getDeviceInfo {
echo $color(other) -gs -UPnP- Getting Service Info...
var %upnp.devip = $gettok($gettok($$1,2,47),1,58)
var %upnp.devport = $gettok($gettok($1,2,47),2,58)
sockclose upnp.devinfo
sockopen upnp.devinfo %upnp.devip %upnp.devport
sockmark upnp.devinfo $+($chr(47),$gettok($1,3-,47))
}
on 1:sockopen:upnp.devinfo: {
if ($sockerr > 0) return
set %upnp.devinfoMode HTTP
set %upnp.getCURL $false
sockwrite -nt $sockname GET $sock($sockname).mark HTTP/1.1
sockwrite -nt $sockname Host: $+($sock($sockname).ip,$chr(58),$sock($sockname).port)
sockwrite -nt $sockname Connection: close
sockwrite -nt $sockname Accept-Language: en
sockwrite -nt $sockname
}
on *:sockread:upnp.devinfo: {
if ($sockerr > 0) return
sockread %info
while ($sockbr > 0) {
tokenize 32 %info
if (%upnp.devinfoMode == XML) {
if (<URLBase> isin $1-) {
set %upnp.servinfoBase $upnp.getXMLValue($1-,<URLBase>)
echo $color(other) -gs -UPnP- Service Base URL: %upnp.servinfoBase
}
if (!%upnp.getCURL) {
if ($+(<serviceType>,%upnp.st,</serviceType>) isin $1-) set %upnp.getCURL $true
}
if (%upnp.getCURL) {
if (<controlURL> isin $1-) {
set %upnp.servinfoURL $upnp.getXMLValue($1-,<controlURL>)
set %upnp.getCURL $false
echo $color(other) -gs -UPnP- Service Control URL: %upnp.servinfoURL
upnp.getServiceExternalIP $+(%upnp.servinfoBase,%upnp.servinfoURL)
}
}
}
if ($1 == $null) && (%upnp.devinfoMode == HTTP) set %upnp.devinfoMode XML
sockread %info
}
}
alias upnp.getServiceExternalIP {
echo $color(other) -gs -UPnP- Getting Service External IP Address...
var %upnp.servip = $gettok($gettok($$1,2,47),1,58)
var %upnp.servport = $gettok($gettok($1,2,47),2,58)
sockclose upnp.servIP
sockopen upnp.servIP %upnp.servip %upnp.servport
sockmark upnp.servIP $+($chr(47),$gettok($1,3-,47))
}
on 1:sockopen:upnp.servIP: {
if ($sockerr > 0) return
set %upnp.servIPMode HTTP
sockwrite -nt $sockname POST $sock($sockname).mark HTTP/1.1
sockwrite -nt $sockname Host: $+($sock($sockname).ip,$chr(58),$sock($sockname).port)
sockwrite -nt $sockname Connection: close
sockwrite -nt $sockname Content-Length: $iif(PPP isin %upnp.st,273,272)
sockwrite -nt $sockname Content-Type: text/xml; charset="utf-8"
sockwrite -nt $sockname SOAPAction: $+(",%upnp.st,#GetExternalIPAddress")
sockwrite -nt $sockname
sockwrite -nt $sockname <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
sockwrite -nt $sockname <s:Body>
sockwrite -nt $sockname $+(<u:GetExternalIPAddress xmlns:u=",%upnp.st,"></u:GetExternalIPAddress>)
sockwrite -nt $sockname </s:Body>
sockwrite -nt $sockname </s:Envelope>
sockwrite -nt $sockname
}
on *:sockread:upnp.servIP: {
if ($sockerr > 0) return
sockread %info
while ($sockbr > 0) {
tokenize 32 %info
if (%upnp.servIPMode == XML) {
if (<NewExternalIPAddress> isin $1-) {
set %upnp.externalIP $upnp.getXMLValue($1-,<NewExternalIPAddress>)
echo $color(other) -gs -UPnP- Service External IP Address: %upnp.externalIP
}
}
if ($1 == $null) && (%upnp.servIPMode == HTTP) set %upnp.servIPMode XML
sockread %info
}
}
alias upnp.addPortMapping {
var %upnp.lp = $iif($0 > 2,$3,$$2)
var %upnp.prot = $upper($iif($0 > 2,$2,$1))
var %upnp.curl = $iif($0 > 2,$1,$+(%upnp.servinfoBase,%upnp.servinfoURL))
if (%upnp.localip == $null) {
echo $color(other) -gs -UPnP- Cannot map port %upnp.lp $+($chr(40),%upnp.prot,$chr(41)) $+ . Local IP Address is unknown
return
}
echo $color(other) -gs -UPnP- Mapping port %upnp.lp $+($chr(40),%upnp.prot,$chr(41)) to %upnp.localip $+ ...
var %upnp.pmi = $gettok($gettok(%upnp.curl,2,47),1,58)
var %upnp.pmp = $gettok($gettok(%upnp.curl,2,47),2,58)
set %upnp.pmport %upnp.lp
set %upnp.pmprot %upnp.prot
set %upnp.pmlease 0
sockclose upnp.pm
sockopen upnp.pm %upnp.pmi %upnp.pmp
sockmark upnp.pm $+($chr(47),$gettok(%upnp.curl,3-,47))
}
on 1:sockopen:upnp.pm: {
if ($sockerr > 0) return
set %upnp.pmMode HTTP
sockwrite -nt $sockname POST $sock($sockname).mark HTTP/1.1
sockwrite -nt $sockname Host: $+($sock($sockname).ip,$chr(58),$sock($sockname).port)
sockwrite -nt $sockname Connection: close
sockwrite -nt $sockname Content-Length: $calc(527 + $len(%upnp.st) + ($len(%upnp.pmport) * 4) + ($len(%upnp.pmprot) * 2) + ($len(%upnp.localip) * 2) + $len(%upnp.pmlease))
sockwrite -nt $sockname Content-Type: text/xml; charset="utf-8"
sockwrite -nt $sockname SOAPAction: $+(",%upnp.st,#AddPortMapping")
sockwrite -nt $sockname
sockwrite -nt $sockname <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
sockwrite -nt $sockname <s:Body>
sockwrite -nt $sockname $+(<u:AddPortMapping xmlns:u=",%upnp.st,">)
sockwrite -nt $sockname <NewRemoteHost></NewRemoteHost>
sockwrite -nt $sockname $+(<NewExternalPort>,%upnp.pmport,</NewExternalPort>)
sockwrite -nt $sockname $+(<NewProtocol>,%upnp.pmprot,</NewProtocol>)
sockwrite -nt $sockname $+(<NewInternalPort>,%upnp.pmport,</NewInternalPort>)
sockwrite -nt $sockname $+(<NewInternalClient>,%upnp.localip,</NewInternalClient>)
sockwrite -nt $sockname <NewEnabled>1</NewEnabled>
sockwrite -nt $sockname $+(<NewPortMappingDescription>mIRC $chr(40),%upnp.localip,:,%upnp.pmport,$chr(41),$chr(32),%upnp.pmport,$chr(32),%upnp.pmprot,</NewPortMappingDescription>)
sockwrite -nt $sockname $+(<NewLeaseDuration>,%upnp.pmlease,</NewLeaseDuration>)
sockwrite -nt $sockname </u:AddPortMapping>
sockwrite -nt $sockname </s:Body>
sockwrite -nt $sockname </s:Envelope>
sockwrite -nt $sockname
}
on *:sockread:upnp.pm: {
if ($sockerr > 0) return
sockread %info
while ($sockbr > 0) {
tokenize 32 %info
if (%upnp.pmMode == HTTP) {
if (HTTP/1.1 200 * iswm $1-) {
echo $color(other) -gs -UPnP- Port Mapping Added: $+(mIRC $chr(40),%upnp.localip,:,%upnp.pmport,$chr(41),$chr(32),%upnp.pmport,$chr(32),%upnp.pmprot)
sockclose $sockname
return
}
if (HTTP/1.1 500 * iswm $1-) {
echo $color(other) -gs -UPnP- Port Mapping Add Error
sockclose $sockname
return
}
if ($1 == $null) set %upnp.pmMode XML
}
if (%upnp.pmMode == XML) {
;if ($+(<u:AddPortMappingResponse xmlns:u=",%upnp.st,"/>) isin $1-) {
;}
}
sockread %info
}
}
alias upnp.delPortMapping {
var %upnp.lp = $iif($0 > 2,$3,$$2)
var %upnp.prot = $upper($iif($0 > 2,$2,$1))
var %upnp.curl = $iif($0 > 2,$1,$+(%upnp.servinfoBase,%upnp.servinfoURL))
echo $color(other) -gs -UPnP- Deleting Port Mapping for port %upnp.lp $+($chr(40),%upnp.prot,$chr(41)) $+ ...
var %upnp.pmdi = $gettok($gettok(%upnp.curl,2,47),1,58)
var %upnp.pmdp = $gettok($gettok(%upnp.curl,2,47),2,58)
set %upnp.pmdport %upnp.lp
set %upnp.pmdprot %upnp.prot
sockclose upnp.pmd
sockopen upnp.pmd %upnp.pmdi %upnp.pmdp
sockmark upnp.pmd $+($chr(47),$gettok(%upnp.curl,3-,47))
}
on 1:sockopen:upnp.pmd: {
if ($sockerr > 0) return
set %upnp.pmdMode HTTP
sockwrite -nt $sockname POST $sock($sockname).mark HTTP/1.1
sockwrite -nt $sockname Host: $+($sock($sockname).ip,$chr(58),$sock($sockname).port)
sockwrite -nt $sockname Connection: close
sockwrite -nt $sockname Content-Length: $calc(321 + $len(%upnp.st) + $len(%upnp.pmdport) + $len(%upnp.pmdprot))
sockwrite -nt $sockname Content-Tupe: text/xml; charset="utf-8"
sockwrite -nt $sockname SOAPAction: $+(",%upnp.st,#DeletePortMapping")
sockwrite -nt $sockname
sockwrite -nt $sockname <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
sockwrite -nt $sockname <s:Body>
sockwrite -nt $sockname $+(<u:DeletePortMapping xmlns:u=",%upnp.st,">)
sockwrite -nt $sockname <NewRemoteHost></NewRemoteHost>
sockwrite -nt $sockname $+(<NewExternalPort>,%upnp.pmdport,</NewExternalPort>)
sockwrite -nt $sockname $+(<NewProtocol>,%upnp.pmdprot,</NewProtocol>)
sockwrite -nt $sockname </u:DeletePortMapping>
sockwrite -nt $sockname </s:Body>
sockwrite -nt $sockname </s:Envelope>
sockwrite -nt $sockname
}
on *:sockread:upnp.pmd: {
if ($sockerr > 0) return
sockread %info
while ($sockbr > 0) {
tokenize 32 %info
if (%upnp.pmdMode == HTTP) {
if (HTTP/1.1 200 * iswm $1-) {
echo $color(other) -gs -UPnP- Port Mapping Deleted for port %upnp.pmdport $+($chr(40),%upnp.pmdprot,$chr(41))
sockclose $sockname
return
}
if (HTTP/1.1 500 * iswm $1-) {
echo $color(other) -gs -UPnP- Port Mapping Delete Error
sockclose $sockname
return
}
if ($1 == $null) set %upnp.pmdMode XML
}
if (%upnp.pmdMode == XML) {
;if ($+(<u:DeletePortMappingResponse xmlns:u=",%upnp.st,"/>) isin $1-) {
;}
}
sockread %info
}
}
alias upnp.getXMLValue {
if (!$isid) return
var %rest = $right($$1-,$calc(0 - ($pos($1-,$2) + $len($2) - 1)))
var %tag = $2
if ($pos(%rest,<) != 1) return $gettok(%rest,1,$asc(<))
else return $null
} I remember fixing a bug in the "on 1:sockopen:upnp.pmd" event (there was a "%upnp.pmport" that should have been "%upnp.pmdport") and changing the parameters that both the upnp.addPortMapping and upnp.delPortMapping methods take; they now take [Control URL] <TCP|UDP> <port>. I've been using it for a couple of months now without having any problems. In case this script is unable to close a port it opened thanks to a crash or something similar, you can manually close it with the upnp.delPortMapping method. Hell, you can even close ports that were left open by another application. Ports opened by UPnP usually show up in your router's configuration page, and if you have a mess for whatever reason (for example, sometimes MSN Messenger and BT clients will leave a lot of ports open), unplugging your router should be enough to clear them all.
|
|
|
|
Jaak
|
Jaak
|
In case someone is still interested, I quit working on this script a couple of days after my last post in this topic, but here is my last version:
This script is fantastic. I hope you'll keep on developing it!
|
|
|
|
Joined: Dec 2002
Posts: 3,534
Hoopy frood
|
Hoopy frood
Joined: Dec 2002
Posts: 3,534 |
This script is fantastic. I hope you'll keep on developing it!
In case someone is still interested, I quit working on this script a couple of days after my last post in this topic, but here is my last version:
|
|
|
|
Jaak
|
Jaak
|
I quit working on this script a couple of days after my last post in this topic, but here is my last version: No, really?
|
|
|
|
Joined: Nov 2006
Posts: 1,552
Hoopy frood
|
Hoopy frood
Joined: Nov 2006
Posts: 1,552 |
|
|
|
|
|