⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hxudp.pas

📁 非常好的UDP穿透Socks5的实例源码教程
💻 PAS
📖 第 1 页 / 共 2 页
字号:
    PeerPort:= ntohs(saRemote.sin_port);
  end;

  if ret = SOCKET_ERROR then
  begin
    ErrorCode:= GetLastError;
    if ErrorCode <> WSAEWOULDBLOCK then
    begin
      if Assigned(FOnSocketError) then
        FOnSocketError(Self, utRecv, ErrorCode);
      if ErrorCode <> 0 then
        raise TUDPException.CreateFmt('接收数据出错。错误码是%d', [ErrorCode]);
    end;
  end
  else
    Result:= True;
end;

function ThxUDPSocket.SendBuf(var Buf; Size: Integer; IP: string; Port: Integer): Boolean;
var
  ret, ErrorCode: Integer;
  saRemote: TSockAddrIn;
begin
  Result:= False;

  saRemote.sin_family:= AF_INET;
  saRemote.sin_port:= htons(Port);
  saRemote.sin_addr.S_addr:= inet_addr(PChar(IP));

  if saRemote.sin_addr.S_addr = INADDR_NONE then
    raise TUDPException.Create('无效的远程主机地址!');

  if FProxyInfo.Enabled then
    ret:= SendByProxy(FSocket, Buf, Size, IP, Port)
  else
    ret:= sendto(FSocket, Buf, Size, 0, saRemote, SizeOf(saRemote));
  if ret = SOCKET_ERROR then
  begin
    ErrorCode:= GetLastError;
    if ErrorCode <> WSAEWOULDBLOCK then
    begin
      if Assigned(FOnSocketError) then
        FOnSocketError(Self, utSend, ErrorCode);
      if ErrorCode <> 0 then
        raise TUDPException.CreateFmt('发送数据时出错。错误码是%d', [ErrorCode]);
    end;
  end
  else
    Result:= True;
end;

function ThxUDPSocket.SendText(Text, IP: string; Port: integer): Boolean;
begin
  Result := SendBuf(Pointer(Text)^, Length(Text), IP, Port);
end;

procedure ThxUDPSocket.SetActive(Value: Boolean);
begin
  if FActive <> Value then
    DoActive(Value);
end;

procedure ThxUDPSocket.SetRecvBufSize(Value: Integer);
var
  ErrorCode: Integer;
begin
  if FRecvBufSize <> Value then
  begin
    ErrorCode:= setsockopt(FSocket, SOL_SOCKET, SO_RCVBUF, @Value, sizeof(Value));
    if ErrorCode = SOCKET_ERROR then
      raise TUDPException.CreateFmt('设置接收缓冲区出错。错误码是%d', [GetLastError]);
    FRecvBufSize:= Value;
  end;
end;

procedure ThxUDPSocket.SetSendBufSize(Value: Integer);
var
  ErrorCode: Integer;
begin
  if FSendBufSize <> Value then
  begin
    ErrorCode:= setsockopt(FSocket, SOL_SOCKET, SO_SNDBUF, @Value, sizeof(Value));
    if ErrorCode = SOCKET_ERROR then
      raise TUDPException.CreateFmt('设置发送缓冲区错误。错误码是%d', [GetLastError]);
    FSendBufSize:= Value;
  end;
end;

procedure ThxUDPSocket.SetTimeOut(Value: Longword);
begin
  if FTimeOut <> Value then
    FTimeOut:= Value;
end;

function ThxUDPSocket.ConnectToProxy: Boolean;
var
  saProxy: TSockAddrIn;
  ret: Integer;
  bRet: Boolean;
begin
  Result:= False;
  //建立到Proxy的Tcp连接
  if FTcpSocket = INVALID_SOCKET then
    FTcpSocket:= socket(AF_INET, SOCK_STREAM, 0);

  saProxy.sin_family:= AF_INET;
  saProxy.sin_port:= htons(FProxyInfo.Port);
  saProxy.sin_addr.S_addr:= inet_addr(PChar(FProxyInfo.Address));
  ret:= connect(FTcpSocket, @saProxy, SizeOf(saProxy));
  if ret = SOCKET_ERROR then
    raise Exception.CreateFmt('无法连接到代理服务器,错误码是%d', [WSAGetLastError]);

  {代理服务器是否需要身份验证}
  if Trim(FProxyInfo.Username) <> '' then
    bRet:= Handclasp(FTcpSocket, atUserPass)
   else
    bRet:= Handclasp(FTcpSocket, atNone);

  if not bRet then
  begin
    closesocket(FTcpSocket);
    raise Exception.CreateFmt('代理服务器身份验证失败!错误码是%d', [WSAGetLastError]);
  end;

  //建立UDP映射通道
  if not MapUdpChannel(FTcpSocket) then
  begin
    closesocket(FTcpSocket);
    raise Exception.CreateFmt('代理服务器不支持UDP!错误码是%d', [WSAGetLastError]);
  end;

  Result:= True;
end;

function ThxUDPSocket.Handclasp(Socket: TSocket; AuthenType: TAuthenType): Boolean;
var
  Buf: array[0..255] of Byte;
  I, Ret: Integer;
  Username, Password: string;
begin
  Result:= False;
  case AuthenType of
    // 无需验证
    atNone:
    begin
      Buf[0]:= $05;
      Buf[1]:= $01;
      Buf[2]:= $00;
      Ret:= send(Socket, Buf, 3, 0);
      if Ret = -1 then Exit;
      FillChar(Buf, 256, #0);
      Ret:= recv(Socket, Buf, 256, 0);
      if Ret < 2 then Exit;
      if Buf[1] <> $00 then Exit;
      Result:= True;
    end;
    // 用户名密码验证
    atUserPass:
    begin
      Buf[0]:= $05; // Socks版本号
      Buf[1]:= $02; // 两种认证方法
      Buf[2]:= $00; // 无需校验
      Buf[3]:= $02; // 需用户名密码校验
      Ret:= send(Socket, Buf, 4, 0);
      if Ret = -1 then Exit;
      FillChar(Buf, 256, #0);
      Ret:= recv(Socket, Buf, 256, 0);
      if Ret < 2 then Exit;
      if Buf[1] <> $02 then Exit;
      Username:= FProxyInfo.Username;
      Password:= FProxyInfo.Password;
      FillChar(Buf, 256, #0);
      Buf[0]:= $01;
      Buf[1]:= Length(Username);
      for I:= 0 to Buf[1] - 1 do
        Buf[2 + I]:= Ord(Username[I + 1]);
      Buf[2 + Length(Username)]:= Length(Password);
      for I:= 0 to Buf[2 + Length(Username)] - 1 do
        Buf[3 + Length(Username) + I]:= Ord(Password[I + 1]);
      Ret:= send(Socket, Buf, Length(Username) + Length(Password) + 3, 0);
      if Ret = -1 then Exit;
      Ret:= recv(Socket, Buf, 256, 0);
      if Ret = -1 then Exit;
      if Buf[1] <> $00 then Exit;
      Result:= True;
    end;
  end;
end;

function ThxUDPSocket.MapUdpChannel(Socket: TSocket): Boolean;
var
  saLocal: TSockAddrIn;
  NameLen: Integer;
  ProxyAddr: TInAddr;
  ProxyPort: Word;
  Buf: array[0..255] of Byte;
begin
  Result:= False;
  NameLen:= SizeOf(saLocal);
  getsockname(FSocket, saLocal, NameLen);
  Buf[0]:= $05; //协议版本Socks5
  Buf[1]:= $03; //Socks命令:UDP
  Buf[2]:= $00; //保留
  Buf[3]:= $01; //地址类型IPv4
  CopyMemory(@Buf[4], @saLocal.sin_addr, 4);
  CopyMemory(@Buf[8], @saLocal.sin_port, 2);
  send(Socket, Buf, 10, 0);
  FillChar(Buf, 256, #0);
  recv(Socket, Buf, 256, 0);
  if (Buf[0] <> $05) and (Buf[1] <> $00) then
    Exit;
  CopyMemory(@ProxyAddr, @Buf[4], 4); //获取Proxy的映射地址
  CopyMemory(@ProxyPort, @Buf[8], 2); //获取Proxy的映射端口号

  FUdpProxyAddr.sin_family:= AF_INET;
  FUdpProxyAddr.sin_port:= ProxyPort;
  FUdpProxyAddr.sin_addr:= ProxyAddr;

  Result:= True;
end;


function ThxUDPSocket.SendByProxy(Socket: TSocket; var buf; len: Integer;
  RemoteIP: string; RemotePort: Integer): Integer;
var
  TempBuf: array[0..1023] of Byte;
  saRemote: TSockAddrIn;
begin
  saRemote.sin_family:= AF_INET;
  saRemote.sin_port:= htons(RemotePort);
  saRemote.sin_addr.S_addr:= inet_addr(PChar(RemoteIP));
  // 加上报头
  FillChar(TempBuf, 1023, $0);
  TempBuf[0]:= $00;  //保留
  TempBuf[1]:= $00;  //保留
  TempBuf[2]:= $00;  //是否分段重组(此处不用)
  TempBuf[3]:= $01;  //IPv4
  CopyMemory(@TempBuf[4], @saRemote.sin_addr, 4);    //代理服务器地址
  CopyMemory(@TempBuf[8], @saRemote.sin_port, 2);  //代理服务器端口
  CopyMemory(@TempBuf[10], @buf, len); //实际数据
  Result:= sendto(Socket, TempBuf, len + 10, 0, FUdpProxyAddr, SizeOf(FUdpProxyAddr));
  if Result = SOCKET_ERROR then
    raise Exception.CreateFmt('发送数据错误!错误号是%d', [WSAGetLastError]);
end;

function ThxUDPSocket.RecvByProxy(Socket: TSocket; var buf; len: Integer;
  RemoteIP: string; RemotePort: Integer): Integer;
var
  TempBuf: array[0..1023] of Byte;
  saRemote: TSockAddrIn;
  fromlen: Integer;
begin
  FillChar(TempBuf, 1024, #0);
  saRemote.sin_family:= AF_INET;
  saRemote.sin_port:= htons(RemotePort);
  saRemote.sin_addr.S_addr:= inet_addr(PChar(RemoteIP));
  fromlen:= SizeOf(saRemote);
  Result:= recvfrom(Socket, TempBuf, len, 0, saRemote, fromlen);
  if Result = SOCKET_ERROR then
    raise Exception.CreateFmt('接收数据错误!错误号是%d', [WSAGetLastError]);
  Assert(TempBuf[0] = $00);  //保留
  Assert(TempBuf[1] = $00);  //保留
  Assert(TempBuf[2] = $00);  //是否分段重组
  Assert(TempBuf[3] = $01);  //IPv4
  CopyMemory(@saRemote.sin_addr, @TempBuf[4], 4);  //代理服务器地址
  CopyMemory(@saRemote.sin_port, @TempBuf[8], 2);  //代理服务器端口
  CopyMemory(@buf, @TempBuf[10], len); //实际数据
end;

{ ThxUdpRecvThread }

constructor ThxUdpRecvThread.Create(CreateSuspended: Boolean; AUdpSocket: ThxUdpSocket);
begin
  inherited Create(CreateSuspended);
  FSocket:= AUDPSocket;
  FEvent:= WSA_INVALID_EVENT;
  InitEvent;
end;

destructor ThxUdpRecvThread.Destroy;
begin
  if not Terminated then
    Stop;
  FreeEvent;
  inherited Destroy;
end;

procedure ThxUdpRecvThread.Execute;
var
  ErrorCode: Integer;
begin
  while not Terminated do
  begin
    ErrorCode:= WSAWaitForMultipleEvents(
      1,      //事件数量
      @FEvent,//事件处理函数
      False,  //有一个事件触发时就返回
      FSocket.FTimeOut, // 超时时间
      False   //函数返回时,不执行I/O例程
    );

    if Terminated then
      Break;

    if ErrorCode = WAIT_IO_COMPLETION then
    begin
      Break;
    end
    else
    begin
      WSAResetEvent(FEvent);
      if ErrorCode = WSA_WAIT_TIMEOUT then
      begin
        if Assigned(FSocket.FOnTimeOut) then
          Synchronize(FSocket.FOnTimeOut);
      end
      else if Assigned(FOnDataRecv) then
        Synchronize(FOnDataRecv);
    end;
  end;
end;

procedure ThxUdpRecvThread.FreeEvent;
begin
  if FEvent <> WSA_INVALID_EVENT then
    WSACloseEvent(FEvent);
end;

procedure ThxUdpRecvThread.InitEvent;
var
  ErrorCode: Integer;
begin
  FEvent:= WSACreateEvent;
  if FEvent = WSA_INVALID_EVENT then
    raise TUDPException.CreateFmt('创建套接字事件句柄出错。错误码是%d', [WSAGetLastError]);

  ErrorCode:= WSAEventSelect(FSocket.FSocket, FEvent, FD_READ);
  if ErrorCode = SOCKET_ERROR then
    raise TUDPException.CreateFmt('设置套接字事件句柄出错。错误码是%d', [WSAGetLastError]);
end;

procedure ThxUdpRecvThread.Stop;
begin
  Terminate;
  SetEvent(FEvent);
  WaitFor;
end;

end.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -