From a7c94693320331527ad40aa9f3fae3512a0c8b46 Mon Sep 17 00:00:00 2001 From: root Date: Fri, 4 Oct 2013 20:45:32 -0700 Subject: [PATCH] Patches for IPv6 to Work --- mdl/m_io_sockets.pas | 125 ++++++++++++++++++++++++---------- mdl/m_resolve_address.c | 54 +++++++++++++++ mdl/m_socket_class.pas | 145 +++++++++++++++++++++++++++++----------- mdl/m_socket_server.pas | 3 +- 4 files changed, 252 insertions(+), 75 deletions(-) create mode 100644 mdl/m_resolve_address.c diff --git a/mdl/m_io_sockets.pas b/mdl/m_io_sockets.pas index 11fcdd1..fd14b0f 100644 --- a/mdl/m_io_sockets.pas +++ b/mdl/m_io_sockets.pas @@ -1,5 +1,8 @@ Unit m_io_Sockets; +{$link m_resolve_address.o} +{$linklib c} + {$I M_OPS.PAS} {.$DEFINE TNDEBUG} @@ -59,7 +62,7 @@ Type Function SetBlocking (Block: Boolean): LongInt; Function WaitForData (TimeOut: LongInt) : LongInt; Override; Function Connect (Address: String; Port: Word) : Boolean; - Function ResolveAddress (Host: String) : LongInt; + Function ResolveAddress (Host: String; Remote_Address: PChar):Integer; Procedure WaitInit (NetInterface: String; Port: Word); Function WaitConnection (TimeOut: LongInt) : TIOSocket; @@ -326,7 +329,15 @@ Procedure TIOSocket.TelnetInBuffer (Var Buf: TIOBuffer; Var Len: LongInt); {$IFDEF TNDEBUG} TNLOG ('InBuffer -> Sending data response'); + + + + + + {$ENDIF} + + End; Var @@ -559,57 +570,83 @@ Begin {$ENDIF} End; -Function TIOSocket.ResolveAddress (Host: String) : LongInt; -Var - HostEnt : PHostEnt; -Begin - Host := Host + #0; - HostEnt := GetHostByName(@Host[1]); +Function ResolveAddress_IPv6(Host:PChar; Remote_Address:PChar):Integer; cdecl; external; - If Assigned(HostEnt) Then - Result := PInAddr(HostEnt^.h_addr_list^)^.S_addr - Else - Result := LongInt(StrToNetAddr(Host)); +Function TIOSocket.ResolveAddress (Host: String; Remote_Address: pchar):Integer; +Begin + Host := Host + Char(0); + Result := ResolveAddress_IPv6(@Host, Remote_Address); End; Function TIOSocket.Connect (Address: String; Port: Word) : Boolean; Var - Sin : TINetSockAddr; + Sin6 : TINetSockAddr6; + Sin4 : TINetSockAddr; + Remote_Addr : String; + Family : Integer; Begin - Result := False; - FSocketHandle := fpSocket(PF_INET, SOCK_STREAM, 0); + Result := False; + Family := 0; + Remote_Addr := ''; + + Family := ResolveAddress (Address, @Remote_Addr); - If FSocketHandle = -1 Then Exit; + if Family = 0 Then Begin + if Pos(Address, ':') > 0 then Begin + Family := AF_INET6; + Remote_Addr := Address; + End else Begin + Family := AF_INET; + Remote_Addr := Address; + End; + End; - FPeerName := Address; + FSocketHandle := fpSocket(Family, SOCK_STREAM, 0); + If FSocketHandle = -1 Then Begin + Exit; + End; - FillChar(Sin, SizeOf(Sin), 0); - - Sin.sin_Family := PF_INET; - Sin.sin_Port := htons(Port); - Sin.sin_Addr.S_Addr := ResolveAddress(Address); - - FPeerIP := NetAddrToStr(Sin.Sin_Addr); - Result := fpConnect(FSocketHandle, @Sin, SizeOf(Sin)) = 0; + FPeerName := Address; + + if Family = AF_INET6 then Begin + FillChar(Sin6, SizeOf(Sin6), 0); + Sin6.sin6_Family := AF_INET6; + Sin6.sin6_Port := htons(Port); + Sin6.sin6_Addr := StrToNetAddr6(Remote_Addr); + FPeerIP := NetAddrToStr6(Sin6.Sin6_addr); + Result := fpConnect(FSocketHandle, @Sin6, SizeOf(Sin6)) = 0; + End else Begin + FillChar(Sin4, SizeOf(Sin4), 0); + Sin4.sin_Family := AF_INET; + Sin4.sin_Port := htons(Port); + Sin4.sin_Addr := StrToNetAddr(Remote_Addr); + FPeerIP := NetAddrToStr(Sin4.Sin_addr); + Result := fpConnect(FSocketHandle, @Sin4, SizeOf(Sin4)) = 0; + End; End; Procedure TIOSocket.WaitInit (NetInterface: String; Port: Word); Var - SIN : TINetSockAddr; + SIN : TINetSockAddr6; Opt : LongInt; Begin - FSocketHandle := fpSocket(PF_INET, SOCK_STREAM, 0); + If NetInterface = '0.0.0.0' Then + NetInterface := '::' + else if NetInterface = '127.0.0.1' then + NetInterface := '::1'; + + FSocketHandle := fpSocket(AF_INET6, SOCK_STREAM, 0); Opt := 1; fpSetSockOpt (FSocketHandle, SOL_SOCKET, SO_REUSEADDR, @Opt, SizeOf(Opt)); - SIN.sin_family := PF_INET; - SIN.sin_port := htons(Port); - SIN.sin_addr := StrToNetAddr(NetInterface); + SIN.sin6_family := AF_INET6; + SIN.sin6_port := htons(Port); + SIN.sin6_addr := StrToNetAddr6(NetInterface); {$IFDEF TNDEBUG} - TNLOG('Attempting to bind to interface ' + NetInterface + ' (' + strI2S(SIN.sin_addr.s_addr) + ')'); + TNLOG('Attempting to bind to interface ' + NetInterface + ' (' + strI2S(SIN.sin6_addr) + ')'); TNLOG('WaitInit Bind'); If fpBind(FSocketHandle, @SIN, SizeOf(SIN)) <> 0 Then @@ -628,9 +665,11 @@ Var Sock : LongInt; Client : TIOSocket; PHE : PHostEnt; - SIN : TINetSockAddr; + SIN : TINetSockAddr6; Temp : LongInt; SL : TSockLen; + Code : Integer; + Hold : LongInt; Begin Result := NIL; @@ -656,8 +695,26 @@ Begin If Sock = -1 Then Exit; - FPeerIP := NetAddrToStr(SIN.sin_addr); - PHE := GetHostByAddr(@SIN.sin_addr, 4, PF_INET); + { + We Need to Determine if this is actually IPv4 Mapped as Six + so that we can display and store the IP 4 Address. This is + necessary to we can make FTP and BINKP work properly by + opening returning ports on IPv4 and not IPv6, which won't work + nor clear firewall with input accept established rule, the norm. + } + FPeerIP := Upcase(NetAddrToStr6(SIN.sin6_addr)); + if Length (FPeerIP) > 7 Then + Begin + If Pos('::FFFF:', FPeerIP) = 1 Then // Is IPv4 mapped in 6? + Begin + Delete(FPeerIP, 1, 7); // Strip off ::FFFF: + Delete(FPeerIP, 5, 1); // Remove middle : + val('$' + FPeerIP, Hold, Code); // Convert to IPv4 Addy + FPeerIP := HostAddrToStr(in_addr(Hold)); + End; + End; + + PHE := GetHostByAddr(@SIN.sin6_addr, 16, AF_INET6); If Not Assigned(PHE) Then FPeerName := 'Unknown' @@ -668,7 +725,7 @@ Begin fpGetSockName(FSocketHandle, @SIN, @SL); - FHostIP := NetAddrToStr(SIN.sin_addr); + FHostIP := NetAddrToStr6(SIN.sin6_addr); Client := TIOSocket.Create; Client.SocketHandle := Sock; diff --git a/mdl/m_resolve_address.c b/mdl/m_resolve_address.c new file mode 100644 index 0000000..187f304 --- /dev/null +++ b/mdl/m_resolve_address.c @@ -0,0 +1,54 @@ +#include +#include +#include +#include +#include +#include +#include + +int32_t ResolveAddress_IPv6(const char *host, char *remote_address); + +int32_t ResolveAddress_IPv6(const char *host, char *remote_address) +{ + struct addrinfo *result; + struct addrinfo hints; + int error; + char *ptr_address; + + ptr_address = remote_address + 1; + + // Let's get the Ipv6 address if it exists + memset (&hints, 0, sizeof(hints)); + + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_STREAM; + + error = getaddrinfo(&host[1], 0, &hints, &result); + + if (error == 0) { + inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)(result->ai_addr))->sin6_addr), ptr_address, INET6_ADDRSTRLEN); + *remote_address = (char) strlen(ptr_address); + freeaddrinfo(result); + return AF_INET6; + } + + // Nope, Let us check for an ipv4 address + + memset (&hints, 0, sizeof(hints)); + + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + + error = getaddrinfo(&host[1], 0, &hints, &result); + + if (error == 0) { + inet_ntop(AF_INET, &(((struct sockaddr_in *)(result->ai_addr))->sin_addr), ptr_address, INET6_ADDRSTRLEN); + *remote_address = (char) strlen(ptr_address); + freeaddrinfo(result); + return AF_INET; + } + + remote_address = 0; + return 0; +} + diff --git a/mdl/m_socket_class.pas b/mdl/m_socket_class.pas index 57987da..26ee450 100644 --- a/mdl/m_socket_class.pas +++ b/mdl/m_socket_class.pas @@ -1,5 +1,8 @@ Unit m_Socket_Class; +{$link m_resolve_address.o} +{$linklib c} + {$I M_OPS.PAS} Interface @@ -18,7 +21,8 @@ Uses {$ENDIF} Sockets, m_DateTime, - m_Strings; + m_Strings, + libmysticbbs; Const TSocketBufferSize = 8 * 1024 - 1; @@ -66,7 +70,7 @@ Type Function SetBlocking (Block: Boolean): LongInt; Function WaitForData (TimeOut: LongInt) : LongInt; Function Connect (Address: String; Port: Word) : Boolean; - Function ResolveAddress (Host: String) : LongInt; + Function ResolveAddress (Host: String; Remote_Address: PChar):Integer; Procedure WaitInit (Port: Word); Function WaitConnection : TSocketClass; Procedure PurgeInputData; @@ -490,80 +494,141 @@ Begin {$ENDIF} End; -Function TSocketClass.ResolveAddress (Host: String) : LongInt; -Var - HostEnt : PHostEnt; -Begin - Host := Host + #0; - HostEnt := GetHostByName(@Host[1]); +Function ResolveAddress_IPv6(Host:PChar; Remote_Address:PChar):Integer; cdecl; external; - If Assigned(HostEnt) Then - Result := PInAddr(HostEnt^.h_addr_list^)^.S_addr - Else - Result := LongInt(StrToNetAddr(Host)); +Function TIOSocket.ResolveAddress (Host: String; Remote_Address: pchar):Integer; +Begin + Host := Host + Char(0); + Result := ResolveAddress_IPv6(@Host, Remote_Address); End; -Function TSocketClass.Connect (Address: String; Port: Word) : Boolean; +Function TIOSocket.Connect (Address: String; Port: Word) : Boolean; Var - Sin : TINetSockAddr; + Sin6 : TINetSockAddr6; + Sin4 : TINetSockAddr; + Remote_Addr : String; + Family : Integer; Begin - Result := False; - FSocketHandle := fpSocket(PF_INET, SOCK_STREAM, 0); + Result := False; + Family := 0; + Remote_Addr := ''; + + Family := ResolveAddress (Address, @Remote_Addr); - If FSocketHandle = -1 Then Exit; + if Family = 0 Then Begin + if Pos(Address, ':') > 0 then Begin + Family := AF_INET6; + Remote_Addr := Address; + End else Begin + Family := AF_INET; + Remote_Addr := Address; + End; + End; - FPeerName := Address; + FSocketHandle := fpSocket(Family, SOCK_STREAM, 0); + If FSocketHandle = -1 Then Begin + Exit; + End; - FillChar(Sin, SizeOf(Sin), 0); - - Sin.sin_Family := PF_INET; - Sin.sin_Port := htons(Port); - Sin.sin_Addr.S_Addr := ResolveAddress(Address); - - FPeerIP := NetAddrToStr(Sin.Sin_Addr); - Result := fpConnect(FSocketHandle, @Sin, SizeOf(Sin)) = 0; + FPeerName := Address; + + if Family = AF_INET6 then Begin + FillChar(Sin6, SizeOf(Sin6), 0); + Sin6.sin6_Family := AF_INET6; + Sin6.sin6_Port := htons(Port); + Sin6.sin6_Addr := StrToNetAddr6(Remote_Addr); + FPeerIP := NetAddrToStr6(Sin6.Sin6_addr); + Result := fpConnect(FSocketHandle, @Sin6, SizeOf(Sin6)) = 0; + End else Begin + FillChar(Sin4, SizeOf(Sin4), 0); + Sin4.sin_Family := AF_INET; + Sin4.sin_Port := htons(Port); + Sin4.sin_Addr := StrToNetAddr(Remote_Addr); + FPeerIP := NetAddrToStr(Sin4.Sin_addr); + Result := fpConnect(FSocketHandle, @Sin4, SizeOf(Sin4)) = 0; + End; End; -Procedure TSocketClass.WaitInit (Port: Word); +Procedure TIOSocket.WaitInit (NetInterface: String; Port: Word); Var - SIN : TINetSockAddr; + SIN : TINetSockAddr6; Opt : LongInt; Begin - FSocketHandle := fpSocket(PF_INET, SOCK_STREAM, 0); + If NetInterface = '0.0.0.0' Then + NetInterface := '::' + else if NetInterface = '127.0.0.1' then + NetInterface := '::1'; + + FSocketHandle := fpSocket(AF_INET6, SOCK_STREAM, 0); Opt := 1; fpSetSockOpt (FSocketHandle, SOL_SOCKET, SO_REUSEADDR, @Opt, SizeOf(Opt)); - SIN.sin_family := PF_INET; - SIN.sin_addr.s_addr := 0; - SIN.sin_port := htons(Port); + SIN.sin6_family := AF_INET6; + SIN.sin6_port := htons(Port); + SIN.sin6_addr := StrToNetAddr6(NetInterface); fpBind(FSocketHandle, @SIN, SizeOf(SIN)); SetBlocking(True); End; -Function TSocketClass.WaitConnection : TSocketClass; +Function TIOSocket.WaitConnection (TimeOut: LongInt) : TIOSocket; Var Sock : LongInt; - Client : TSocketClass; + Client : TIOSocket; PHE : PHostEnt; - SIN : TINetSockAddr; + SIN : TINetSockAddr6; Temp : LongInt; SL : TSockLen; + Code : Integer; + Hold : LongInt; Begin Result := NIL; - If fpListen(FSocketHandle, 5) = -1 Then Exit; + If TimeOut > 0 Then Begin + SetBlocking(False); + + If fpListen(FSocketHandle, 5) = -1 Then Begin + SetBlocking(True); + + Exit; + End; + + If WaitForData(TimeOut) <= 0 Then Begin + SetBlocking(True); + + Exit; + End; + End Else + If fpListen(FSocketHandle, 5) = -1 Then Exit; Temp := SizeOf(SIN); Sock := fpAccept(FSocketHandle, @SIN, @Temp); If Sock = -1 Then Exit; - FPeerIP := NetAddrToStr(SIN.sin_addr); - PHE := GetHostByAddr(@SIN.sin_addr, 4, PF_INET); + { + We Need to Determine if this is actually IPv4 Mapped as Six + so that we can display and store the IP 4 Address. This is + necessary to we can make FTP and BINKP work properly by + opening returning ports on IPv4 and not IPv6, which won't work + nor clear firewall with input accept established rule, the norm. + } + FPeerIP := Upcase(NetAddrToStr6(SIN.sin6_addr)); + if Length (FPeerIP) > 7 Then + Begin + If Pos('::FFFF:', FPeerIP) = 1 Then // Is IPv4 mapped in 6? + Begin + Delete(FPeerIP, 1, 7); // Strip off ::FFFF: + Delete(FPeerIP, 5, 1); // Remove middle : + val('$' + FPeerIP, Hold, Code); // Convert to IPv4 Addy + FPeerIP := HostAddrToStr(in_addr(Hold)); + End; + End; + + PHE := GetHostByAddr(@SIN.sin6_addr, 16, AF_INET6); If Not Assigned(PHE) Then FPeerName := 'Unknown' @@ -574,8 +639,8 @@ Begin fpGetSockName(FSocketHandle, @SIN, @SL); - FHostIP := NetAddrToStr(SIN.sin_addr); - Client := TSocketClass.Create; + FHostIP := NetAddrToStr6(SIN.sin6_addr); + Client := TIOSocket.Create; Client.SocketHandle := Sock; Client.PeerName := FPeerName; diff --git a/mdl/m_socket_server.pas b/mdl/m_socket_server.pas index f2c44fb..f41615d 100644 --- a/mdl/m_socket_server.pas +++ b/mdl/m_socket_server.pas @@ -196,7 +196,8 @@ Begin Repeat Until Server <> NIL; // Synchronize with server class Repeat Until ServerStatus <> NIL; // Syncronize with status class - Server.WaitInit('0.0.0.0', Port); + //Server.WaitInit('0.0.0.0', Port); + Server.WaitInit('::', Port); If Terminated Then Exit;