3
3
*
4
4
* Author: Krzysztof Kliś <[email protected] >
5
5
* Fixes and improvements: Jérôme Poulin <[email protected] >
6
+ * IPv6 support: 04/2019 Rafael Ferrari <[email protected] >
6
7
*
7
8
* This program is free software: you can redistribute it and/or modify
8
9
* it under the terms of the GNU Lesser General Public License as published by
67
68
68
69
typedef enum {TRUE = 1 , FALSE = 0 } bool ;
69
70
71
+ int check_ipversion (char * address );
70
72
int create_socket (int port );
71
73
void sigchld_handler (int signal );
72
74
void sigterm_handler (int signal );
73
75
void server_loop ();
74
- void handle_client (int client_sock , struct sockaddr_in client_addr );
76
+ void handle_client (int client_sock , struct sockaddr_storage client_addr );
75
77
void forward_data (int source_sock , int destination_sock );
76
78
void forward_data_ext (int source_sock , int destination_sock , char * cmd );
77
79
int create_connection ();
@@ -84,6 +86,8 @@ char *bind_addr, *remote_host, *cmd_in, *cmd_out;
84
86
bool foreground = FALSE;
85
87
bool use_syslog = FALSE;
86
88
89
+ #define BACKLOG 20 // how many pending connections queue will hold
90
+
87
91
/* Program start */
88
92
int main (int argc , char * argv []) {
89
93
int local_port ;
@@ -170,36 +174,77 @@ int parse_options(int argc, char *argv[]) {
170
174
}
171
175
}
172
176
177
+ int check_ipversion (char * address )
178
+ {
179
+ /* Check for valid IPv4 or Iv6 string. Returns AF_INET for IPv4, AF_INET6 for IPv6 */
180
+
181
+ struct in6_addr bindaddr ;
182
+
183
+ if (inet_pton (AF_INET , address , & bindaddr ) == 1 ) {
184
+ return AF_INET ;
185
+ } else {
186
+ if (inet_pton (AF_INET6 , address , & bindaddr ) == 1 ) {
187
+ return AF_INET6 ;
188
+ }
189
+ }
190
+ return 0 ;
191
+ }
192
+
173
193
/* Create server socket */
174
194
int create_socket (int port ) {
175
195
int server_sock , optval = 1 ;
176
- struct sockaddr_in server_addr ;
196
+ int validfamily = 0 ;
197
+ struct addrinfo hints , * res = NULL ;
198
+ char portstr [12 ];
199
+
200
+ memset (& hints , 0x00 , sizeof (hints ));
201
+ server_sock = -1 ;
202
+
203
+ hints .ai_flags = AI_NUMERICSERV ; /* numeric service number, not resolve */
204
+ hints .ai_family = AF_UNSPEC ;
205
+ hints .ai_socktype = SOCK_STREAM ;
206
+
207
+ /* prepare to bind on specified numeric address */
208
+ if (bind_addr != NULL ) {
209
+ /* check for numeric IP to specify IPv6 or IPv4 socket */
210
+ if (validfamily = check_ipversion (bind_addr )) {
211
+ hints .ai_family = validfamily ;
212
+ hints .ai_flags |= AI_NUMERICHOST ; /* bind_addr is a valid numeric ip, skip resolve */
213
+ }
214
+ } else {
215
+ /* if bind_address is NULL, will bind to IPv6 wildcard */
216
+ hints .ai_family = AF_INET6 ; /* Specify IPv6 socket, also allow ipv4 clients */
217
+ hints .ai_flags |= AI_PASSIVE ; /* Wildcard address */
218
+ }
219
+
220
+ sprintf (portstr , "%d" , port );
221
+
222
+ /* Check if specified socket is valid. Try to resolve address if bind_address is a hostname */
223
+ if (getaddrinfo (bind_addr , portstr , & hints , & res ) != 0 ) {
224
+ return CLIENT_RESOLVE_ERROR ;
225
+ }
177
226
178
- if ((server_sock = socket (AF_INET , SOCK_STREAM , 0 )) < 0 ) {
227
+ if ((server_sock = socket (res -> ai_family , res -> ai_socktype , res -> ai_protocol )) < 0 ) {
179
228
return SERVER_SOCKET_ERROR ;
180
229
}
181
230
231
+
182
232
if (setsockopt (server_sock , SOL_SOCKET , SO_REUSEADDR , & optval , sizeof (optval )) < 0 ) {
183
233
return SERVER_SETSOCKOPT_ERROR ;
184
234
}
185
235
186
- memset (& server_addr , 0 , sizeof (server_addr ));
187
- server_addr .sin_family = AF_INET ;
188
- server_addr .sin_port = htons (port );
189
- if (bind_addr == NULL ) {
190
- server_addr .sin_addr .s_addr = INADDR_ANY ;
191
- } else {
192
- server_addr .sin_addr .s_addr = inet_addr (bind_addr );
193
- }
194
-
195
- if (bind (server_sock , (struct sockaddr * )& server_addr , sizeof (server_addr )) != 0 ) {
236
+ if (bind (server_sock , res -> ai_addr , res -> ai_addrlen ) == -1 ) {
237
+ close (server_sock );
196
238
return SERVER_BIND_ERROR ;
197
239
}
198
240
199
- if (listen (server_sock , 20 ) < 0 ) {
241
+ if (listen (server_sock , BACKLOG ) < 0 ) {
200
242
return SERVER_LISTEN_ERROR ;
201
243
}
202
244
245
+ if (res != NULL )
246
+ freeaddrinfo (res );
247
+
203
248
return server_sock ;
204
249
}
205
250
@@ -242,7 +287,7 @@ void sigterm_handler(int signal) {
242
287
243
288
/* Main server loop */
244
289
void server_loop () {
245
- struct sockaddr_in client_addr ;
290
+ struct sockaddr_storage client_addr ;
246
291
socklen_t addrlen = sizeof (client_addr );
247
292
248
293
#ifdef USE_SYSTEMD
@@ -258,14 +303,17 @@ void server_loop() {
258
303
exit (0 );
259
304
} else
260
305
connections_processed ++ ;
306
+
261
307
close (client_sock );
262
308
}
263
309
264
310
}
265
311
312
+
266
313
/* Handle client connection */
267
- void handle_client (int client_sock , struct sockaddr_in client_addr )
314
+ void handle_client (int client_sock , struct sockaddr_storage client_addr )
268
315
{
316
+
269
317
if ((remote_sock = create_connection ()) < 0 ) {
270
318
plog (LOG_ERR , "Cannot connect to host: %m" );
271
319
goto cleanup ;
@@ -378,28 +426,42 @@ void forward_data_ext(int source_sock, int destination_sock, char *cmd) {
378
426
379
427
/* Create client connection */
380
428
int create_connection () {
381
- struct sockaddr_in server_addr ;
382
- struct hostent * server ;
429
+ struct addrinfo hints , * res = NULL ;
383
430
int sock ;
431
+ int validfamily = 0 ;
432
+ char portstr [12 ];
384
433
385
- if ((sock = socket (AF_INET , SOCK_STREAM , 0 )) < 0 ) {
386
- return CLIENT_SOCKET_ERROR ;
434
+ memset (& hints , 0x00 , sizeof (hints ));
435
+
436
+ hints .ai_flags = AI_NUMERICSERV ; /* numeric service number, not resolve */
437
+ hints .ai_family = AF_UNSPEC ;
438
+ hints .ai_socktype = SOCK_STREAM ;
439
+
440
+ sprintf (portstr , "%d" , remote_port );
441
+
442
+ /* check for numeric IP to specify IPv6 or IPv4 socket */
443
+ if (validfamily = check_ipversion (remote_host )) {
444
+ hints .ai_family = validfamily ;
445
+ hints .ai_flags |= AI_NUMERICHOST ; /* remote_host is a valid numeric ip, skip resolve */
387
446
}
388
447
389
- if ((server = gethostbyname (remote_host )) == NULL ) {
448
+ /* Check if specified host is valid. Try to resolve address if remote_host is a hostname */
449
+ if (getaddrinfo (remote_host ,portstr , & hints , & res ) != 0 ) {
390
450
errno = EFAULT ;
391
451
return CLIENT_RESOLVE_ERROR ;
392
452
}
393
453
394
- memset (& server_addr , 0 , sizeof (server_addr ));
395
- server_addr .sin_family = AF_INET ;
396
- memcpy (& server_addr .sin_addr .s_addr , server -> h_addr , server -> h_length );
397
- server_addr .sin_port = htons (remote_port );
454
+ if ((sock = socket (res -> ai_family , res -> ai_socktype , res -> ai_protocol )) < 0 ) {
455
+ return CLIENT_SOCKET_ERROR ;
456
+ }
398
457
399
- if (connect (sock , ( struct sockaddr * ) & server_addr , sizeof ( server_addr ) ) < 0 ) {
458
+ if (connect (sock , res -> ai_addr , res -> ai_addrlen ) < 0 ) {
400
459
return CLIENT_CONNECT_ERROR ;
401
460
}
402
461
462
+ if (res != NULL )
463
+ freeaddrinfo (res );
464
+
403
465
return sock ;
404
466
}
405
467
/* vim: set et ts=4 sw=4: */
0 commit comments