Solved

Port Mapping (Winsock API)

Posted on 2002-05-25
5
437 Views
Last Modified: 2010-04-04
Just wondering if anyone can provide me with an example on how to map a tcp port to a remote host/port. i need it to allow multiple clients to connect to the port, and redirect data to/from the remote host. a feature that isn't neccesary, but would help would be the ability to have multiple mappings, and an ability to enumerate/stop them. i've been trying to do something like this for a while, with no luck. thank you for any help. (please note i am doing this in Winsock API, i am not interested in code which uses components).
0
Comment
Question by:freedumb
  • 4
5 Comments
 
LVL 14

Expert Comment

by:AvonWyss
ID: 7035171
0
 
LVL 14

Accepted Solution

by:
AvonWyss earned 200 total points
ID: 7035173
(EE sometimes has this "No Text" problem. Hopefully it will work now.)

The following should do it. Note that I don't use anything from the VCL, its all pure Windows-API, Winsock-API and RTL (RunTime Library). Even so, it's object-oriented, multi-threaded, small and pretty fast.

Ta allow you to see the essential parts of the code, I have only included the very necessary error checking. For instance, if the remote host is not reachable, you will not get an error. Therefore, I strongly suggest to add more error checking for a serious application.

The useage is displayed in the bottom part. In this example, I map the port 1025 to the FTP port on the local machine. Of course, you can use any other IP address/port combination.

{$APPTYPE CONSOLE}

program PortMapper;

uses
     SysUtils, Windows, Winsock;

type
     TPortMapper=class
     private
          FLocalEP, FRemoteEP: TSockAddrIn;
          FThreadHandle, FSyncEvent: THandle;
          FThreadID: Cardinal;
          FPending, FListener: TSocket;
          procedure Listener;
          procedure Transfer;
     public
          constructor Create(const LocalEndPoint, RemoteEndPoint: TSockAddrIn);
          destructor Destroy; override;
     end;

{ TPortMapper }

constructor TPortMapper.Create(const LocalEndPoint,     RemoteEndPoint: TSockAddrIn);
begin
     inherited Create;
     FLocalEP:=LocalEndPoint;
     FRemoteEP:=RemoteEndPoint;
     FThreadHandle:=BeginThread(nil, 0, Pointer(@TPortMapper.Listener), self, 0, FThreadID);
end;

destructor TPortMapper.Destroy;
begin
     CloseSocket(FListener);
     WaitForSingleObject(FThreadHandle, INFINITE);
     CloseHandle(FThreadHandle);
     inherited;
end;

procedure TPortMapper.Listener;
begin
     FSyncEvent:=CreateEvent(nil, False, False, nil);
     FListener:=Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // internet socket, stream, TCP protocol
     Bind(FListener, FLocalEP, SizeOf(FLocalEP));
     Listen(FListener, 5);
     repeat
          FPending:=Accept(FListener, nil, nil); // wait for incoming connection
          if FPending<>INVALID_SOCKET then begin // if valid socket, create connection thread
               CloseHandle(BeginThread(nil, 0, Pointer(@TPortMapper.Transfer), self, 0, FThreadID));
               WaitForSingleObject(FSyncEvent, INFINITE);
          end;
     until FPending=INVALID_SOCKET;
     CloseHandle(FSyncEvent);
end;

procedure TPortMapper.Transfer;
var
     Local, Remote: TSocket;
     FD: TFDSet;
     function TransferData(FromSock, ToSock: TSocket): Boolean;
     var
          Buffer: packed array[0..1023] of Byte;
          Waiting, Sent: Integer;
     begin
          IOCtlSocket(FromSock, FIONREAD, Waiting);
          repeat
               Sent:=Send(ToSock, Buffer, Recv(FromSock, Buffer, SizeOf(Buffer), 0), 0);
               Dec(Waiting, Sent);
          until (Sent<=0) or (Waiting<=0);
          Result:=Sent>0;
     end;
begin
     Local:=FPending;
     SetEvent(FSyncEvent);
     Remote:=Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
     Connect(Remote, FRemoteEP, SizeOf(FRemoteEP));
     repeat
          FD_ZERO(FD);
          FD_SET(Local, FD);
          FD_SET(Remote, FD);
          Select(0, @FD, nil, nil, nil);
     until (FD_ISSET(Local, FD) and (not TransferData(Local, Remote))) or (FD_ISSET(Remote, FD) and (not TransferData(Remote, Local)));
     CloseSocket(Remote);
     CloseSocket(Local);
end;

var
     WSAData: TWSAData;
     Mapper: TPortMapper;
     LocalEP, RemoteEP: TSockAddrIn;

begin
     WSAStartup($101, WSAData);
     // the local endpoint is the address on which the mapper will listen locally
     LocalEP.sin_family:=AF_INET; // internet protocol
     LocalEP.sin_port:=HToNS(1025); // port 1025
     LocalEP.sin_addr.S_addr:=INADDR_ANY; // listen on all local IP addresses
     // the remote endpoint is the address where the mapper connects to
     RemoteEP.sin_family:=AF_INET;
     RemoteEP.sin_port:=HToNS(21); // remote port: 21 (FTP)
     RemoteEP.sin_addr.S_addr:=HToNL(INADDR_LOOPBACK); // remote IP: 127.0.0.1 (localhost)
     // the mapper object uses its own thread, so that the mapping is active after creation
     Mapper:=TPortMapper.Create(LocalEP, RemoteEP);
     ReadLn; // wait for return key
     Mapper.Free;
     WSACleanup;
end.
0
 
LVL 14

Expert Comment

by:AvonWyss
ID: 7035175
Of course, you can create as many instances of TPortMapper as you need for the different mappings, and you can store them in a list or array so that you can enumerate them.
0
 
LVL 14

Expert Comment

by:AvonWyss
ID: 7035180
freedumb, while looking at your profile I have seen that you are new to Experts Exchange. Therefore, let me welcome you!

In order to get the most out of Experts Exchange, please make sure to read and understand the guidelines and suggestions provided by the Expert Exchange staff. One point that often lead to misunderstandings is the grading and points distribution. The grade you award does not change the cost of points to you, but it does influence the amount of expert points an expert gets. Therefore, if you are not fully happy with a comment or answer provided, please do first give the expert to refine the comment or answer prior to giving a grade less than A. If you give a lesser grade, please also inform the expert why. This helps everyone here to provide a much higher quality of answers and comments than what you can find on most forums etc. on the net.
0
 

Author Comment

by:freedumb
ID: 7035428
Thanks for all your help, got it all working. :)
0

Featured Post

NAS Cloud Backup Strategies

This article explains backup scenarios when using network storage. We review the so-called “3-2-1 strategy” and summarize the methods you can use to send NAS data to the cloud

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
Microsoft Active Directory, the widely used IT infrastructure, is known for its high risk of credential theft. The best way to test your Active Directory’s vulnerabilities to pass-the-ticket, pass-the-hash, privilege escalation, and malware attacks …
This video shows how to use Hyena, from SystemTools Software, to bulk import 100 user accounts from an external text file. View in 1080p for best video quality.

809 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question