Recent

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

Key-Real

  • Full Member
  • ***
  • Posts: 189
[SOLVED] How to open UPnP port with synapse
« on: June 13, 2023, 11:39:49 am »
Hi

I cant open a port with UPnP :(


my Server to listen:

the Server works if I do PortForwarding
Code: Pascal  [Select][+][-]
  1. {$MODE OBJFPC}{$H+}
  2. uses
  3.     blcksock, sockets, Synautil, SysUtils, HTTPSend, synaip, Process, synamisc, crt;
  4. var
  5.     soket : TUDPBlockSocket;                             
  6.  
  7. begin
  8.    
  9.     soket:= TUDPBlockSocket.Create;
  10.     soket.bind('0.0.0.0', '4444');
  11.  
  12.     readln;
  13.     soket.Free;
  14. end.
  15.  

my Code to open the port:

Code: Pascal  [Select][+][-]
  1. {$MODE OBJFPC}{$H+}
  2. uses httpsend,sysutils,classes,synautil;
  3. var
  4.         f : text;
  5.         post : string;
  6.         s : string;
  7.         http : THTTPSend;
  8.         Response : TStringList;
  9. begin
  10.  
  11.         assignfile(f, 'add.xml');
  12.         reset(f);
  13.         post:= '';
  14.         repeat
  15.                 readln(f, s);
  16.                 post:= post + s;
  17.         until eof(f);
  18.         close(f);
  19.  
  20.  
  21.         //writeln(post);
  22.  
  23.         http:=THTTPSend.Create;
  24.  
  25.         http.Document.Clear;
  26.      WriteStrToStream(HTTP.Document, post);    
  27.      http.MimeType:='text/xml; charset="UTF-8"';
  28.      http.Headers.Add('SOAPAction: "urn:schemas-upnp-org:service:WANIPConnection:1#AddPortMapping"');
  29.  
  30.         if not http.HTTPMethod('POST', 'http://192.168.0.1/upnp/control/WANIPConnection0') then begin
  31.         end;
  32.  
  33.         writeln(http.ResultCode);
  34.         writeln(http.ResultString);
  35.    
  36.         Response:= TStringList.Create;
  37.         Response.LoadFromStream(HTTP.Document);
  38.         s:= Response.Text;
  39.         writeln(s);
  40.  
  41.         http.Free;
  42.         Response.Free;
  43. end.
  44.  

the add.xml:

Code: Pascal  [Select][+][-]
  1. <?xml version="1.0"?>
  2. <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
  3. <SOAP-ENV:Body>
  4.     <m:AddPortMapping xmlns:m="urn:schemas-upnp-org:service:WANIPConnection:1">
  5.         <NewPortMappingDescription>test</NewPortMappingDescription>
  6.         <NewLeaseDuration>0</NewLeaseDuration>
  7.         <NewInternalClient>192.168.0.4</NewInternalClient>
  8.         <NewEnabled>True</NewEnabled>
  9.         <NewExternalPort>3333</NewExternalPort>
  10.         <NewRemoteHost></NewRemoteHost>
  11.         <NewProtocol>UDP</NewProtocol>
  12.         <NewInternalPort>4444</NewInternalPort>
  13.     </m:AddPortMapping>
  14. </SOAP-ENV:Body>
  15. </SOAP-ENV:Envelope>
  16.  


the controll.xml sniped from my router:

Code: Pascal  [Select][+][-]
  1. <serviceList>
  2. <service>
  3. <serviceType>urn:schemas-upnp-org:service:WANIPConnection:1</serviceType>
  4. <serviceId>urn:upnp-org:serviceId:WANIPConn1</serviceId>
  5. <SCPDURL>/WANIPConnectionServiceSCPD.xml</SCPDURL>
  6. <controlURL>/upnp/control/WANIPConnection0</controlURL>
  7. <eventSubURL>/upnp/event/WANIPConnection0</eventSubURL>
  8. </service>
  9. </serviceList>
  10.  


I get this if I send the M-SEARCH to my router:
Code: Pascal  [Select][+][-]
  1. HTTP/1.1 200 OK
  2. CACHE-CONTROL: max-age=1800
  3. DATE: Tue, 13 Jun 2023 09:35:31 GMT
  4. EXT:
  5. LOCATION: http://192.168.0.1:49153/IGDdevicedesc_brlan0.xml
  6. OPT: "http://schemas.upnp.org/upnp/1/0/"; ns=01
  7. 01-NLS: b8c5fa84-09cc-11ee-a2e9-9217cd6c62d8
  8. SERVER: Linux/4.9.135-Prod_19.3, UPnP/1.0, Portable SDK for UPnP devices/1.6.22
  9. X-User-Agent: redsonic
  10. ST: upnp:rootdevice
  11. USN: uuid:ebf5a0a0-1dd1-11b2-a90f-021018951e6c::upnp:rootdevice
  12.  


I check the openPort with nmap

Code: Pascal  [Select][+][-]
  1. sudo nmap -sU -v -p 3333 31.18.77.240


what do I did wrong?
« Last Edit: June 13, 2023, 06:32:53 pm by Key-Real »

rvk

  • Hero Member
  • *****
  • Posts: 6159
Re: How to open UPnP port?
« Reply #1 on: June 13, 2023, 11:55:02 am »
what do I did wrong?
Well, you don't mention to us what the result of the POST to WANIPConnection0 is.

Are you sure UPnP is enabled on your router?

And you don't need to check with nmap. Just check in the router itself if the UPnP is done correctly (there should be a list for this).
And otherwise you can do a POST with #GetGenericPortMappingEntry to get the ports.

(You can also check with the utility miniupnp to see if the redirect is done correctly.)

PS. The xml is correct (assuming the internal IP is correct). With the same code (changing the internal IP) the xml works for me.
« Last Edit: June 13, 2023, 12:15:41 pm by rvk »

Key-Real

  • Full Member
  • ***
  • Posts: 189
Re: How to open UPnP port?
« Reply #2 on: June 13, 2023, 01:20:11 pm »
then i do:

Code: Pascal  [Select][+][-]
  1. #! /usr/bin/env python
  2. import miniupnpc
  3.  
  4. # create the object
  5. u = miniupnpc.UPnP()
  6. u.discoverdelay = 200;
  7.  
  8.  
  9. print('Discovering... delay=%ums' % u.discoverdelay)
  10. ndevices = u.discover()
  11. print(ndevices, 'device(s) detected')
  12.  
  13. # select an igd
  14. u.selectigd()
  15.  
  16. print('local ip address :', u.lanaddr)
  17. externalipaddress = u.externalipaddress()
  18. print('external ip address :', externalipaddress)
  19.  
  20.  
  21. try:
  22.        
  23.         u.addportmapping(4444, 'UDP', u.lanaddr, 4444, 'test', '')
  24.  
  25. except:
  26.  
  27.         print('Fail')
  28.  

and after that I start my server it works.




I have a code to return a M-SEARCH message from Router:

Code: Pascal  [Select][+][-]
  1. {$MODE OBJFPC}
  2. uses
  3.     sockets, SysUtils;
  4.  
  5. procedure SocketError(s:string);
  6. begin
  7.     writeln('Scket Error: ', s);
  8.     halt(1);
  9. end;
  10.  
  11. const
  12.         MS = 'M-SEARCH * HTTP/1.1' + #$0D + #$0A +
  13.     'HOST:239.255.255.250:1900' + #$0D + #$0A +
  14.     'ST:upnp:rootdevice' + #$0D + #$0A +
  15.     'MX:2' + #$0D + #$0A +
  16.     'MAN:"ssdp:discover"' + #$0D + #$0A +
  17.     #$0D + #$0A;
  18.  
  19. var
  20.         socket : longint;
  21.         addr : sockaddr_in;
  22.         slen : dword;
  23.         buf : array [0..8192] of char;
  24. begin
  25.         socket:= fpsocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  26.     if socket = -1 then SocketError('Init Socket');
  27.  
  28.         fillchar(addr, 0, sizeof(addr));
  29.     addr.sin_family:= AF_INET;
  30.         addr.sin_addr:= StrToNetAddr('239.255.255.250');
  31.         addr.sin_port:= htons(1900);
  32.  
  33.         slen:= sizeof(addr);
  34.  
  35.         if fpsendto(socket, pchar(MS), sizeof(MS), 0, @addr, sizeof(addr)) = -1 then SocketError('send MS message');
  36.  
  37.         if fprecvfrom(socket, @buf, sizeof(buf), 0, @addr, @slen) = -1 then SocketError('Receive message from Router');
  38.  
  39.         writeln('router send me this ip and address as response: ',NetAddrToStr(addr.sin_addr), ':', addr.sin_port);
  40.  
  41.         writeln(buf);
  42.  
  43.     closeSocket(socket);
  44. end.
  45.  



it returns:

Code: Pascal  [Select][+][-]
  1. router send me this ip and address as response: 192.168.0.1:63633
  2. HTTP/1.1 200 OK
  3. CACHE-CONTROL: max-age=1800
  4. DATE: Tue, 13 Jun 2023 11:06:18 GMT
  5. EXT:
  6. LOCATION: http://192.168.0.1:49153/IGDdevicedesc_brlan0.xml
  7. OPT: "http://schemas.upnp.org/upnp/1/0/"; ns=01
  8. 01-NLS: b8c5fa84-09cc-11ee-a2e9-9217cd6c62d8
  9. SERVER: Linux/4.9.135-Prod_19.3, UPnP/1.0, Portable SDK for UPnP devices/1.6.22
  10. X-User-Agent: redsonic
  11. ST: upnp:rootdevice
  12. USN: uuid:ebf5a0a0-1dd1-11b2-a90f-021018951e6c::upnp:rootdevice
  13.  


so I do:

Code: Pascal  [Select][+][-]
  1.  {$MODE OBJFPC}{$H+}
  2. uses httpsend,sysutils,classes,synautil;
  3.  
  4. var
  5.   S, Found: String;
  6.   HTTP: THTTPSend;
  7.   Location,ServiceType : String;
  8.   Response : TStringList;
  9.   f:text;
  10. begin  
  11.  
  12.         // SHOULD I ADD THE PORT NUMBER QUTED IN THE root.xml ?
  13.  
  14.         // the port 63633 is returned router address on the resoponse to the M-SEARCH  
  15.         // nothing happens
  16.         // The port: 49153 is retrunden in the M-SEARCH MESSAGE itself
  17.         // here i get 400 Bad Request
  18.         // without the port I get a long response, I post it
  19.  
  20.   Location := 'http://192.168.0.1/upnp/control/WANIPConnection0';
  21.  
  22.  
  23.  
  24.  
  25.  
  26.   ServiceType := 'urn:schemas-upnp-org:service:WANIPConnection:1';
  27.  
  28.   S := '';
  29.   S := S + '<?xml version="1.0" encoding="utf-8"?>';
  30.   S := S + '<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">';
  31.   S := S + ' <s:Body>';
  32.   S := S + '  <u:GetGenericPortMappingEntry xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1">';
  33.   S := S + '   <NewPortMappingIndex>0</NewPortMappingIndex>';
  34.   S := S + '  </u:GetGenericPortMappingEntry>';
  35.   S := S + ' </s:Body>';
  36.   S := S + '</s:Envelope>';
  37.  
  38.   Response := TStringList.Create;
  39.   HTTP := THTTPSend.Create;
  40.   try
  41.     WriteStrToStream(HTTP.Document, S);
  42.     HTTP.MimeType := 'text/xml; charset="utf-8"';
  43.     HTTP.Headers.Add('SOAPAction: ' + ServiceType + '#GetGenericPortMappingEntry');
  44.     if HTTP.HTTPMethod('POST', Location) then
  45.     begin
  46.       Response.LoadFromStream(HTTP.Document);
  47.       Found := Response.Text;
  48.       writeln(found);
  49.     end;
  50.   finally
  51.     Response.Free;
  52.     HTTP.Free;
  53.   end;
  54.  
  55. assign(f,'res.html');
  56. rewrite(f);
  57. writeln(f,found);
  58. close(f);
  59. end.
  60.  

the response I put in attachment


PS: Unfortunly my Router doesn't list the UPnP ports


PSS:
I posted a sniped of my conrtoll.xml (or root.xml).
It is retruned by
http://192.168.0.1:49153/IGDdevicedesc_brlan0.xml
« Last Edit: June 13, 2023, 01:33:35 pm by Key-Real »

rvk

  • Hero Member
  • *****
  • Posts: 6159
Re: How to open UPnP port?
« Reply #3 on: June 13, 2023, 01:33:36 pm »
Yeah, that result is just html.
You are quering port 80.

You should include the found port in your location.
:49153

So
Code: Pascal  [Select][+][-]
  1. Location := 'http://192.168.0.1:49153/upnp/control/WANIPConnection0';

Key-Real

  • Full Member
  • ***
  • Posts: 189
Re: How to open UPnP port?
« Reply #4 on: June 13, 2023, 01:35:20 pm »

Code: Pascal  [Select][+][-]
  1.   Location := 'http://192.168.0.1:49153/upnp/control/WANIPConnection0';
  2.  

Code: Pascal  [Select][+][-]
  1. <html><body><h1>400 Bad Request</h1></body></html>
  2.  

rvk

  • Hero Member
  • *****
  • Posts: 6159
Re: How to open UPnP port?
« Reply #5 on: June 13, 2023, 01:58:33 pm »
Weird. Here my code from a few weeks ago (which lists the UPnP redirects).

I used hardcode for Gateway but you could put in some code to check for the correct one.
(So I didn't loop all results from M-SEARCH but directly send an M-SEARCH to the known gateway)

Put the exact code in a program and run it. What is the output?

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.   function GetStringBetweenAndStrip(var str: string; startStr, endStr: string): string;
  13.   var
  14.     startPos, endPos: integer;
  15.   begin
  16.     startStr := uppercase(startStr);
  17.     endStr := uppercase(endStr);
  18.     startPos := Pos(startStr, uppercase(str));
  19.     if startPos = 0 then exit('');
  20.     startPos := startPos + Length(startStr);
  21.     endPos := Pos(endStr, uppercase(str), startPos);
  22.     if endPos = 0 then exit('');
  23.     Result := Copy(str, startPos, endPos - startPos);
  24.     // strip the string
  25.     startPos := startPos - Length(startStr);
  26.     endPos := endPos + Length(endStr);
  27.     System.Delete(str, startPos, endPos - startPos);
  28.   end;
  29.  
  30. var
  31.   GatewayIP, Location, Base, Found, Found1, Service, S: string;
  32.   ServiceType: string;
  33.   Socket: TUDPBlockSocket;
  34.   Response: TStringList;
  35.   HTTP: THTTPSend;
  36.   ResultCode: integer;
  37.   Idx: integer;
  38.   eH, eP, Pr, iP, iH, iE, iD, iL: string;
  39. begin
  40.  
  41.   GatewayIP := '192.168.0.1';  // I used hardcoded Gateway here. You can also listen for any other upnp device and pick that one.
  42.  
  43.   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;
  44.   Socket := TUDPBlockSocket.Create;
  45.   Socket.EnableBroadcast(True);
  46.   Socket.Connect(GatewayIP, '1900');
  47.   Socket.SendString(S);
  48.   repeat
  49.     if Socket.CanRead(3000) then
  50.     begin
  51.       Found := Socket.RecvPacket(3000);
  52.       if Pos('LOCATION: ', uppercase(Found)) > 0 then
  53.       begin
  54.         Location := Copy(Found, Pos('LOCATION:', uppercase(Found)) + 9);
  55.         Location := Trim(Copy(Location, 1, Pos(#13#10, Location) - 1));
  56.         writeln('Location is ' + Location);
  57.         Response := TStringList.Create;
  58.         try
  59.  
  60.           HttpGetText(Location, Response);
  61.           Found := Response.Text;
  62.  
  63.           Base := Location; // take base of Location for control
  64.           while (Base <> '') and (Location[Length(Base)] <> '/') do Delete(Base, Length(Base), 1);
  65.           if Base <> '' then Delete(Base, Length(Base), 1);
  66.           writeln('Base is ' + Base);
  67.  
  68.           // loop all services
  69.           repeat
  70.             Service := GetStringBetweenAndStrip(Found, '<service>', '</service>');
  71.             if Pos(uppercase(':WANIPConnection:'), uppercase(service)) > 0 then
  72.             begin
  73.               S := GetStringBetweenAndStrip(Service, '<SCPDURL>', '</SCPDURL>');
  74.               if S <> '' then
  75.               begin
  76.                 Location := Base + S;
  77.                 writeln('Control URL is ' + Location);
  78.                 HttpGetText(Location, Response);
  79.                 S := Response.Text;
  80.                 if Pos(uppercase('<name>AddPortMapping</name>'), uppercase(S)) > 0 then
  81.                 begin
  82.                   ServiceType := GetStringBetweenAndStrip(Service, '<serviceType>', '</serviceType>');
  83.                   S := GetStringBetweenAndStrip(Service, '<controlURL>', '</controlURL>');
  84.                   Location := Base + S;
  85.  
  86.                   Idx := 0;
  87.                   repeat
  88.  
  89.                     S := '';
  90.                     S := S + '<?xml version="1.0" encoding="utf-8"?>';
  91.                     S := S + '<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">';
  92.                     S := S + ' <s:Body>';
  93.                     S := S + '  <u:GetGenericPortMappingEntry xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1">';
  94.                     S := S + '   <NewPortMappingIndex>' + IntToStr(Idx) + '</NewPortMappingIndex>';
  95.                     S := S + '  </u:GetGenericPortMappingEntry>';
  96.                     S := S + ' </s:Body>';
  97.                     S := S + '</s:Envelope>';
  98.  
  99.                     HTTP := THTTPSend.Create;
  100.                   try
  101.  
  102.                     WriteStrToStream(HTTP.Document, S);
  103.                     HTTP.MimeType := 'text/xml; charset="utf-8"';
  104.                     HTTP.Headers.Add('SOAPAction: ' + ServiceType + '#GetGenericPortMappingEntry');
  105.  
  106.                     if HTTP.HTTPMethod('POST', Location) then
  107.                     begin
  108.                       Resultcode := HTTP.ResultCode;
  109.                       Response.LoadFromStream(HTTP.Document);
  110.                       Found := Response.Text;
  111.                       // writeln(found);
  112.                       repeat
  113.                         Found1 := GetStringBetweenAndStrip(Found, '<u:GetGenericPortMappingEntryResponse', '</u:GetGenericPortMappingEntryResponse>');
  114.                         if Found1 <> '' then
  115.                         begin
  116.                           eH := GetStringBetweenAndStrip(Found1, '<NewRemoteHost>', '</NewRemoteHost>');
  117.                           eP := GetStringBetweenAndStrip(Found1, '<NewExternalPort>', '</NewExternalPort>');
  118.                           Pr := GetStringBetweenAndStrip(Found1, '<NewProtocol>', '</NewProtocol>');
  119.                           iP := GetStringBetweenAndStrip(Found1, '<NewInternalPort>', '</NewInternalPort>');
  120.                           iH := GetStringBetweenAndStrip(Found1, '<NewInternalClient>', '</NewInternalClient>');
  121.                           iE := GetStringBetweenAndStrip(Found1, '<NewEnabled>', '<NewEnabled>');
  122.                           iD := GetStringBetweenAndStrip(Found1, '<NewPortMappingDescription>', '</NewPortMappingDescription>');
  123.                           iL := GetStringBetweenAndStrip(Found1, '<NewLeaseDuration>', '</NewLeaseDuration>');
  124.                           S := Format('%s %s:%s -> %s:%s En: %s  De: %s  Le: %s', [Pr, eH, eP, iH, iP, iE, iD, iL]);
  125.                           writeln(S);
  126.                         end;
  127.                       until Found1 = '';
  128.                     end;
  129.  
  130.                   finally
  131.                     HTTP.Free;
  132.                   end;
  133.                   Inc(Idx);
  134.                   until Resultcode <> 200;
  135.  
  136.                 end;
  137.  
  138.               end;
  139.  
  140.             end;
  141.  
  142.           until service = '';
  143.  
  144.         finally
  145.           Response.Free;
  146.         end;
  147.       end;
  148.       break;
  149.     end;
  150.     sleep(100);
  151.   until False;
  152.   Socket.CloseSocket;
  153.   Socket.Free;
  154.   writeln('we are done, press enter');
  155.   readln;
  156.  
  157. end.

Key-Real

  • Full Member
  • ***
  • Posts: 189
Re: How to open UPnP port?
« Reply #6 on: June 13, 2023, 02:02:50 pm »
I started the python script, than
I started the program as it is

Code: Pascal  [Select][+][-]
  1. Location is http://192.168.0.1:49153/IGDdevicedesc_brlan0.xml
  2. Base is http://192.168.0.1:49153
  3. Control URL is http://192.168.0.1:49153/WANIPConnectionServiceSCPD.xml
  4. we are done, press enter
  5.  

rvk

  • Hero Member
  • *****
  • Posts: 6159
Re: How to open UPnP port?
« Reply #7 on: June 13, 2023, 02:09:51 pm »
That seems to be correct.
(I made an error. I printed the SCPDUrl as Control URL.)

It should be:

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.   function GetStringBetweenAndStrip(var str: string; startStr, endStr: string): string;
  13.   var
  14.     startPos, endPos: integer;
  15.   begin
  16.     startStr := uppercase(startStr);
  17.     endStr := uppercase(endStr);
  18.     startPos := Pos(startStr, uppercase(str));
  19.     if startPos = 0 then exit('');
  20.     startPos := startPos + Length(startStr);
  21.     endPos := Pos(endStr, uppercase(str), startPos);
  22.     if endPos = 0 then exit('');
  23.     Result := Copy(str, startPos, endPos - startPos);
  24.     // strip the string
  25.     startPos := startPos - Length(startStr);
  26.     endPos := endPos + Length(endStr);
  27.     System.Delete(str, startPos, endPos - startPos);
  28.   end;
  29.  
  30. var
  31.   GatewayIP, Location, Base, Found, Found1, Service, S: string;
  32.   ServiceType: string;
  33.   Socket: TUDPBlockSocket;
  34.   Response: TStringList;
  35.   HTTP: THTTPSend;
  36.   ResultCode: integer;
  37.   Idx: integer;
  38.   eH, eP, Pr, iP, iH, iE, iD, iL: string;
  39. begin
  40.  
  41.   GatewayIP := '192.168.0.1';  // I used hardcoded Gateway here. You can also listen for any other upnp device and pick that one.
  42.  
  43.   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;
  44.   Socket := TUDPBlockSocket.Create;
  45.   Socket.EnableBroadcast(True);
  46.   Socket.Connect(GatewayIP, '1900');
  47.   Socket.SendString(S);
  48.   repeat
  49.     if Socket.CanRead(3000) then
  50.     begin
  51.       Found := Socket.RecvPacket(3000);
  52.       if Pos('LOCATION: ', uppercase(Found)) > 0 then
  53.       begin
  54.         Location := Copy(Found, Pos('LOCATION:', uppercase(Found)) + 9);
  55.         Location := Trim(Copy(Location, 1, Pos(#13#10, Location) - 1));
  56.         writeln('Location is ' + Location);
  57.         Response := TStringList.Create;
  58.         try
  59.  
  60.           HttpGetText(Location, Response);
  61.           Found := Response.Text;
  62.  
  63.           Base := Location; // take base of Location for control
  64.           while (Base <> '') and (Location[Length(Base)] <> '/') do Delete(Base, Length(Base), 1);
  65.           if Base <> '' then Delete(Base, Length(Base), 1);
  66.           writeln('Base is ' + Base);
  67.  
  68.           // loop all services
  69.           repeat
  70.             Service := GetStringBetweenAndStrip(Found, '<service>', '</service>');
  71.             if Pos(uppercase(':WANIPConnection:'), uppercase(service)) > 0 then
  72.             begin
  73.               S := GetStringBetweenAndStrip(Service, '<SCPDURL>', '</SCPDURL>');
  74.               if S <> '' then
  75.               begin
  76.                 Location := Base + S;
  77.                 writeln('SCPDURL is ' + Location);
  78.                 HttpGetText(Location, Response);
  79.                 S := Response.Text;
  80.                 if Pos(uppercase('<name>AddPortMapping</name>'), uppercase(S)) > 0 then
  81.                 begin
  82.                   ServiceType := GetStringBetweenAndStrip(Service, '<serviceType>', '</serviceType>');
  83.                   S := GetStringBetweenAndStrip(Service, '<controlURL>', '</controlURL>');
  84.                   Location := Base + S;
  85.                   writeln('Control URL is ' + Location);
  86.  
  87.                   Idx := 0;
  88.                   repeat
  89.  
  90.                     S := '';
  91.                     S := S + '<?xml version="1.0" encoding="utf-8"?>';
  92.                     S := S + '<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">';
  93.                     S := S + ' <s:Body>';
  94.                     S := S + '  <u:GetGenericPortMappingEntry xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1">';
  95.                     S := S + '   <NewPortMappingIndex>' + IntToStr(Idx) + '</NewPortMappingIndex>';
  96.                     S := S + '  </u:GetGenericPortMappingEntry>';
  97.                     S := S + ' </s:Body>';
  98.                     S := S + '</s:Envelope>';
  99.  
  100.                     HTTP := THTTPSend.Create;
  101.                   try
  102.  
  103.                     WriteStrToStream(HTTP.Document, S);
  104.                     HTTP.MimeType := 'text/xml; charset="utf-8"';
  105.                     HTTP.Headers.Add('SOAPAction: ' + ServiceType + '#GetGenericPortMappingEntry');
  106.  
  107.                     if HTTP.HTTPMethod('POST', Location) then
  108.                     begin
  109.                       Resultcode := HTTP.ResultCode;
  110.                       Response.LoadFromStream(HTTP.Document);
  111.                       Found := Response.Text;
  112.                       // writeln(found);
  113.                       repeat
  114.                         Found1 := GetStringBetweenAndStrip(Found, '<u:GetGenericPortMappingEntryResponse', '</u:GetGenericPortMappingEntryResponse>');
  115.                         if Found1 <> '' then
  116.                         begin
  117.                           eH := GetStringBetweenAndStrip(Found1, '<NewRemoteHost>', '</NewRemoteHost>');
  118.                           eP := GetStringBetweenAndStrip(Found1, '<NewExternalPort>', '</NewExternalPort>');
  119.                           Pr := GetStringBetweenAndStrip(Found1, '<NewProtocol>', '</NewProtocol>');
  120.                           iP := GetStringBetweenAndStrip(Found1, '<NewInternalPort>', '</NewInternalPort>');
  121.                           iH := GetStringBetweenAndStrip(Found1, '<NewInternalClient>', '</NewInternalClient>');
  122.                           iE := GetStringBetweenAndStrip(Found1, '<NewEnabled>', '<NewEnabled>');
  123.                           iD := GetStringBetweenAndStrip(Found1, '<NewPortMappingDescription>', '</NewPortMappingDescription>');
  124.                           iL := GetStringBetweenAndStrip(Found1, '<NewLeaseDuration>', '</NewLeaseDuration>');
  125.                           S := Format('%s %s:%s -> %s:%s En: %s  De: %s  Le: %s', [Pr, eH, eP, iH, iP, iE, iD, iL]);
  126.                           writeln(S);
  127.                         end;
  128.                       until Found1 = '';
  129.                     end;
  130.  
  131.                   finally
  132.                     HTTP.Free;
  133.                   end;
  134.                   Inc(Idx);
  135.                   until Resultcode <> 200;
  136.  
  137.                 end;
  138.  
  139.               end;
  140.  
  141.             end;
  142.  
  143.           until service = '';
  144.  
  145.         finally
  146.           Response.Free;
  147.         end;
  148.       end;
  149.       break;
  150.     end;
  151.     sleep(100);
  152.   until False;
  153.   Socket.CloseSocket;
  154.   Socket.Free;
  155.   writeln('we are done, press enter');
  156.   readln;
  157.  
  158. end.

For me this results in (using 192.168.2.1 as my gateway of course):

Code: [Select]
Location is http://192.168.2.1:60687/rootDesc.xml
Base is http://192.168.2.1:60687
SCPDURL is http://192.168.2.1:60687/WANIPCn.xml
Control URL is http://192.168.2.1:60687/ctl/IPConn
UDP :3333 -> 192.168.2.21:4444 En:   De: test  Le: 0
we are done, press enter

(I've already successfully inserted that port 4444 with your code.)


Key-Real

  • Full Member
  • ***
  • Posts: 189
Re: How to open UPnP port?
« Reply #8 on: June 13, 2023, 02:12:44 pm »
Code: Pascal  [Select][+][-]
  1. Location is http://192.168.0.1:49153/IGDdevicedesc_brlan0.xml
  2. Base is http://192.168.0.1:49153
  3. SCPDURL is http://192.168.0.1:49153/WANIPConnectionServiceSCPD.xml
  4. Control URL is http://192.168.0.1:49153/upnp/control/WANIPConnection0
  5. we are done, press enter
  6.  

rvk

  • Hero Member
  • *****
  • Posts: 6159
Re: How to open UPnP port?
« Reply #9 on: June 13, 2023, 02:18:33 pm »
Here is code for adding a port and querying it aftwerwards. (I used port 3331 here for clarity)
Note: 192.168.0.4 needs to be an existing computer in the network.

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

rvk

  • Hero Member
  • *****
  • Posts: 6159
Re: How to open UPnP port?
« Reply #10 on: June 13, 2023, 02:21:03 pm »
I hardcoded the http.Headers.Add('SOAPAction: in my previous example.
That should be the exact ServiceType as the xml descibed (see the GetGenericPortMappingEntry code).

But for now they are the same so the example should work.

Key-Real

  • Full Member
  • ***
  • Posts: 189
Re: How to open UPnP port?
« Reply #11 on: June 13, 2023, 02:21:56 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
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<s:Fault>
<faultcode>s:Client</faultcode>
<faultstring>UPnPError</faultstring>
<detail>
<UPnPError xmlns="urn:schemas-upnp-org:control-1-0">
<errorCode>402</errorCode>
<errorDescription>PAL_UPNP_SOAP_E_INVALID_ARGS</errorDescription>
</UPnPError>
</detail>
</s:Fault>
</s:Body>
</s:Envelope>
« Last Edit: June 13, 2023, 02:46:34 pm by Key-Real »

rvk

  • Hero Member
  • *****
  • Posts: 6159
Re: How to open UPnP port?
« Reply #12 on: June 13, 2023, 02:23:06 pm »
Ah, progress  :D

<faultcode>s:Client</faultcode>
Is that 192.168.0.4 a valid computer?

Key-Real

  • Full Member
  • ***
  • Posts: 189
Re: How to open UPnP port?
« Reply #13 on: June 13, 2023, 02:24:23 pm »
Quote
[key-real@koshka upnp]$ ip address
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: enp7s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether d8:bb:c1:a2:2b:35 brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.4/24 metric 100 brd 192.168.0.255 scope global dynamic enp7s0
       valid_lft 586912sec preferred_lft 586912sec
    inet6 fe80::dabb:c1ff:fea2:2b35/64 scope link
       valid_lft forever preferred_lft forever
3: wlo1: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
    link/ether 60:dd:8e:a5:2f:a8 brd ff:ff:ff:ff:ff:ff
    altname wlp0s20f3
« Last Edit: June 13, 2023, 02:46:20 pm by Key-Real »

rvk

  • Hero Member
  • *****
  • Posts: 6159
Re: How to open UPnP port?
« Reply #14 on: June 13, 2023, 02:38:35 pm »
Is the miniupnpc utility able to insert a portforward?
Or does that also give an error?

http://miniupnp.free.fr/

Code: [Select]
/usr/bin/upnpc -r 3332 UDP

 

TinyPortal © 2005-2018