Patches for IPv6 to Work

This commit is contained in:
root 2013-10-04 20:45:32 -07:00
parent aaa9111b23
commit a7c9469332
4 changed files with 252 additions and 75 deletions

View File

@ -1,5 +1,8 @@
Unit m_io_Sockets; Unit m_io_Sockets;
{$link m_resolve_address.o}
{$linklib c}
{$I M_OPS.PAS} {$I M_OPS.PAS}
{.$DEFINE TNDEBUG} {.$DEFINE TNDEBUG}
@ -59,7 +62,7 @@ Type
Function SetBlocking (Block: Boolean): LongInt; Function SetBlocking (Block: Boolean): LongInt;
Function WaitForData (TimeOut: LongInt) : LongInt; Override; Function WaitForData (TimeOut: LongInt) : LongInt; Override;
Function Connect (Address: String; Port: Word) : Boolean; 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); Procedure WaitInit (NetInterface: String; Port: Word);
Function WaitConnection (TimeOut: LongInt) : TIOSocket; Function WaitConnection (TimeOut: LongInt) : TIOSocket;
@ -326,7 +329,15 @@ Procedure TIOSocket.TelnetInBuffer (Var Buf: TIOBuffer; Var Len: LongInt);
{$IFDEF TNDEBUG} {$IFDEF TNDEBUG}
TNLOG ('InBuffer -> Sending data response'); TNLOG ('InBuffer -> Sending data response');
{$ENDIF} {$ENDIF}
End; End;
Var Var
@ -559,57 +570,83 @@ Begin
{$ENDIF} {$ENDIF}
End; End;
Function TIOSocket.ResolveAddress (Host: String) : LongInt; Function ResolveAddress_IPv6(Host:PChar; Remote_Address:PChar):Integer; cdecl; external;
Var
HostEnt : PHostEnt;
Begin
Host := Host + #0;
HostEnt := GetHostByName(@Host[1]);
If Assigned(HostEnt) Then Function TIOSocket.ResolveAddress (Host: String; Remote_Address: pchar):Integer;
Result := PInAddr(HostEnt^.h_addr_list^)^.S_addr Begin
Else Host := Host + Char(0);
Result := LongInt(StrToNetAddr(Host)); Result := ResolveAddress_IPv6(@Host, Remote_Address);
End; End;
Function TIOSocket.Connect (Address: String; Port: Word) : Boolean; Function TIOSocket.Connect (Address: String; Port: Word) : Boolean;
Var Var
Sin : TINetSockAddr; Sin6 : TINetSockAddr6;
Sin4 : TINetSockAddr;
Remote_Addr : String;
Family : Integer;
Begin Begin
Result := False; Result := False;
FSocketHandle := fpSocket(PF_INET, SOCK_STREAM, 0); Family := 0;
Remote_Addr := '';
If FSocketHandle = -1 Then Exit; Family := ResolveAddress (Address, @Remote_Addr);
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;
FSocketHandle := fpSocket(Family, SOCK_STREAM, 0);
If FSocketHandle = -1 Then Begin
Exit;
End;
FPeerName := Address; FPeerName := Address;
FillChar(Sin, SizeOf(Sin), 0); if Family = AF_INET6 then Begin
FillChar(Sin6, SizeOf(Sin6), 0);
Sin.sin_Family := PF_INET; Sin6.sin6_Family := AF_INET6;
Sin.sin_Port := htons(Port); Sin6.sin6_Port := htons(Port);
Sin.sin_Addr.S_Addr := ResolveAddress(Address); Sin6.sin6_Addr := StrToNetAddr6(Remote_Addr);
FPeerIP := NetAddrToStr6(Sin6.Sin6_addr);
FPeerIP := NetAddrToStr(Sin.Sin_Addr); Result := fpConnect(FSocketHandle, @Sin6, SizeOf(Sin6)) = 0;
Result := fpConnect(FSocketHandle, @Sin, SizeOf(Sin)) = 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; End;
Procedure TIOSocket.WaitInit (NetInterface: String; Port: Word); Procedure TIOSocket.WaitInit (NetInterface: String; Port: Word);
Var Var
SIN : TINetSockAddr; SIN : TINetSockAddr6;
Opt : LongInt; Opt : LongInt;
Begin 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; Opt := 1;
fpSetSockOpt (FSocketHandle, SOL_SOCKET, SO_REUSEADDR, @Opt, SizeOf(Opt)); fpSetSockOpt (FSocketHandle, SOL_SOCKET, SO_REUSEADDR, @Opt, SizeOf(Opt));
SIN.sin_family := PF_INET; SIN.sin6_family := AF_INET6;
SIN.sin_port := htons(Port); SIN.sin6_port := htons(Port);
SIN.sin_addr := StrToNetAddr(NetInterface); SIN.sin6_addr := StrToNetAddr6(NetInterface);
{$IFDEF TNDEBUG} {$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'); TNLOG('WaitInit Bind');
If fpBind(FSocketHandle, @SIN, SizeOf(SIN)) <> 0 Then If fpBind(FSocketHandle, @SIN, SizeOf(SIN)) <> 0 Then
@ -628,9 +665,11 @@ Var
Sock : LongInt; Sock : LongInt;
Client : TIOSocket; Client : TIOSocket;
PHE : PHostEnt; PHE : PHostEnt;
SIN : TINetSockAddr; SIN : TINetSockAddr6;
Temp : LongInt; Temp : LongInt;
SL : TSockLen; SL : TSockLen;
Code : Integer;
Hold : LongInt;
Begin Begin
Result := NIL; Result := NIL;
@ -656,8 +695,26 @@ Begin
If Sock = -1 Then Exit; 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 If Not Assigned(PHE) Then
FPeerName := 'Unknown' FPeerName := 'Unknown'
@ -668,7 +725,7 @@ Begin
fpGetSockName(FSocketHandle, @SIN, @SL); fpGetSockName(FSocketHandle, @SIN, @SL);
FHostIP := NetAddrToStr(SIN.sin_addr); FHostIP := NetAddrToStr6(SIN.sin6_addr);
Client := TIOSocket.Create; Client := TIOSocket.Create;
Client.SocketHandle := Sock; Client.SocketHandle := Sock;

54
mdl/m_resolve_address.c Normal file
View File

@ -0,0 +1,54 @@
#include <sys/socket.h>
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <arpa/inet.h>
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;
}

View File

@ -1,5 +1,8 @@
Unit m_Socket_Class; Unit m_Socket_Class;
{$link m_resolve_address.o}
{$linklib c}
{$I M_OPS.PAS} {$I M_OPS.PAS}
Interface Interface
@ -18,7 +21,8 @@ Uses
{$ENDIF} {$ENDIF}
Sockets, Sockets,
m_DateTime, m_DateTime,
m_Strings; m_Strings,
libmysticbbs;
Const Const
TSocketBufferSize = 8 * 1024 - 1; TSocketBufferSize = 8 * 1024 - 1;
@ -66,7 +70,7 @@ Type
Function SetBlocking (Block: Boolean): LongInt; Function SetBlocking (Block: Boolean): LongInt;
Function WaitForData (TimeOut: LongInt) : LongInt; Function WaitForData (TimeOut: LongInt) : LongInt;
Function Connect (Address: String; Port: Word) : Boolean; Function Connect (Address: String; Port: Word) : Boolean;
Function ResolveAddress (Host: String) : LongInt; Function ResolveAddress (Host: String; Remote_Address: PChar):Integer;
Procedure WaitInit (Port: Word); Procedure WaitInit (Port: Word);
Function WaitConnection : TSocketClass; Function WaitConnection : TSocketClass;
Procedure PurgeInputData; Procedure PurgeInputData;
@ -490,71 +494,114 @@ Begin
{$ENDIF} {$ENDIF}
End; End;
Function TSocketClass.ResolveAddress (Host: String) : LongInt; Function ResolveAddress_IPv6(Host:PChar; Remote_Address:PChar):Integer; cdecl; external;
Var
HostEnt : PHostEnt;
Begin
Host := Host + #0;
HostEnt := GetHostByName(@Host[1]);
If Assigned(HostEnt) Then Function TIOSocket.ResolveAddress (Host: String; Remote_Address: pchar):Integer;
Result := PInAddr(HostEnt^.h_addr_list^)^.S_addr Begin
Else Host := Host + Char(0);
Result := LongInt(StrToNetAddr(Host)); Result := ResolveAddress_IPv6(@Host, Remote_Address);
End; End;
Function TSocketClass.Connect (Address: String; Port: Word) : Boolean; Function TIOSocket.Connect (Address: String; Port: Word) : Boolean;
Var Var
Sin : TINetSockAddr; Sin6 : TINetSockAddr6;
Sin4 : TINetSockAddr;
Remote_Addr : String;
Family : Integer;
Begin Begin
Result := False; Result := False;
FSocketHandle := fpSocket(PF_INET, SOCK_STREAM, 0); Family := 0;
Remote_Addr := '';
If FSocketHandle = -1 Then Exit; Family := ResolveAddress (Address, @Remote_Addr);
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;
FSocketHandle := fpSocket(Family, SOCK_STREAM, 0);
If FSocketHandle = -1 Then Begin
Exit;
End;
FPeerName := Address; FPeerName := Address;
FillChar(Sin, SizeOf(Sin), 0); if Family = AF_INET6 then Begin
FillChar(Sin6, SizeOf(Sin6), 0);
Sin.sin_Family := PF_INET; Sin6.sin6_Family := AF_INET6;
Sin.sin_Port := htons(Port); Sin6.sin6_Port := htons(Port);
Sin.sin_Addr.S_Addr := ResolveAddress(Address); Sin6.sin6_Addr := StrToNetAddr6(Remote_Addr);
FPeerIP := NetAddrToStr6(Sin6.Sin6_addr);
FPeerIP := NetAddrToStr(Sin.Sin_Addr); Result := fpConnect(FSocketHandle, @Sin6, SizeOf(Sin6)) = 0;
Result := fpConnect(FSocketHandle, @Sin, SizeOf(Sin)) = 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; End;
Procedure TSocketClass.WaitInit (Port: Word); Procedure TIOSocket.WaitInit (NetInterface: String; Port: Word);
Var Var
SIN : TINetSockAddr; SIN : TINetSockAddr6;
Opt : LongInt; Opt : LongInt;
Begin 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; Opt := 1;
fpSetSockOpt (FSocketHandle, SOL_SOCKET, SO_REUSEADDR, @Opt, SizeOf(Opt)); fpSetSockOpt (FSocketHandle, SOL_SOCKET, SO_REUSEADDR, @Opt, SizeOf(Opt));
SIN.sin_family := PF_INET; SIN.sin6_family := AF_INET6;
SIN.sin_addr.s_addr := 0; SIN.sin6_port := htons(Port);
SIN.sin_port := htons(Port); SIN.sin6_addr := StrToNetAddr6(NetInterface);
fpBind(FSocketHandle, @SIN, SizeOf(SIN)); fpBind(FSocketHandle, @SIN, SizeOf(SIN));
SetBlocking(True); SetBlocking(True);
End; End;
Function TSocketClass.WaitConnection : TSocketClass; Function TIOSocket.WaitConnection (TimeOut: LongInt) : TIOSocket;
Var Var
Sock : LongInt; Sock : LongInt;
Client : TSocketClass; Client : TIOSocket;
PHE : PHostEnt; PHE : PHostEnt;
SIN : TINetSockAddr; SIN : TINetSockAddr6;
Temp : LongInt; Temp : LongInt;
SL : TSockLen; SL : TSockLen;
Code : Integer;
Hold : LongInt;
Begin Begin
Result := NIL; Result := NIL;
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; If fpListen(FSocketHandle, 5) = -1 Then Exit;
Temp := SizeOf(SIN); Temp := SizeOf(SIN);
@ -562,8 +609,26 @@ Begin
If Sock = -1 Then Exit; 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 If Not Assigned(PHE) Then
FPeerName := 'Unknown' FPeerName := 'Unknown'
@ -574,8 +639,8 @@ Begin
fpGetSockName(FSocketHandle, @SIN, @SL); fpGetSockName(FSocketHandle, @SIN, @SL);
FHostIP := NetAddrToStr(SIN.sin_addr); FHostIP := NetAddrToStr6(SIN.sin6_addr);
Client := TSocketClass.Create; Client := TIOSocket.Create;
Client.SocketHandle := Sock; Client.SocketHandle := Sock;
Client.PeerName := FPeerName; Client.PeerName := FPeerName;

View File

@ -196,7 +196,8 @@ Begin
Repeat Until Server <> NIL; // Synchronize with server class Repeat Until Server <> NIL; // Synchronize with server class
Repeat Until ServerStatus <> NIL; // Syncronize with status 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; If Terminated Then Exit;