38c9f98fdbbfda0777a19d52d45d26907ef0e4bf
[bbaumbach/samba-autobuild/.git] / source4 / lib / socket / socket_ipv4.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Socket IPv4 functions
5
6    Copyright (C) Stefan Metzmacher 2004
7    Copyright (C) Andrew Tridgell 2004-2005
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25 #include "system/network.h"
26 #include "system/filesys.h"
27 #include "lib/socket/socket.h"
28
29 static NTSTATUS ipv4_init(struct socket_context *sock)
30 {
31         int type;
32
33         switch (sock->type) {
34         case SOCKET_TYPE_STREAM:
35                 type = SOCK_STREAM;
36                 break;
37         case SOCKET_TYPE_DGRAM:
38                 type = SOCK_DGRAM;
39                 break;
40         default:
41                 return NT_STATUS_INVALID_PARAMETER;
42         }
43
44         sock->fd = socket(PF_INET, type, 0);
45         if (sock->fd == -1) {
46                 return map_nt_error_from_unix(errno);
47         }
48
49         sock->backend_name = "ipv4";
50
51         return NT_STATUS_OK;
52 }
53
54 static void ipv4_close(struct socket_context *sock)
55 {
56         close(sock->fd);
57 }
58
59 static NTSTATUS ipv4_connect_complete(struct socket_context *sock, uint32_t flags)
60 {
61         int error=0, ret;
62         socklen_t len = sizeof(error);
63
64         /* check for any errors that may have occurred - this is needed
65            for non-blocking connect */
66         ret = getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, &error, &len);
67         if (ret == -1) {
68                 return map_nt_error_from_unix(errno);
69         }
70         if (error != 0) {
71                 return map_nt_error_from_unix(error);
72         }
73
74         if (!(flags & SOCKET_FLAG_BLOCK)) {
75                 ret = set_blocking(sock->fd, False);
76                 if (ret == -1) {
77                         return map_nt_error_from_unix(errno);
78                 }
79         }
80
81         sock->state = SOCKET_STATE_CLIENT_CONNECTED;
82
83         return NT_STATUS_OK;
84 }
85
86
87 static NTSTATUS ipv4_connect(struct socket_context *sock,
88                              const struct socket_address *my_address, 
89                              const struct socket_address *srv_address,
90                              uint32_t flags)
91 {
92         struct sockaddr_in srv_addr;
93         struct ipv4_addr my_ip;
94         struct ipv4_addr srv_ip;
95         int ret;
96
97         if (my_address && my_address->sockaddr) {
98                 ret = bind(sock->fd, my_address->sockaddr, my_address->sockaddrlen);
99                 if (ret == -1) {
100                         return map_nt_error_from_unix(errno);
101                 }
102         } else if (my_address) {
103                 my_ip = interpret_addr2(my_address->addr);
104                 
105                 if (my_ip.addr != 0 || my_address->port != 0) {
106                         struct sockaddr_in my_addr;
107                         ZERO_STRUCT(my_addr);
108 #ifdef HAVE_SOCK_SIN_LEN
109                         my_addr.sin_len         = sizeof(my_addr);
110 #endif
111                         my_addr.sin_addr.s_addr = my_ip.addr;
112                         my_addr.sin_port        = htons(my_address->port);
113                         my_addr.sin_family      = PF_INET;
114                         
115                         ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr));
116                         if (ret == -1) {
117                                 return map_nt_error_from_unix(errno);
118                         }
119                 }
120         }
121
122         if (srv_address->sockaddr) {
123                 ret = connect(sock->fd, srv_address->sockaddr, srv_address->sockaddrlen);
124                 if (ret == -1) {
125                         return map_nt_error_from_unix(errno);
126                 }
127         } else {
128                 srv_ip = interpret_addr2(srv_address->addr);
129                 if (!srv_ip.addr) {
130                         return NT_STATUS_BAD_NETWORK_NAME;
131                 }
132                 
133                 ZERO_STRUCT(srv_addr);
134 #ifdef HAVE_SOCK_SIN_LEN
135                 srv_addr.sin_len        = sizeof(srv_addr);
136 #endif
137                 srv_addr.sin_addr.s_addr= srv_ip.addr;
138                 srv_addr.sin_port       = htons(srv_address->port);
139                 srv_addr.sin_family     = PF_INET;
140
141                 ret = connect(sock->fd, (const struct sockaddr *)&srv_addr, sizeof(srv_addr));
142                 if (ret == -1) {
143                         return map_nt_error_from_unix(errno);
144                 }
145         }
146
147         return ipv4_connect_complete(sock, flags);
148 }
149
150
151 /*
152   note that for simplicity of the API, socket_listen() is also
153   use for DGRAM sockets, but in reality only a bind() is done
154 */
155 static NTSTATUS ipv4_listen(struct socket_context *sock,
156                             const struct socket_address *my_address, 
157                             int queue_size, uint32_t flags)
158 {
159         struct sockaddr_in my_addr;
160         struct ipv4_addr ip_addr;
161         int ret;
162
163         socket_set_option(sock, "SO_REUSEADDR=1", NULL);
164
165         if (my_address->sockaddr) {
166                 ret = bind(sock->fd, my_address->sockaddr, my_address->sockaddrlen);
167         } else {
168                 ip_addr = interpret_addr2(my_address->addr);
169                 
170                 ZERO_STRUCT(my_addr);
171 #ifdef HAVE_SOCK_SIN_LEN
172                 my_addr.sin_len         = sizeof(my_addr);
173 #endif
174                 my_addr.sin_addr.s_addr = ip_addr.addr;
175                 my_addr.sin_port        = htons(my_address->port);
176                 my_addr.sin_family      = PF_INET;
177                 
178                 ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr));
179         }
180
181         if (ret == -1) {
182                 return map_nt_error_from_unix(errno);
183         }
184
185         if (sock->type == SOCKET_TYPE_STREAM) {
186                 ret = listen(sock->fd, queue_size);
187                 if (ret == -1) {
188                         return map_nt_error_from_unix(errno);
189                 }
190         }
191
192         if (!(flags & SOCKET_FLAG_BLOCK)) {
193                 ret = set_blocking(sock->fd, False);
194                 if (ret == -1) {
195                         return map_nt_error_from_unix(errno);
196                 }
197         }
198
199         sock->state= SOCKET_STATE_SERVER_LISTEN;
200
201         return NT_STATUS_OK;
202 }
203
204 static NTSTATUS ipv4_accept(struct socket_context *sock, struct socket_context **new_sock)
205 {
206         struct sockaddr_in cli_addr;
207         socklen_t cli_addr_len = sizeof(cli_addr);
208         int new_fd;
209
210         if (sock->type != SOCKET_TYPE_STREAM) {
211                 return NT_STATUS_INVALID_PARAMETER;
212         }
213
214         new_fd = accept(sock->fd, (struct sockaddr *)&cli_addr, &cli_addr_len);
215         if (new_fd == -1) {
216                 return map_nt_error_from_unix(errno);
217         }
218
219         if (!(sock->flags & SOCKET_FLAG_BLOCK)) {
220                 int ret = set_blocking(new_fd, False);
221                 if (ret == -1) {
222                         close(new_fd);
223                         return map_nt_error_from_unix(errno);
224                 }
225         }
226
227         /* TODO: we could add a 'accept_check' hook here
228          *       which get the black/white lists via socket_set_accept_filter()
229          *       or something like that
230          *       --metze
231          */
232
233         (*new_sock) = talloc(NULL, struct socket_context);
234         if (!(*new_sock)) {
235                 close(new_fd);
236                 return NT_STATUS_NO_MEMORY;
237         }
238
239         /* copy the socket_context */
240         (*new_sock)->type               = sock->type;
241         (*new_sock)->state              = SOCKET_STATE_SERVER_CONNECTED;
242         (*new_sock)->flags              = sock->flags;
243
244         (*new_sock)->fd                 = new_fd;
245
246         (*new_sock)->private_data       = NULL;
247         (*new_sock)->ops                = sock->ops;
248         (*new_sock)->backend_name       = sock->backend_name;
249
250         return NT_STATUS_OK;
251 }
252
253 static NTSTATUS ipv4_recv(struct socket_context *sock, void *buf, 
254                               size_t wantlen, size_t *nread)
255 {
256         ssize_t gotlen;
257
258         *nread = 0;
259
260         gotlen = recv(sock->fd, buf, wantlen, 0);
261         if (gotlen == 0) {
262                 return NT_STATUS_END_OF_FILE;
263         } else if (gotlen == -1) {
264                 return map_nt_error_from_unix(errno);
265         }
266
267         *nread = gotlen;
268
269         return NT_STATUS_OK;
270 }
271
272
273 static NTSTATUS ipv4_recvfrom(struct socket_context *sock, void *buf, 
274                               size_t wantlen, size_t *nread, 
275                               TALLOC_CTX *addr_ctx, struct socket_address **_src)
276 {
277         ssize_t gotlen;
278         struct sockaddr_in *from_addr;
279         socklen_t from_len = sizeof(*from_addr);
280         struct socket_address *src;
281         const char *addr;
282         
283         src = talloc(addr_ctx, struct socket_address);
284         if (!src) {
285                 return NT_STATUS_NO_MEMORY;
286         }
287         
288         src->family = sock->backend_name;
289
290         from_addr = talloc(src, struct sockaddr_in);
291         if (!from_addr) {
292                 talloc_free(src);
293                 return NT_STATUS_NO_MEMORY;
294         }
295
296         src->sockaddr = (struct sockaddr *)from_addr;
297
298         *nread = 0;
299
300         gotlen = recvfrom(sock->fd, buf, wantlen, 0, 
301                           src->sockaddr, &from_len);
302         if (gotlen == 0) {
303                 talloc_free(src);
304                 return NT_STATUS_END_OF_FILE;
305         } else if (gotlen == -1) {
306                 talloc_free(src);
307                 return map_nt_error_from_unix(errno);
308         }
309
310         src->sockaddrlen = from_len;
311
312         addr = inet_ntoa(from_addr->sin_addr);
313         if (addr == NULL) {
314                 talloc_free(src);
315                 return NT_STATUS_INTERNAL_ERROR;
316         }
317         src->addr = talloc_strdup(src, addr);
318         if (src->addr == NULL) {
319                 talloc_free(src);
320                 return NT_STATUS_NO_MEMORY;
321         }
322         src->port = ntohs(from_addr->sin_port);
323
324         *nread  = gotlen;
325         *_src   = src;
326         return NT_STATUS_OK;
327 }
328
329 static NTSTATUS ipv4_send(struct socket_context *sock, 
330                               const DATA_BLOB *blob, size_t *sendlen)
331 {
332         ssize_t len;
333
334         *sendlen = 0;
335
336         len = send(sock->fd, blob->data, blob->length, 0);
337         if (len == -1) {
338                 return map_nt_error_from_unix(errno);
339         }       
340
341         *sendlen = len;
342
343         return NT_STATUS_OK;
344 }
345
346 static NTSTATUS ipv4_sendto(struct socket_context *sock, 
347                             const DATA_BLOB *blob, size_t *sendlen, 
348                             const struct socket_address *dest_addr)
349 {
350         ssize_t len;
351
352         if (dest_addr->sockaddr) {
353                 len = sendto(sock->fd, blob->data, blob->length, 0, 
354                              dest_addr->sockaddr, dest_addr->sockaddrlen);
355         } else {
356                 struct sockaddr_in srv_addr;
357                 struct ipv4_addr addr;
358                 
359                 ZERO_STRUCT(srv_addr);
360 #ifdef HAVE_SOCK_SIN_LEN
361                 srv_addr.sin_len         = sizeof(srv_addr);
362 #endif
363                 addr                     = interpret_addr2(dest_addr->addr);
364                 srv_addr.sin_addr.s_addr = addr.addr;
365                 srv_addr.sin_port        = htons(dest_addr->port);
366                 srv_addr.sin_family      = PF_INET;
367                 
368                 *sendlen = 0;
369                 
370                 len = sendto(sock->fd, blob->data, blob->length, 0, 
371                              (struct sockaddr *)&srv_addr, sizeof(srv_addr));
372         }
373         if (len == -1) {
374                 return map_nt_error_from_unix(errno);
375         }       
376
377         *sendlen = len;
378
379         return NT_STATUS_OK;
380 }
381
382 static NTSTATUS ipv4_set_option(struct socket_context *sock, const char *option, const char *val)
383 {
384         set_socket_options(sock->fd, option);
385         return NT_STATUS_OK;
386 }
387
388 static char *ipv4_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx)
389 {
390         struct sockaddr_in peer_addr;
391         socklen_t len = sizeof(peer_addr);
392         struct hostent *he;
393         int ret;
394
395         ret = getpeername(sock->fd, (struct sockaddr *)&peer_addr, &len);
396         if (ret == -1) {
397                 return NULL;
398         }
399
400         he = gethostbyaddr((char *)&peer_addr.sin_addr, sizeof(peer_addr.sin_addr), AF_INET);
401         if (he == NULL) {
402                 return NULL;
403         }
404
405         return talloc_strdup(mem_ctx, he->h_name);
406 }
407
408 static struct socket_address *ipv4_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
409 {
410         struct sockaddr_in *peer_addr;
411         socklen_t len = sizeof(*peer_addr);
412         const char *addr;
413         struct socket_address *peer;
414         int ret;
415         
416         peer = talloc(mem_ctx, struct socket_address);
417         if (!peer) {
418                 return NULL;
419         }
420         
421         peer->family = sock->backend_name;
422         peer_addr = talloc(peer, struct sockaddr_in);
423         if (!peer_addr) {
424                 talloc_free(peer);
425                 return NULL;
426         }
427
428         peer->sockaddr = (struct sockaddr *)peer_addr;
429
430         ret = getpeername(sock->fd, peer->sockaddr, &len);
431         if (ret == -1) {
432                 talloc_free(peer);
433                 return NULL;
434         }
435
436         peer->sockaddrlen = len;
437
438         addr = inet_ntoa(peer_addr->sin_addr);
439         if (addr == NULL) {
440                 talloc_free(peer);
441                 return NULL;
442         }
443         peer->addr = talloc_strdup(peer, addr);
444         if (!peer->addr) {
445                 talloc_free(peer);
446                 return NULL;
447         }
448         peer->port = ntohs(peer_addr->sin_port);
449
450         return peer;
451 }
452
453 static struct socket_address *ipv4_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
454 {
455         struct sockaddr_in *local_addr;
456         socklen_t len = sizeof(*local_addr);
457         const char *addr;
458         struct socket_address *local;
459         int ret;
460         
461         local = talloc(mem_ctx, struct socket_address);
462         if (!local) {
463                 return NULL;
464         }
465         
466         local->family = sock->backend_name;
467         local_addr = talloc(local, struct sockaddr_in);
468         if (!local_addr) {
469                 talloc_free(local);
470                 return NULL;
471         }
472
473         local->sockaddr = (struct sockaddr *)local_addr;
474
475         ret = getsockname(sock->fd, local->sockaddr, &len);
476         if (ret == -1) {
477                 talloc_free(local);
478                 return NULL;
479         }
480
481         local->sockaddrlen = len;
482
483         addr = inet_ntoa(local_addr->sin_addr);
484         if (addr == NULL) {
485                 talloc_free(local);
486                 return NULL;
487         }
488         local->addr = talloc_strdup(local, addr);
489         if (!local->addr) {
490                 talloc_free(local);
491                 return NULL;
492         }
493         local->port = ntohs(local_addr->sin_port);
494
495         return local;
496 }
497 static int ipv4_get_fd(struct socket_context *sock)
498 {
499         return sock->fd;
500 }
501
502 static NTSTATUS ipv4_pending(struct socket_context *sock, size_t *npending)
503 {
504         int value = 0;
505         if (ioctl(sock->fd, FIONREAD, &value) == 0) {
506                 *npending = value;
507                 return NT_STATUS_OK;
508         }
509         return map_nt_error_from_unix(errno);
510 }
511
512 static const struct socket_ops ipv4_ops = {
513         .name                   = "ipv4",
514         .fn_init                = ipv4_init,
515         .fn_connect             = ipv4_connect,
516         .fn_connect_complete    = ipv4_connect_complete,
517         .fn_listen              = ipv4_listen,
518         .fn_accept              = ipv4_accept,
519         .fn_recv                = ipv4_recv,
520         .fn_recvfrom            = ipv4_recvfrom,
521         .fn_send                = ipv4_send,
522         .fn_sendto              = ipv4_sendto,
523         .fn_pending             = ipv4_pending,
524         .fn_close               = ipv4_close,
525
526         .fn_set_option          = ipv4_set_option,
527
528         .fn_get_peer_name       = ipv4_get_peer_name,
529         .fn_get_peer_addr       = ipv4_get_peer_addr,
530         .fn_get_my_addr         = ipv4_get_my_addr,
531         .fn_get_fd              = ipv4_get_fd
532 };
533
534 const struct socket_ops *socket_ipv4_ops(enum socket_type type)
535 {
536         return &ipv4_ops;
537 }