Bind to user-specified address (BindAddress6)
[mgsmtp.git] / DNSResolve.pas
1 {
2 Copyright (C) 2010-2018 MegaBrutal
3
4 This unit is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
8
9 This unit is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
16 }
17
18
19 {$MODE FPC}
20
21 unit DNSResolve;
22
23 interface
24 uses WinSock, Sockets, ctypes;
25
26 const
27
28 NI_NOFQDN = $01;
29 NI_NUMERICHOST = $02;
30 NI_NAMEREQD = $04;
31 NI_NUMERICSERV = $08;
32 NI_DGRAM = $10;
33
34
35 type
36
37 PAddrInfo = ^TAddrInfo;
38 TAddrInfo = record
39 ai_flags: cint;
40 ai_family: cint;
41 ai_socktype: cint;
42 ai_protocol: cint;
43 ai_addrlen: size_t;
44 ai_canonname: PChar;
45 ai_addr: PSockAddr;
46 ai_next: PAddrInfo;
47 end;
48
49 TGAIResult = record
50 GAIError: integer;
51 AddrInfo: PAddrInfo;
52 end;
53
54
55 function getaddrinfo(NodeName, ServiceName: PChar; Hints: PAddrInfo; var AddrInfo: PAddrInfo): cint; stdcall;
56 external 'ws2_32.dll' name 'getaddrinfo';
57
58 procedure freeaddrinfo(AddrInfo: PAddrInfo); stdcall;
59 external 'ws2_32.dll' name 'freeaddrinfo';
60
61 function getnameinfo(SockAddr: PSockAddr; SockAddrLength: cuint32; NodeBuffer: PChar; NodeBufferSize: cuint32;
62 ServiceBuffer: PChar; ServiceBufferSize: cuint32; Flags: cint): cint; stdcall;
63 external 'ws2_32.dll' name 'getnameinfo';
64
65 function ResolveHost(HostName: ansistring; Family: cint): TGAIResult;
66 procedure FreeHost(var GAIResult: TGAIResult);
67 function ResolveIP(AddrInfo: PAddrInfo; Flags: cint): ansistring; overload;
68 function ResolveIP(AddrInfo: PAddrInfo): ansistring; overload;
69 function ResolveIP(SockAddr: PSockAddr; Flags: cint): ansistring; overload;
70 function ResolveIP(SockAddr: PSockAddr): ansistring; overload;
71 function IPToStr(SockAddr: PSockAddr): ansistring;
72
73
74 implementation
75
76
77 function ResolveHost(HostName: ansistring; Family: cint): TGAIResult;
78 var hint: TAddrInfo;
79 begin
80 FillByte(hint, SizeOf(hint), 0);
81 with hint do begin
82 ai_family:= Family;
83 ai_socktype:= SOCK_STREAM;
84 ai_protocol:= IPPROTO_TCP;
85 end;
86 ResolveHost.GAIError:= getaddrinfo(PChar(HostName), nil, @hint, ResolveHost.AddrInfo);
87 end;
88
89 procedure FreeHost(var GAIResult: TGAIResult);
90 begin
91 if GAIResult.AddrInfo <> nil then begin
92 freeaddrinfo(GAIResult.AddrInfo);
93 GAIResult.AddrInfo:= nil;
94 end;
95 end;
96
97 function ResolveIP(AddrInfo: PAddrInfo; Flags: cint): ansistring;
98 var
99 r: integer;
100 NodeBuffer: array[0..255] of char;
101 begin
102 NodeBuffer[0]:= #0;
103 r:= getnameinfo(AddrInfo^.ai_addr, AddrInfo^.ai_addrlen, @NodeBuffer, SizeOf(NodeBuffer), nil, 0, Flags);
104 if r = 0 then ResolveIP:= PChar(@NodeBuffer)
105 else ResolveIP:= IPToStr(AddrInfo^.ai_addr);
106 end;
107
108 function ResolveIP(AddrInfo: PAddrInfo): ansistring;
109 begin
110 ResolveIP:= ResolveIP(AddrInfo, 0);
111 end;
112
113 function ResolveIP(SockAddr: PSockAddr; Flags: cint): ansistring;
114 var
115 AddrInfo: TAddrInfo;
116 begin
117 AddrInfo.ai_addr:= SockAddr;
118
119 if SockAddr^.sa_family = AF_INET then
120 AddrInfo.ai_addrlen:= SizeOf(TSockAddr)
121 else if SockAddr^.sa_family = AF_INET6 then
122 AddrInfo.ai_addrlen:= SizeOf(TSockAddr6)
123 else
124 AddrInfo.ai_addrlen:= 0;
125
126 ResolveIP:= ResolveIP(PAddrInfo(@AddrInfo), Flags);
127 end;
128
129 function ResolveIP(SockAddr: PSockAddr): ansistring;
130 begin
131 ResolveIP:= ResolveIP(SockAddr, 0);
132 end;
133
134 function IPToStr(SockAddr: PSockAddr): ansistring;
135 begin
136 {$IFNDEF GNI}
137 if SockAddr^.sa_family = AF_INET then
138 IPToStr:= NetAddrToStr(SockAddr^.sin_addr)
139 else if SockAddr^.sa_family = AF_INET6 then
140 IPToStr:= NetAddrToStr6(PSockAddr6(SockAddr)^.sin6_addr)
141 else
142 IPToStr:= 'unknown';
143 {$ELSE}
144 IPToStr:= ResolveIP(SockAddr, NI_NUMERICHOST);
145 {$ENDIF}
146 end;
147
148
149 end.