Recent

Author Topic: [SOLVED] How to open UPnP port with synapse  (Read 10882 times)

rvk

  • Hero Member
  • *****
  • Posts: 6715
Re: How to open UPnP port?
« Reply #45 on: June 13, 2023, 04:36:27 pm »
why i have to start the server first?
It shouldn't. The IP needs to be present in the network for the AddPort to succeed.

But the port doesn't have to be open.
So this should also be possible.

1. start the prog to addport
2. start the server on port 4444
3. start nmap

rvk

  • Hero Member
  • *****
  • Posts: 6715
Re: How to open UPnP port?
« Reply #46 on: June 13, 2023, 04:37:31 pm »
BTW, Can you do a writeln(s) before doing the WriteStrToStream(HTTP.Document, S); for AddPort ?
(in the code you have now)

I find it really strange you get a 400 with my latest code:
(I added everything as constant parameters at the top)

Code: Pascal  [Select][+][-]
  1. program upnp;
  2.  
  3. {$MODE OBJFPC}{$H+}
  4. uses
  5.   Classes,
  6.   blcksock,
  7.   synautil,
  8.   SysUtils,
  9.   RegExpr,
  10.   httpsend;
  11.  
  12. const
  13.   GatewayIP = '192.168.0.1'; // I used hardcoded Gateway here. You can also listen for any other upnp device and pick that one.
  14.   IPIn = '192.168.0.4';
  15.   PortIn = '4444';
  16.   PortEx = '3341';
  17.   Debug = false;
  18.  
  19.   function GetStringBetweenAndStrip(var str: string; startStr, endStr: string): string;
  20.   var
  21.     startPos, endPos: integer;
  22.   begin
  23.     startStr := uppercase(startStr);
  24.     endStr := uppercase(endStr);
  25.     startPos := Pos(startStr, uppercase(str));
  26.     if startPos = 0 then exit('');
  27.     startPos := startPos + Length(startStr);
  28.     endPos := Pos(endStr, uppercase(str), startPos);
  29.     if endPos = 0 then exit('');
  30.     Result := Copy(str, startPos, endPos - startPos);
  31.     // strip the string
  32.     startPos := startPos - Length(startStr);
  33.     endPos := endPos + Length(endStr);
  34.     System.Delete(str, startPos, endPos - startPos);
  35.   end;
  36.  
  37. var
  38.   Location, Base, Found, Found1, Service, S: string;
  39.   ServiceType: string;
  40.   Socket: TUDPBlockSocket;
  41.   Response: TStringList;
  42.   HTTP: THTTPSend;
  43.   ResultCode: integer;
  44.   Idx: integer;
  45.   eH, eP, Pr, iP, iH, iE, iD, iL: string;
  46. begin
  47.  
  48.   S := 'M-SEARCH * HTTP/1.1'#13#10 + 'HOST: 239.255.255.250:1900'#13#10 + 'MAN: "ssdp:discover"'#13#10 + 'MX: 3'#13#10 + 'ST: upnp:rootdevice'#13#10#13#10;
  49.   Socket := TUDPBlockSocket.Create;
  50.   Socket.EnableBroadcast(True);
  51.   Socket.Connect(GatewayIP, '1900');
  52.   Socket.SendString(S);
  53.   repeat
  54.     if Socket.CanRead(3000) then
  55.     begin
  56.       Found := Socket.RecvPacket(3000);
  57.       if Pos('LOCATION: ', uppercase(Found)) > 0 then
  58.       begin
  59.         Location := Copy(Found, Pos('LOCATION:', uppercase(Found)) + 9);
  60.         Location := Trim(Copy(Location, 1, Pos(#13#10, Location) - 1));
  61.         writeln('Location is ' + Location);
  62.         Response := TStringList.Create;
  63.         try
  64.  
  65.           HttpGetText(Location, Response);
  66.           Found := Response.Text;
  67.  
  68.           Base := Location; // take base of Location for control
  69.           while (Base <> '') and (Location[Length(Base)] <> '/') do Delete(Base, Length(Base), 1);
  70.           if Base <> '' then Delete(Base, Length(Base), 1);
  71.           writeln('Base is ' + Base);
  72.  
  73.           // loop all services
  74.           repeat
  75.             Service := GetStringBetweenAndStrip(Found, '<service>', '</service>');
  76.             if Pos(uppercase(':WANIPConnection:'), uppercase(service)) > 0 then
  77.             begin
  78.               S := GetStringBetweenAndStrip(Service, '<SCPDURL>', '</SCPDURL>');
  79.               if S <> '' then
  80.               begin
  81.                 Location := Base + S;
  82.                 writeln('SCPDURL is ' + Location);
  83.                 HttpGetText(Location, Response);
  84.                 S := Response.Text;
  85.                 if Pos(uppercase('<name>AddPortMapping</name>'), uppercase(S)) > 0 then
  86.                 begin
  87.                   ServiceType := GetStringBetweenAndStrip(Service, '<serviceType>', '</serviceType>');
  88.                   S := GetStringBetweenAndStrip(Service, '<controlURL>', '</controlURL>');
  89.                   Location := Base + S;
  90.                   writeln('Control URL is ' + Location);
  91.                   writeln('ServiceType is ' + ServiceType);
  92.  
  93.                   // HERE WE INSERT
  94.  
  95.                   s := '<?xml version="1.0"?>';
  96.                   s := s + '<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">';
  97.                   s := s + '<SOAP-ENV:Body>';
  98.                   s := s + '    <m:AddPortMapping xmlns:m="' + ServiceType + '">';
  99.                   s := s + '        <NewRemoteHost></NewRemoteHost>';
  100.                   s := s + '        <NewExternalPort>' + PortEx + '</NewExternalPort>';
  101.                   s := s + '        <NewProtocol>UDP</NewProtocol>';
  102.                   s := s + '        <NewInternalPort>' + PortIn + '</NewInternalPort>';
  103.                   s := s + '        <NewInternalClient>' + IPIn + '</NewInternalClient>';
  104.                   s := s + '        <NewEnabled>1</NewEnabled>';
  105.                   s := s + '        <NewPortMappingDescription>test</NewPortMappingDescription>';
  106.                   s := s + '        <NewLeaseDuration>0</NewLeaseDuration>';
  107.                   s := s + '    </m:AddPortMapping>';
  108.                   s := s + '</SOAP-ENV:Body>';
  109.                   s := s + '</SOAP-ENV:Envelope>';
  110.  
  111.                   HTTP := THTTPSend.Create;
  112.                   try
  113.  
  114.                     writeln;
  115.                     writeln('posting ' + s);
  116.                     writeln;
  117.  
  118.                     WriteStrToStream(HTTP.Document, S);
  119.                     HTTP.MimeType := 'text/xml; charset="utf-8"';
  120.                     HTTP.Headers.Add('SOAPAction: ' + ServiceType + '#AddPortMapping');
  121.  
  122.                     if HTTP.HTTPMethod('POST', Location) then
  123.                     begin
  124.                       Resultcode := HTTP.ResultCode;
  125.                       Response.LoadFromStream(HTTP.Document);
  126.                       Found := Response.Text;
  127.                       if (HTTP.ResultCode = 200) then writeln('Success adding port forward');
  128.                       if (HTTP.ResultCode <> 200) or Debug then
  129.                       begin
  130.                         writeln('');
  131.                         writeln('Result of AddPort: ' + HTTP.ResultCode.ToString + ' ' + found);
  132.                       end;
  133.                     end;
  134.  
  135.                   finally
  136.                     HTTP.Free;
  137.                   end;
  138.  
  139.                   // HERE WE CHECK
  140.  
  141.  
  142.                   Idx := 0;
  143.                   repeat
  144.  
  145.                     S := '';
  146.                     S := S + '<?xml version="1.0"?>';
  147.                     S := S + '<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">';
  148.                     S := S + ' <s:Body>';
  149.                     S := S + '  <u:GetGenericPortMappingEntry xmlns:u="' + ServiceType + '">';
  150.                     S := S + '   <NewPortMappingIndex>' + Idx.ToString + '</NewPortMappingIndex>';
  151.                     S := S + '  </u:GetGenericPortMappingEntry>';
  152.                     S := S + ' </s:Body>';
  153.                     S := S + '</s:Envelope>';
  154.  
  155.                     HTTP := THTTPSend.Create;
  156.                     try
  157.  
  158.                       WriteStrToStream(HTTP.Document, S);
  159.                       HTTP.MimeType := 'text/xml; charset="utf-8"';
  160.                       HTTP.Headers.Add('SOAPAction: ' + ServiceType + '#GetGenericPortMappingEntry');
  161.  
  162.                       if HTTP.HTTPMethod('POST', Location) then
  163.                       begin
  164.                         Resultcode := HTTP.ResultCode;
  165.                         Response.LoadFromStream(HTTP.Document);
  166.                         Found := Response.Text;
  167.                         if Debug or ((HTTP.ResultCode <> 200) and (HTTP.ResultCode <> 500)) then
  168.                         begin
  169.                           writeln('');
  170.                           writeln('Result of GetPortMapping #' + Idx.ToString + ': ' + HTTP.ResultCode.ToString + ' ' + found);
  171.                         end;
  172.                         repeat
  173.                           Found1 := GetStringBetweenAndStrip(Found, '<u:GetGenericPortMappingEntryResponse', '</u:GetGenericPortMappingEntryResponse>');
  174.                           if Found1 <> '' then
  175.                           begin
  176.                             eH := GetStringBetweenAndStrip(Found1, '<NewRemoteHost>', '</NewRemoteHost>');
  177.                             eP := GetStringBetweenAndStrip(Found1, '<NewExternalPort>', '</NewExternalPort>');
  178.                             Pr := GetStringBetweenAndStrip(Found1, '<NewProtocol>', '</NewProtocol>');
  179.                             iP := GetStringBetweenAndStrip(Found1, '<NewInternalPort>', '</NewInternalPort>');
  180.                             iH := GetStringBetweenAndStrip(Found1, '<NewInternalClient>', '</NewInternalClient>');
  181.                             iE := GetStringBetweenAndStrip(Found1, '<NewEnabled>', '<NewEnabled>');
  182.                             iD := GetStringBetweenAndStrip(Found1, '<NewPortMappingDescription>', '</NewPortMappingDescription>');
  183.                             iL := GetStringBetweenAndStrip(Found1, '<NewLeaseDuration>', '</NewLeaseDuration>');
  184.                             S := Format('%s %s:%s -> %s:%s En: %s  De: %s  Le: %s', [Pr, eH, eP, iH, iP, iE, iD, iL]);
  185.                             writeln(S);
  186.                           end;
  187.                         until Found1 = '';
  188.                       end;
  189.  
  190.                     finally
  191.                       HTTP.Free;
  192.                     end;
  193.                     Inc(Idx);
  194.  
  195.                   until Resultcode <> 200;
  196.  
  197.                 end;
  198.  
  199.               end;
  200.  
  201.             end;
  202.  
  203.           until service = '';
  204.  
  205.         finally
  206.           Response.Free;
  207.         end;
  208.       end;
  209.       break;
  210.     end;
  211.     sleep(100);
  212.   until False;
  213.   Socket.CloseSocket;
  214.   Socket.Free;
  215.   writeln('we are done, press enter');
  216.   readln;
  217.  
  218. end.

Key-Real

  • Sr. Member
  • ****
  • Posts: 387
Re: How to open UPnP port?
« Reply #47 on: June 13, 2023, 04:39:37 pm »
Quote
Location is http://192.168.0.1:49153/IGDdevicedesc_brlan0.xml
Base is http://192.168.0.1:49153
SCPDURL is http://192.168.0.1:49153/WANIPConnectionServiceSCPD.xml
Control URL is http://192.168.0.1:49153/upnp/control/WANIPConnection0
ServiceType is urn:schemas-upnp-org:service:WANIPConnection:1

posting <?xml version="1.0"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body>    <m:AddPortMapping xmlns:m="urn:schemas-upnp-org:service:WANIPConnection:1">        <NewRemoteHost></NewRemoteHost>        <NewExternalPort>3341</NewExternalPort>        <NewProtocol>UDP</NewProtocol>        <NewInternalPort>4444</NewInternalPort>        <NewInternalClient>192.168.0.4</NewInternalClient>        <NewEnabled>1</NewEnabled>        <NewPortMappingDescription>test</NewPortMappingDescription>        <NewLeaseDuration>0</NewLeaseDuration>    </m:AddPortMapping></SOAP-ENV:Body></SOAP-ENV:Envelope>


Result of AddPort: 400 <html><body><h1>400 Bad Request</h1></body></html>


Result of GetPortMapping #0: 400 <html><body><h1>400 Bad Request</h1></body></html>

we are done, press enter




Key-Real

  • Sr. Member
  • ****
  • Posts: 387
Re: How to open UPnP port?
« Reply #48 on: June 13, 2023, 04:40:39 pm »
and he closes the port after some time (seems to be random, but i don't knew)

rvk

  • Hero Member
  • *****
  • Posts: 6715
Re: How to open UPnP port?
« Reply #49 on: June 13, 2023, 04:41:29 pm »
Quote
...
And can you put the writeln(s) in your working code so we can compare the xml which is posted.

and he closes the port after some time (seems to be random, but i don't knew)
The lease time for open port can be extended.
(you now have 0 I thought)

0 could be a default of 3600 seconds.

Key-Real

  • Sr. Member
  • ****
  • Posts: 387
Re: How to open UPnP port?
« Reply #50 on: June 13, 2023, 04:45:03 pm »
You mean:

Code: Pascal  [Select][+][-]
  1. writeln('ServiceType is ' + ServiceType);

I thought 0 in
Code: Pascal  [Select][+][-]
  1. <NewLeaseDuration>0</NewLeaseDuration>
is forever?

rvk

  • Hero Member
  • *****
  • Posts: 6715
Re: How to open UPnP port?
« Reply #51 on: June 13, 2023, 04:49:19 pm »
You mean:
Could you put the line
writeln('posting ' + s);
above WriteStrToStream(HTTP.Document, S); in the AddPort section? (of your now working code)

We need to compare the difference between my last code and your working code.

I thought 0 in
Code: Pascal  [Select][+][-]
  1. <NewLeaseDuration>0</NewLeaseDuration>
is forever?
Yes, 0 should be permanent.
But maybe not all routers follow this 'suggestion'.

If you see the UPnP disappear after some time, try to figure out what that time is.
(but thats hard to do if you can't do a upnpc -l to check and the GetPortMapping doesn't work)

Key-Real

  • Sr. Member
  • ****
  • Posts: 387
Re: How to open UPnP port?
« Reply #52 on: June 13, 2023, 04:52:28 pm »
Quote
Location is http://192.168.0.1:49153/IGDdevicedesc_brlan0.xml
Base is http://192.168.0.1:49153
SCPDURL is http://192.168.0.1:49153/WANIPConnectionServiceSCPD.xml
Control URL is http://192.168.0.1:49153/upnp/control/WANIPConnection0
ServiceType is urn:schemas-upnp-org:service:WANIPConnection:1
posting <?xml version="1.0"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body>    <m:AddPortMapping xmlns:m="urn:schemas-upnp-org:service:WANIPConnection:1">        <NewRemoteHost></NewRemoteHost>        <NewExternalPort>3331</NewExternalPort>        <NewProtocol>UDP</NewProtocol>        <NewInternalPort>4444</NewInternalPort>        <NewInternalClient>192.168.0.4</NewInternalClient>        <NewEnabled>1</NewEnabled>        <NewPortMappingDescription>test</NewPortMappingDescription>        <NewLeaseDuration>0</NewLeaseDuration>    </m:AddPortMapping></SOAP-ENV:Body></SOAP-ENV:Envelope>
200 <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body>
<u:AddPortMappingResponse xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1"></u:AddPortMappingResponse>
</s:Body> </s:Envelope>

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body>
<u:AddPortMappingResponse xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1"></u:AddPortMappingResponse>
</s:Body> </s:Envelope>



rvk

  • Hero Member
  • *****
  • Posts: 6715
Re: How to open UPnP port?
« Reply #53 on: June 13, 2023, 04:57:34 pm »
Quote
[...]
Thanks... Really weird... If I look at my own last code:

Quote
posting <?xml version="1.0"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body>    <m:AddPortMapping xmlns:m="urn:schemas-upnp-org:service:WANIPConnection:1">        <NewRemoteHost></NewRemoteHost>        <NewExternalPort>3341</NewExternalPort>        <NewProtocol>UDP</NewProtocol>        <NewInternalPort>4444</NewInternalPort>        <NewInternalClient>192.168.0.4</NewInternalClient>        <NewEnabled>1</NewEnabled>        <NewPortMappingDescription>test</NewPortMappingDescription>        <NewLeaseDuration>0</NewLeaseDuration>    </m:AddPortMapping></SOAP-ENV:Body></SOAP-ENV:Envelope>


Result of AddPort: 400 <html><body><h1>400 Bad Request</h1></body></html>

Your working code:
Quote
posting <?xml version="1.0"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body>    <m:AddPortMapping xmlns:m="urn:schemas-upnp-org:service:WANIPConnection:1">        <NewRemoteHost></NewRemoteHost>        <NewExternalPort>3331</NewExternalPort>        <NewProtocol>UDP</NewProtocol>        <NewInternalPort>4444</NewInternalPort>        <NewInternalClient>192.168.0.4</NewInternalClient>        <NewEnabled>1</NewEnabled>        <NewPortMappingDescription>test</NewPortMappingDescription>        <NewLeaseDuration>0</NewLeaseDuration>    </m:AddPortMapping></SOAP-ENV:Body></SOAP-ENV:Envelope>
200 <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body>
<u:AddPortMappingResponse xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1"></u:AddPortMappingResponse>
</s:Body> </s:Envelope>

The xml seems to be exactly the same.

Only other difference is this for you:
Code: Pascal  [Select][+][-]
  1.                         HTTP.MimeType := 'text/xml; charset="utf-8"';
  2.                         http.Headers.Add('SOAPAction: "urn:schemas-upnp-org:service:WANIPConnection:1#AddPortMapping"');
and this for me:
Code: Pascal  [Select][+][-]
  1.                     HTTP.MimeType := 'text/xml; charset="utf-8"';
  2.                     HTTP.Headers.Add('SOAPAction: ' + ServiceType + '#AddPortMapping');
and your ServiceType variable stated:
Quote
urn:schemas-upnp-org:service:WANIPConnection:1

Maybe I'm blind but I can't spot the difference.

rvk

  • Hero Member
  • *****
  • Posts: 6715
Re: How to open UPnP port?
« Reply #54 on: June 13, 2023, 05:00:31 pm »
Mmmm, only difference is the double quotes around the servicetype.

Can you try this version?

Code: Pascal  [Select][+][-]
  1. program upnp;
  2.  
  3. {$MODE OBJFPC}{$H+}
  4. uses
  5.   Classes,
  6.   blcksock,
  7.   synautil,
  8.   SysUtils,
  9.   RegExpr,
  10.   httpsend;
  11.  
  12. const
  13.   GatewayIP = '192.168.0.1'; // I used hardcoded Gateway here. You can also listen for any other upnp device and pick that one.
  14.   IPIn = '192.168.0.4';
  15.   PortIn = '4444';
  16.   PortEx = '3344';
  17.   Debug = false;
  18.  
  19.   function GetStringBetweenAndStrip(var str: string; startStr, endStr: string): string;
  20.   var
  21.     startPos, endPos: integer;
  22.   begin
  23.     startStr := uppercase(startStr);
  24.     endStr := uppercase(endStr);
  25.     startPos := Pos(startStr, uppercase(str));
  26.     if startPos = 0 then exit('');
  27.     startPos := startPos + Length(startStr);
  28.     endPos := Pos(endStr, uppercase(str), startPos);
  29.     if endPos = 0 then exit('');
  30.     Result := Copy(str, startPos, endPos - startPos);
  31.     // strip the string
  32.     startPos := startPos - Length(startStr);
  33.     endPos := endPos + Length(endStr);
  34.     System.Delete(str, startPos, endPos - startPos);
  35.   end;
  36.  
  37. var
  38.   Location, Base, Found, Found1, Service, S: string;
  39.   ServiceType: string;
  40.   Socket: TUDPBlockSocket;
  41.   Response: TStringList;
  42.   HTTP: THTTPSend;
  43.   ResultCode: integer;
  44.   Idx: integer;
  45.   eH, eP, Pr, iP, iH, iE, iD, iL: string;
  46. begin
  47.  
  48.   S := 'M-SEARCH * HTTP/1.1'#13#10 + 'HOST: 239.255.255.250:1900'#13#10 + 'MAN: "ssdp:discover"'#13#10 + 'MX: 3'#13#10 + 'ST: upnp:rootdevice'#13#10#13#10;
  49.   Socket := TUDPBlockSocket.Create;
  50.   Socket.EnableBroadcast(True);
  51.   Socket.Connect(GatewayIP, '1900');
  52.   Socket.SendString(S);
  53.   repeat
  54.     if Socket.CanRead(3000) then
  55.     begin
  56.       Found := Socket.RecvPacket(3000);
  57.       if Pos('LOCATION: ', uppercase(Found)) > 0 then
  58.       begin
  59.         Location := Copy(Found, Pos('LOCATION:', uppercase(Found)) + 9);
  60.         Location := Trim(Copy(Location, 1, Pos(#13#10, Location) - 1));
  61.         writeln('Location is ' + Location);
  62.         Response := TStringList.Create;
  63.         try
  64.  
  65.           HttpGetText(Location, Response);
  66.           Found := Response.Text;
  67.  
  68.           Base := Location; // take base of Location for control
  69.           while (Base <> '') and (Location[Length(Base)] <> '/') do Delete(Base, Length(Base), 1);
  70.           if Base <> '' then Delete(Base, Length(Base), 1);
  71.           writeln('Base is ' + Base);
  72.  
  73.           // loop all services
  74.           repeat
  75.             Service := GetStringBetweenAndStrip(Found, '<service>', '</service>');
  76.             if Pos(uppercase(':WANIPConnection:'), uppercase(service)) > 0 then
  77.             begin
  78.               S := GetStringBetweenAndStrip(Service, '<SCPDURL>', '</SCPDURL>');
  79.               if S <> '' then
  80.               begin
  81.                 Location := Base + S;
  82.                 writeln('SCPDURL is ' + Location);
  83.                 HttpGetText(Location, Response);
  84.                 S := Response.Text;
  85.                 if Pos(uppercase('<name>AddPortMapping</name>'), uppercase(S)) > 0 then
  86.                 begin
  87.                   ServiceType := GetStringBetweenAndStrip(Service, '<serviceType>', '</serviceType>');
  88.                   S := GetStringBetweenAndStrip(Service, '<controlURL>', '</controlURL>');
  89.                   Location := Base + S;
  90.                   writeln('Control URL is ' + Location);
  91.                   writeln('ServiceType is ' + ServiceType);
  92.  
  93.                   // HERE WE INSERT
  94.  
  95.                   s := '<?xml version="1.0"?>';
  96.                   s := s + '<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">';
  97.                   s := s + '<SOAP-ENV:Body>';
  98.                   s := s + '    <m:AddPortMapping xmlns:m="' + ServiceType + '">';
  99.                   s := s + '        <NewRemoteHost></NewRemoteHost>';
  100.                   s := s + '        <NewExternalPort>' + PortEx + '</NewExternalPort>';
  101.                   s := s + '        <NewProtocol>UDP</NewProtocol>';
  102.                   s := s + '        <NewInternalPort>' + PortIn + '</NewInternalPort>';
  103.                   s := s + '        <NewInternalClient>' + IPIn + '</NewInternalClient>';
  104.                   s := s + '        <NewEnabled>1</NewEnabled>';
  105.                   s := s + '        <NewPortMappingDescription>test</NewPortMappingDescription>';
  106.                   s := s + '        <NewLeaseDuration>0</NewLeaseDuration>';
  107.                   s := s + '    </m:AddPortMapping>';
  108.                   s := s + '</SOAP-ENV:Body>';
  109.                   s := s + '</SOAP-ENV:Envelope>';
  110.  
  111.                   HTTP := THTTPSend.Create;
  112.                   try
  113.  
  114.                     WriteStrToStream(HTTP.Document, S);
  115.                     HTTP.MimeType := 'text/xml; charset="utf-8"';
  116.                     HTTP.Headers.Add('SOAPAction: "' + ServiceType + '#AddPortMapping"');
  117.  
  118.                     if HTTP.HTTPMethod('POST', Location) then
  119.                     begin
  120.                       Resultcode := HTTP.ResultCode;
  121.                       Response.LoadFromStream(HTTP.Document);
  122.                       Found := Response.Text;
  123.                       if (HTTP.ResultCode = 200) then writeln('Success adding port forward');
  124.                       if (HTTP.ResultCode <> 200) or Debug then
  125.                       begin
  126.                         writeln('');
  127.                         writeln('Result of AddPort: ' + HTTP.ResultCode.ToString + ' ' + found);
  128.                       end;
  129.                     end;
  130.  
  131.                   finally
  132.                     HTTP.Free;
  133.                   end;
  134.  
  135.                   // HERE WE CHECK
  136.  
  137.                   writeln('Checking ports');
  138.                   Idx := 0;
  139.                   repeat
  140.  
  141.                     S := '';
  142.                     S := S + '<?xml version="1.0"?>';
  143.                     S := S + '<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">';
  144.                     S := S + ' <s:Body>';
  145.                     S := S + '  <u:GetGenericPortMappingEntry xmlns:u="' + ServiceType + '">';
  146.                     S := S + '   <NewPortMappingIndex>' + Idx.ToString + '</NewPortMappingIndex>';
  147.                     S := S + '  </u:GetGenericPortMappingEntry>';
  148.                     S := S + ' </s:Body>';
  149.                     S := S + '</s:Envelope>';
  150.  
  151.                     HTTP := THTTPSend.Create;
  152.                     try
  153.  
  154.                       WriteStrToStream(HTTP.Document, S);
  155.                       HTTP.MimeType := 'text/xml; charset="utf-8"';
  156.                       HTTP.Headers.Add('SOAPAction: "' + ServiceType + '#GetGenericPortMappingEntry"');
  157.  
  158.                       if HTTP.HTTPMethod('POST', Location) then
  159.                       begin
  160.                         Resultcode := HTTP.ResultCode;
  161.                         Response.LoadFromStream(HTTP.Document);
  162.                         Found := Response.Text;
  163.                         if Debug or ((HTTP.ResultCode <> 200) and (HTTP.ResultCode <> 500)) then
  164.                         begin
  165.                           writeln('');
  166.                           writeln('Result of GetPortMapping #' + Idx.ToString + ': ' + HTTP.ResultCode.ToString + ' ' + found);
  167.                         end;
  168.                         repeat
  169.                           Found1 := GetStringBetweenAndStrip(Found, '<u:GetGenericPortMappingEntryResponse', '</u:GetGenericPortMappingEntryResponse>');
  170.                           if Found1 <> '' then
  171.                           begin
  172.                             eH := GetStringBetweenAndStrip(Found1, '<NewRemoteHost>', '</NewRemoteHost>');
  173.                             eP := GetStringBetweenAndStrip(Found1, '<NewExternalPort>', '</NewExternalPort>');
  174.                             Pr := GetStringBetweenAndStrip(Found1, '<NewProtocol>', '</NewProtocol>');
  175.                             iP := GetStringBetweenAndStrip(Found1, '<NewInternalPort>', '</NewInternalPort>');
  176.                             iH := GetStringBetweenAndStrip(Found1, '<NewInternalClient>', '</NewInternalClient>');
  177.                             iE := GetStringBetweenAndStrip(Found1, '<NewEnabled>', '<NewEnabled>');
  178.                             iD := GetStringBetweenAndStrip(Found1, '<NewPortMappingDescription>', '</NewPortMappingDescription>');
  179.                             iL := GetStringBetweenAndStrip(Found1, '<NewLeaseDuration>', '</NewLeaseDuration>');
  180.                             S := Format('%s %s:%s -> %s:%s En: %s  De: %s  Le: %s', [Pr, eH, eP, iH, iP, iE, iD, iL]);
  181.                             writeln(S);
  182.                           end;
  183.                         until Found1 = '';
  184.                       end;
  185.  
  186.                     finally
  187.                       HTTP.Free;
  188.                     end;
  189.                     Inc(Idx);
  190.  
  191.                   until Resultcode <> 200;
  192.  
  193.                 end;
  194.  
  195.               end;
  196.  
  197.             end;
  198.  
  199.           until service = '';
  200.  
  201.         finally
  202.           Response.Free;
  203.         end;
  204.       end;
  205.       break;
  206.     end;
  207.     sleep(100);
  208.   until False;
  209.   Socket.CloseSocket;
  210.   Socket.Free;
  211.   writeln('we are done, press enter');
  212.   readln;
  213.  
  214. end.

Key-Real

  • Sr. Member
  • ****
  • Posts: 387
Re: How to open UPnP port?
« Reply #55 on: June 13, 2023, 06:22:11 pm »
Great Success!!!!!!!


Quote
Location is http://192.168.0.1:49153/IGDdevicedesc_brlan0.xml
Base is http://192.168.0.1:49153
SCPDURL is http://192.168.0.1:49153/WANIPConnectionServiceSCPD.xml
Control URL is http://192.168.0.1:49153/upnp/control/WANIPConnection0
ServiceType is urn:schemas-upnp-org:service:WANIPConnection:1
Success adding port forward
Checking ports
UDP :3344 -> 192.168.0.4:4444 En:   De: test  Le: 0
we are done, press enter

rvk

  • Hero Member
  • *****
  • Posts: 6715
Re: How to open UPnP port?
« Reply #56 on: June 13, 2023, 06:24:52 pm »
Great Success!!!!!!!
Yeah  :D great :D

This was with my last code with the double quote around the servicetype in the SOAP header?

(What a small character change can do  ;D )

Key-Real

  • Sr. Member
  • ****
  • Posts: 387
Re: How to open UPnP port?
« Reply #57 on: June 13, 2023, 06:28:10 pm »
Big thx very much :)

I'm glad you could help


I'll have to go now, I'll try to close the port this week,

If You have an Idea about closing and about connection duration, pls post :)

rvk

  • Hero Member
  • *****
  • Posts: 6715
Re: [SOLVED] How to open UPnP port with synapse
« Reply #58 on: June 13, 2023, 08:01:08 pm »
Here is a small unit with a class to open and close the port.
(I don't know why 0 as lease doesn't work for you. Try to determine the time-out when it gets deleted automatically)

This is example code to use the unit.

Code: Pascal  [Select][+][-]
  1. program upnptest;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses upnplibrary;
  6.  
  7. var
  8.   UPnP: TUPnP;
  9. begin
  10.   UPnP := TUPnP.Create('192.168.0.1');
  11.  
  12.   if UPnP.IsUPnPAvailable then
  13.   begin
  14.     Writeln('UPnP is available.');
  15.  
  16.     Writeln('External IP: ', UPnP.ExternalIP);
  17.  
  18.     // Set a port mapping
  19.     if UPnP.SetPortMapping('192.168.0.4', 8081, 8000) = 200 then
  20.     begin
  21.       writeln('Forward result is OK');
  22.       writeln('Check port. Press Enter to delete and terminate');
  23.       readln;
  24.     end
  25.     else
  26.     begin
  27.       writeln('Error forwarding ');
  28.     end;
  29.  
  30.     // Delete a port mapping
  31.     if UPnP.DeletePortMapping(8000) = 200 then
  32.     begin
  33.       writeln('Forward deleted ok');
  34.     end
  35.     else
  36.     begin
  37.       writeln('Error deleting forward');
  38.     end;
  39.  
  40.   end
  41.   else
  42.     Writeln('UPnP is not available.');
  43.  
  44.   UPnP.Free;
  45.  
  46.   writeln('we are done, press enter');
  47.   readln;
  48.  
  49. end.

This is the UPNPLibrary unit with class.
It doesn't have the GetPortMap yet but the AddPort and DeletePort work for me.
If I have some time I can build in those too.
(I wonder if there isn't already such a library floating around...  %) )

Code: Pascal  [Select][+][-]
  1. unit UPNPLibrary;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, SynaUtil, HTTPSend, blcksock;
  9.  
  10. type
  11.   TUPnP = class
  12.   private
  13.     FRootXML: string;
  14.     FBaseURL: string;
  15.     FControlURL: string;
  16.     FServiceType: string;
  17.     function GetExternalIP: string;
  18.     function ExecuteSoapAction(const Action, SoapRequest: string; var SoapResponse: string): Integer;
  19.   public
  20.     constructor Create(const RouterIP: string);
  21.     function IsUPnPAvailable: boolean;
  22.     function SetPortMapping(const InternalIP: string; InternalPort, ExternalPort: integer; Protocol: String = 'TCP'; Description: String = ''): Integer;
  23.     function DeletePortMapping(const ExternalPort: integer; Protocol: String = 'TCP'): Integer;
  24.     property ExternalIP: string read GetExternalIP;
  25.   end;
  26.  
  27. implementation
  28.  
  29. function GetStringBetweenAndStrip(var str: string; startStr, endStr: string): string;
  30. var
  31.   startPos, endPos: integer;
  32. begin
  33.   startStr := uppercase(startStr);
  34.   endStr := uppercase(endStr);
  35.   startPos := Pos(startStr, uppercase(str));
  36.   if startPos = 0 then exit('');
  37.   startPos := startPos + Length(startStr);
  38.   endPos := Pos(endStr, uppercase(str), startPos);
  39.   if endPos = 0 then exit('');
  40.   Result := Copy(str, startPos, endPos - startPos);
  41.   // strip the string
  42.   startPos := startPos - Length(startStr);
  43.   endPos := endPos + Length(endStr);
  44.   System.Delete(str, startPos, endPos - startPos);
  45. end;
  46.  
  47. constructor TUPnP.Create(const RouterIP: string);
  48. var
  49.   Socket: TUDPBlockSocket;
  50.   S, Location, Service: string;
  51.   Response: TStringList;
  52.   Cnt: integer;
  53. begin
  54.   FRootXML := '';
  55.  
  56.   Cnt := 0;
  57.  
  58.   S := 'M-SEARCH * HTTP/1.1'#13#10 + 'HOST: 239.255.255.250:1900'#13#10 + 'MAN: "ssdp:discover"'#13#10 + 'MX: 3'#13#10 + 'ST: upnp:rootdevice'#13#10#13#10;
  59.   Socket := TUDPBlockSocket.Create;
  60.   Socket.EnableBroadcast(True);
  61.   Socket.Connect(RouterIP, '1900');
  62.   Socket.SendString(S);
  63.   repeat
  64.     Inc(Cnt);
  65.     if Socket.CanRead(3000) then
  66.     begin
  67.       S := Socket.RecvPacket(3000);
  68.       if Pos('LOCATION: ', uppercase(S)) > 0 then
  69.       begin
  70.         Location := Copy(S, Pos('LOCATION:', uppercase(S)) + 9);
  71.         Location := Trim(Copy(Location, 1, Pos(#13#10, Location) - 1));
  72.         Response := TStringList.Create;
  73.         try
  74.  
  75.           HttpGetText(Location, Response);
  76.           FRootXML := Response.Text;
  77.  
  78.           FBaseURL := Location; // take base of Location for control
  79.           while (FBaseURL <> '') and (Location[Length(FBaseURL)] <> '/') do Delete(FBaseURL, Length(FBaseURL), 1);
  80.           if FBaseURL <> '' then Delete(FBaseURL, Length(FBaseURL), 1);
  81.  
  82.           // loop all services
  83.           repeat
  84.             Service := GetStringBetweenAndStrip(FRootXML, '<service>', '</service>');
  85.             if Pos(uppercase(':WANIPConnection:'), uppercase(service)) > 0 then
  86.             begin
  87.               S := GetStringBetweenAndStrip(Service, '<SCPDURL>', '</SCPDURL>');
  88.               if S <> '' then
  89.               begin
  90.                 Location := FBaseURL + S;
  91.                 HttpGetText(Location, Response);
  92.                 S := Response.Text;
  93.                 if Pos(uppercase('<name>AddPortMapping</name>'), uppercase(S)) > 0 then
  94.                 begin
  95.                   FServiceType := GetStringBetweenAndStrip(Service, '<serviceType>', '</serviceType>');
  96.                   S := GetStringBetweenAndStrip(Service, '<controlURL>', '</controlURL>');
  97.                   FControlURL := FBaseURL + S;
  98.                 end;
  99.               end;
  100.             end;
  101.           until service = '';
  102.  
  103.           break;
  104.  
  105.         finally
  106.           Response.Free;
  107.         end;
  108.  
  109.       end;
  110.  
  111.     end;
  112.  
  113.     sleep(100);
  114.  
  115.   until (Cnt > 1000);
  116.  
  117.   Socket.CloseSocket;
  118.   Socket.Free;
  119.  
  120. end;
  121.  
  122. function TUPnP.IsUPnPAvailable: boolean;
  123. begin
  124.   Result := FControlURL <> '';
  125. end;
  126.  
  127. function TUPnP.GetExternalIP: string;
  128. var
  129.   SoapRequest, SoapResponse: string;
  130. begin
  131.   SoapRequest :=
  132.     '<?xml version="1.0" encoding="utf-8"?>' +
  133.     '<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"' +
  134.     ' xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1">' +
  135.     '<s:Body>' +
  136.     '<u:GetExternalIPAddress xmlns:u="' + FServiceType + '">' +
  137.     '</u:GetExternalIPAddress>' +
  138.     '</s:Body>' +
  139.     '</s:Envelope>';
  140.  
  141.   ExecuteSoapAction('GetExternalIPAddress', SoapRequest, SoapResponse);
  142.  
  143.   Result := GetStringBetweenAndStrip(SoapResponse, '<NewExternalIPAddress>', '</NewExternalIPAddress>');
  144.  
  145. end;
  146.  
  147. function TUPnP.SetPortMapping(const InternalIP: string; InternalPort, ExternalPort: integer; Protocol: String = 'TCP'; Description: String = ''): Integer;
  148. var
  149.   SoapRequest, SoapResponse: string;
  150. begin
  151.   SoapRequest :=
  152.     '<?xml version="1.0" encoding="utf-8"?>' +
  153.     '<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"' +
  154.     ' xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1">' +
  155.     '<s:Body>' +
  156.     '<u:AddPortMapping xmlns:u="' + FServiceType + '">' +
  157.     '<NewRemoteHost></NewRemoteHost>' +
  158.     '<NewExternalPort>' + IntToStr(ExternalPort) + '</NewExternalPort>' +
  159.     '<NewProtocol>' + Protocol + '</NewProtocol>' +
  160.     '<NewInternalPort>' + IntToStr(InternalPort) + '</NewInternalPort>' +
  161.     '<NewInternalClient>' + InternalIP + '</NewInternalClient>' +
  162.     '<NewEnabled>1</NewEnabled>' +
  163.     '<NewPortMappingDescription>' + Description + '</NewPortMappingDescription>' +
  164.     '<NewLeaseDuration>0</NewLeaseDuration>' +
  165.     '</u:AddPortMapping>' +
  166.     '</s:Body>' +
  167.     '</s:Envelope>';
  168.  
  169.   Result := ExecuteSoapAction('AddPortMapping', SoapRequest, SoapResponse);
  170. end;
  171.  
  172. function TUPnP.DeletePortMapping(const ExternalPort: integer; Protocol: String = 'TCP'): Integer;
  173. var
  174.   SoapRequest, SoapResponse: string;
  175. begin
  176.   SoapRequest :=
  177.     '<?xml version="1.0" encoding="utf-8"?>' +
  178.     '<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"' + ' xmlns:u="' + FServiceType + '">' +
  179.     '<s:Body>' +
  180.     '<u:DeletePortMapping xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1">' +
  181.     '<NewRemoteHost></NewRemoteHost>' +
  182.     '<NewExternalPort>' + IntToStr(ExternalPort) + '</NewExternalPort>' +
  183.     '<NewProtocol>' + Protocol + '</NewProtocol>' +
  184.     '</u:DeletePortMapping>' +
  185.     '</s:Body>' +
  186.     '</s:Envelope>';
  187.  
  188.   Result := ExecuteSoapAction('DeletePortMapping', SoapRequest, SoapResponse);
  189.  
  190. end;
  191.  
  192. function TUPnP.ExecuteSoapAction(const Action, SoapRequest: string; var SoapResponse: string): Integer;
  193. var
  194.   HTTP: THTTPSend;
  195.   Response: TStringList;
  196. begin
  197.   Result := -1;
  198.   HTTP := THTTPSend.Create;
  199.   Response := TStringList.Create;
  200.   try
  201.     HTTP.Headers.Clear;
  202.     HTTP.Document.Position := 0;
  203.     WriteStrToStream(HTTP.Document, SoapRequest);
  204.     HTTP.MimeType := 'text/xml; charset="utf-8"';
  205.     HTTP.Headers.Add('SOAPAction: "' + FServiceType + '#' + Action + '"');
  206.     if HTTP.HTTPMethod('POST', FControlURL) then
  207.     begin
  208.       Response.LoadFromStream(HTTP.Document);
  209.       SoapResponse := Response.Text;
  210.       Result := HTTP.ResultCode;
  211.     end;
  212.   finally
  213.     HTTP.Free;
  214.     Response.Free;
  215.   end;
  216. end;
  217.  
  218. end.

rvk

  • Hero Member
  • *****
  • Posts: 6715
Re: [SOLVED] How to open UPnP port with synapse
« Reply #59 on: June 14, 2023, 11:54:13 am »
I have created a upnplib.pas and put it on github with an example.
https://github.com/rvk01/upnp

You can use it to list status info, create port mapping, delete port mapping and list port mappings.

(Still need to do discovery if the Gateway IP isn't provided)

Output of example program.
Quote
UPnP is available.

Internal IP: 192.168.2.11
External IP: x.x.x.x
Status: Connected
Last error: ERROR_NONE
Uptime router: 23 days, 4 hours 41 minutes and 24 seoconds

SetPortMapping OK
Portmappings:
0 UDP 3332->192.168.2.21:3332 libminiupnpc 0 s
1 UDP 3344->192.168.2.21:4444 test 0 s
2 TCP 8000->192.168.2.11:8081  0 s

Check port. Press Enter to delete and terminate


DeletePortMapping OK

Portmappings:
0 UDP 3332->192.168.2.21:3332 libminiupnpc 0 s
1 UDP 3344->192.168.2.21:4444 test 0 s

We are done, press enter

BTW. Can you check if the UDP entries of yesterday are still there for you?
For me they are, with lease duration of 0.
« Last Edit: June 14, 2023, 12:09:01 pm by rvk »

 

TinyPortal © 2005-2018