Coverage Report

Created: 2025-12-31 06:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source4/lib/socket/socket_ip.c
Line
Count
Source
1
/* 
2
   Unix SMB/CIFS implementation.
3
4
   Socket IPv4/IPv6 functions
5
6
   Copyright (C) Stefan Metzmacher 2004
7
   Copyright (C) Andrew Tridgell 2004-2005
8
   Copyright (C) Jelmer Vernooij 2004
9
   
10
   This program is free software; you can redistribute it and/or modify
11
   it under the terms of the GNU General Public License as published by
12
   the Free Software Foundation; either version 3 of the License, or
13
   (at your option) any later version.
14
   
15
   This program is distributed in the hope that it will be useful,
16
   but WITHOUT ANY WARRANTY; without even the implied warranty of
17
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
   GNU General Public License for more details.
19
   
20
   You should have received a copy of the GNU General Public License
21
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
*/
23
24
#include "includes.h"
25
#include "system/filesys.h"
26
#include "lib/socket/socket.h"
27
#include "system/network.h"
28
#include "lib/util/util_net.h"
29
30
#undef strcasecmp
31
32
_PUBLIC_ const struct socket_ops *socket_ipv4_ops(enum socket_type type);
33
_PUBLIC_ const struct socket_ops *socket_ipv6_ops(enum socket_type type);
34
35
static NTSTATUS ipv4_init(struct socket_context *sock)
36
0
{
37
0
  int type;
38
39
0
  switch (sock->type) {
40
0
  case SOCKET_TYPE_STREAM:
41
0
    type = SOCK_STREAM;
42
0
    break;
43
0
  case SOCKET_TYPE_DGRAM:
44
0
    type = SOCK_DGRAM;
45
0
    break;
46
0
  default:
47
0
    return NT_STATUS_INVALID_PARAMETER;
48
0
  }
49
50
0
  sock->fd = socket(PF_INET, type, 0);
51
0
  if (sock->fd == -1) {
52
0
    return map_nt_error_from_unix_common(errno);
53
0
  }
54
55
0
  smb_set_close_on_exec(sock->fd);
56
57
0
  sock->backend_name = "ipv4";
58
0
  sock->family = AF_INET;
59
60
0
  return NT_STATUS_OK;
61
0
}
62
63
static void ip_close(struct socket_context *sock)
64
0
{
65
0
  if (sock->fd != -1) {
66
0
    close(sock->fd);
67
0
    sock->fd = -1;
68
0
  }
69
0
}
70
71
static NTSTATUS ip_connect_complete(struct socket_context *sock, uint32_t flags)
72
0
{
73
0
  int error=0, ret;
74
0
  socklen_t len = sizeof(error);
75
76
  /* check for any errors that may have occurred - this is needed
77
     for non-blocking connect */
78
0
  ret = getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, &error, &len);
79
0
  if (ret == -1) {
80
0
    return map_nt_error_from_unix_common(errno);
81
0
  }
82
0
  if (error != 0) {
83
0
    return map_nt_error_from_unix_common(error);
84
0
  }
85
86
0
  ret = set_blocking(sock->fd, false);
87
0
  if (ret == -1) {
88
0
    return map_nt_error_from_unix_common(errno);
89
0
  }
90
91
0
  sock->state = SOCKET_STATE_CLIENT_CONNECTED;
92
93
0
  return NT_STATUS_OK;
94
0
}
95
96
97
static NTSTATUS ipv4_connect(struct socket_context *sock,
98
           const struct socket_address *my_address, 
99
           const struct socket_address *srv_address,
100
           uint32_t flags)
101
0
{
102
0
  struct sockaddr_in srv_addr;
103
0
  struct in_addr my_ip;
104
0
  struct in_addr srv_ip;
105
0
  int ret;
106
107
0
  if (my_address && my_address->sockaddr) {
108
0
    ret = bind(sock->fd, my_address->sockaddr, my_address->sockaddrlen);
109
0
    if (ret == -1) {
110
0
      return map_nt_error_from_unix_common(errno);
111
0
    }
112
0
  } else if (my_address) {
113
0
    my_ip = interpret_addr2(my_address->addr);
114
    
115
0
    if (my_ip.s_addr != 0 || my_address->port != 0) {
116
0
      struct sockaddr_in my_addr;
117
0
      ZERO_STRUCT(my_addr);
118
#ifdef HAVE_SOCK_SIN_LEN
119
      my_addr.sin_len   = sizeof(my_addr);
120
#endif
121
0
      my_addr.sin_addr.s_addr = my_ip.s_addr;
122
0
      my_addr.sin_port  = htons(my_address->port);
123
0
      my_addr.sin_family  = PF_INET;
124
      
125
0
      ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr));
126
0
      if (ret == -1) {
127
0
        return map_nt_error_from_unix_common(errno);
128
0
      }
129
0
    }
130
0
  }
131
132
0
  if (srv_address->sockaddr) {
133
0
    ret = connect(sock->fd, srv_address->sockaddr, srv_address->sockaddrlen);
134
0
    if (ret == -1) {
135
0
      return map_nt_error_from_unix_common(errno);
136
0
    }
137
0
  } else {
138
0
    srv_ip = interpret_addr2(srv_address->addr);
139
0
    if (!srv_ip.s_addr) {
140
0
      return NT_STATUS_BAD_NETWORK_NAME;
141
0
    }
142
143
0
    SMB_ASSERT(srv_address->port != 0);
144
    
145
0
    ZERO_STRUCT(srv_addr);
146
#ifdef HAVE_SOCK_SIN_LEN
147
    srv_addr.sin_len  = sizeof(srv_addr);
148
#endif
149
0
    srv_addr.sin_addr.s_addr= srv_ip.s_addr;
150
0
    srv_addr.sin_port = htons(srv_address->port);
151
0
    srv_addr.sin_family = PF_INET;
152
153
0
    ret = connect(sock->fd, (const struct sockaddr *)&srv_addr, sizeof(srv_addr));
154
0
    if (ret == -1) {
155
0
      return map_nt_error_from_unix_common(errno);
156
0
    }
157
0
  }
158
159
0
  return ip_connect_complete(sock, flags);
160
0
}
161
162
163
/*
164
  note that for simplicity of the API, socket_listen() is also
165
  use for DGRAM sockets, but in reality only a bind() is done
166
*/
167
static NTSTATUS ipv4_listen(struct socket_context *sock,
168
          const struct socket_address *my_address, 
169
          int queue_size, uint32_t flags)
170
0
{
171
0
  struct sockaddr_in my_addr;
172
0
  struct in_addr ip_addr;
173
0
  int ret;
174
175
0
  socket_set_option(sock, "SO_REUSEADDR=1", NULL);
176
177
0
  if (my_address->sockaddr) {
178
0
    ret = bind(sock->fd, my_address->sockaddr, my_address->sockaddrlen);
179
0
  } else {
180
0
    ip_addr = interpret_addr2(my_address->addr);
181
    
182
0
    ZERO_STRUCT(my_addr);
183
#ifdef HAVE_SOCK_SIN_LEN
184
    my_addr.sin_len   = sizeof(my_addr);
185
#endif
186
0
    my_addr.sin_addr.s_addr = ip_addr.s_addr;
187
0
    my_addr.sin_port  = htons(my_address->port);
188
0
    my_addr.sin_family  = PF_INET;
189
    
190
0
    ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr));
191
0
  }
192
193
0
  if (ret == -1) {
194
0
    return map_nt_error_from_unix_common(errno);
195
0
  }
196
197
0
  if (sock->type == SOCKET_TYPE_STREAM) {
198
0
    ret = listen(sock->fd, queue_size);
199
0
    if (ret == -1) {
200
0
      return map_nt_error_from_unix_common(errno);
201
0
    }
202
0
  }
203
204
0
  ret = set_blocking(sock->fd, false);
205
0
  if (ret == -1) {
206
0
    return map_nt_error_from_unix_common(errno);
207
0
  }
208
209
0
  sock->state= SOCKET_STATE_SERVER_LISTEN;
210
211
0
  return NT_STATUS_OK;
212
0
}
213
214
static NTSTATUS ipv4_accept(struct socket_context *sock, struct socket_context **new_sock)
215
0
{
216
0
  struct sockaddr_in cli_addr;
217
0
  socklen_t cli_addr_len = sizeof(cli_addr);
218
0
  int new_fd, ret;
219
220
0
  if (sock->type != SOCKET_TYPE_STREAM) {
221
0
    return NT_STATUS_INVALID_PARAMETER;
222
0
  }
223
224
0
  new_fd = accept(sock->fd, (struct sockaddr *)&cli_addr, &cli_addr_len);
225
0
  if (new_fd == -1) {
226
0
    return map_nt_error_from_unix_common(errno);
227
0
  }
228
229
0
  ret = set_blocking(new_fd, false);
230
0
  if (ret == -1) {
231
0
    close(new_fd);
232
0
    return map_nt_error_from_unix_common(errno);
233
0
  }
234
235
0
  smb_set_close_on_exec(new_fd);
236
237
238
  /* TODO: we could add a 'accept_check' hook here
239
   *   which get the black/white lists via socket_set_accept_filter()
240
   *   or something like that
241
   *   --metze
242
   */
243
244
0
  (*new_sock) = talloc(NULL, struct socket_context);
245
0
  if (!(*new_sock)) {
246
0
    close(new_fd);
247
0
    return NT_STATUS_NO_MEMORY;
248
0
  }
249
250
  /* copy the socket_context */
251
0
  (*new_sock)->type   = sock->type;
252
0
  (*new_sock)->state    = SOCKET_STATE_SERVER_CONNECTED;
253
0
  (*new_sock)->flags    = sock->flags;
254
255
0
  (*new_sock)->fd     = new_fd;
256
257
0
  (*new_sock)->private_data = NULL;
258
0
  (*new_sock)->ops    = sock->ops;
259
0
  (*new_sock)->backend_name = sock->backend_name;
260
261
0
  return NT_STATUS_OK;
262
0
}
263
264
static NTSTATUS ip_recv(struct socket_context *sock, void *buf, 
265
            size_t wantlen, size_t *nread)
266
0
{
267
0
  ssize_t gotlen;
268
269
0
  *nread = 0;
270
271
0
  gotlen = recv(sock->fd, buf, wantlen, 0);
272
0
  if (gotlen == 0) {
273
0
    return NT_STATUS_END_OF_FILE;
274
0
  } else if (gotlen == -1) {
275
0
    return map_nt_error_from_unix_common(errno);
276
0
  }
277
278
0
  *nread = gotlen;
279
280
0
  return NT_STATUS_OK;
281
0
}
282
283
284
static NTSTATUS ipv4_recvfrom(struct socket_context *sock, void *buf, 
285
            size_t wantlen, size_t *nread, 
286
            TALLOC_CTX *addr_ctx, struct socket_address **_src)
287
0
{
288
0
  ssize_t gotlen;
289
0
  struct sockaddr_in *from_addr;
290
0
  socklen_t from_len = sizeof(*from_addr);
291
0
  struct socket_address *src;
292
0
  char addrstring[INET_ADDRSTRLEN];
293
  
294
0
  src = talloc(addr_ctx, struct socket_address);
295
0
  if (!src) {
296
0
    return NT_STATUS_NO_MEMORY;
297
0
  }
298
  
299
0
  src->family = sock->backend_name;
300
301
0
  from_addr = talloc(src, struct sockaddr_in);
302
0
  if (!from_addr) {
303
0
    talloc_free(src);
304
0
    return NT_STATUS_NO_MEMORY;
305
0
  }
306
307
0
  src->sockaddr = (struct sockaddr *)from_addr;
308
309
0
  *nread = 0;
310
311
0
  gotlen = recvfrom(sock->fd, buf, wantlen, 0, 
312
0
        src->sockaddr, &from_len);
313
0
  if (gotlen == 0) {
314
0
    talloc_free(src);
315
0
    return NT_STATUS_END_OF_FILE;
316
0
  }
317
0
  if (gotlen == -1) {
318
0
    talloc_free(src);
319
0
    return map_nt_error_from_unix_common(errno);
320
0
  }
321
322
0
  src->sockaddrlen = from_len;
323
324
0
  if (inet_ntop(AF_INET, &from_addr->sin_addr, addrstring, 
325
0
       sizeof(addrstring)) == NULL) {
326
0
    talloc_free(src);
327
0
    return NT_STATUS_INTERNAL_ERROR;
328
0
  }
329
0
  src->addr = talloc_strdup(src, addrstring);
330
0
  if (src->addr == NULL) {
331
0
    talloc_free(src);
332
0
    return NT_STATUS_NO_MEMORY;
333
0
  }
334
0
  src->port = ntohs(from_addr->sin_port);
335
336
0
  *nread  = gotlen;
337
0
  *_src = src;
338
0
  return NT_STATUS_OK;
339
0
}
340
341
static NTSTATUS ip_send(struct socket_context *sock, 
342
            const DATA_BLOB *blob, size_t *sendlen)
343
0
{
344
0
  ssize_t len;
345
346
0
  *sendlen = 0;
347
348
0
  len = send(sock->fd, blob->data, blob->length, 0);
349
0
  if (len == -1) {
350
0
    return map_nt_error_from_unix_common(errno);
351
0
  }  
352
353
0
  *sendlen = len;
354
355
0
  return NT_STATUS_OK;
356
0
}
357
358
static NTSTATUS ipv4_sendto(struct socket_context *sock, 
359
          const DATA_BLOB *blob, size_t *sendlen, 
360
          const struct socket_address *dest_addr)
361
0
{
362
0
  ssize_t len;
363
364
0
  if (dest_addr->sockaddr) {
365
0
    len = sendto(sock->fd, blob->data, blob->length, 0, 
366
0
           dest_addr->sockaddr, dest_addr->sockaddrlen);
367
0
  } else {
368
0
    struct sockaddr_in srv_addr;
369
0
    struct in_addr addr;
370
371
0
    SMB_ASSERT(dest_addr->port != 0);
372
    
373
0
    ZERO_STRUCT(srv_addr);
374
#ifdef HAVE_SOCK_SIN_LEN
375
    srv_addr.sin_len         = sizeof(srv_addr);
376
#endif
377
0
    addr                     = interpret_addr2(dest_addr->addr);
378
0
    if (addr.s_addr == 0) {
379
0
      return NT_STATUS_HOST_UNREACHABLE;
380
0
    }
381
0
    srv_addr.sin_addr.s_addr = addr.s_addr;
382
0
    srv_addr.sin_port        = htons(dest_addr->port);
383
0
    srv_addr.sin_family      = PF_INET;
384
    
385
0
    *sendlen = 0;
386
    
387
0
    len = sendto(sock->fd, blob->data, blob->length, 0, 
388
0
           (struct sockaddr *)&srv_addr, sizeof(srv_addr));
389
0
  }
390
0
  if (len == -1) {
391
0
    return map_nt_error_from_unix_common(errno);
392
0
  }  
393
394
0
  *sendlen = len;
395
396
0
  return NT_STATUS_OK;
397
0
}
398
399
static NTSTATUS ipv4_set_option(struct socket_context *sock, const char *option, const char *val)
400
0
{
401
0
  set_socket_options(sock->fd, option);
402
0
  return NT_STATUS_OK;
403
0
}
404
405
static char *ipv4_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx)
406
0
{
407
0
  struct sockaddr_in peer_addr;
408
0
  socklen_t len = sizeof(peer_addr);
409
0
  struct hostent *he;
410
0
  int ret;
411
412
0
  ret = getpeername(sock->fd, (struct sockaddr *)&peer_addr, &len);
413
0
  if (ret == -1) {
414
0
    return NULL;
415
0
  }
416
417
0
  he = gethostbyaddr((char *)&peer_addr.sin_addr, sizeof(peer_addr.sin_addr), AF_INET);
418
0
  if (he == NULL) {
419
0
    return NULL;
420
0
  }
421
422
0
  return talloc_strdup(mem_ctx, he->h_name);
423
0
}
424
425
static struct socket_address *ipv4_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
426
0
{
427
0
  struct sockaddr_in *peer_addr;
428
0
  socklen_t len = sizeof(*peer_addr);
429
0
  struct socket_address *peer;
430
0
  char addrstring[INET_ADDRSTRLEN];
431
0
  int ret;
432
  
433
0
  peer = talloc(mem_ctx, struct socket_address);
434
0
  if (!peer) {
435
0
    return NULL;
436
0
  }
437
  
438
0
  peer->family = sock->backend_name;
439
0
  peer_addr = talloc(peer, struct sockaddr_in);
440
0
  if (!peer_addr) {
441
0
    talloc_free(peer);
442
0
    return NULL;
443
0
  }
444
445
0
  peer->sockaddr = (struct sockaddr *)peer_addr;
446
447
0
  ret = getpeername(sock->fd, peer->sockaddr, &len);
448
0
  if (ret == -1) {
449
0
    talloc_free(peer);
450
0
    return NULL;
451
0
  }
452
453
0
  peer->sockaddrlen = len;
454
455
0
  if (inet_ntop(AF_INET, &peer_addr->sin_addr, addrstring,
456
0
       sizeof(addrstring)) == NULL) {
457
0
    talloc_free(peer);
458
0
    return NULL;
459
0
  }
460
0
  peer->addr = talloc_strdup(peer, addrstring);
461
0
  if (!peer->addr) {
462
0
    talloc_free(peer);
463
0
    return NULL;
464
0
  }
465
0
  peer->port = ntohs(peer_addr->sin_port);
466
467
0
  return peer;
468
0
}
469
470
static struct socket_address *ipv4_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
471
0
{
472
0
  struct sockaddr_in *local_addr;
473
0
  socklen_t len = sizeof(*local_addr);
474
0
  struct socket_address *local;
475
0
  char addrstring[INET_ADDRSTRLEN];
476
0
  int ret;
477
  
478
0
  local = talloc(mem_ctx, struct socket_address);
479
0
  if (!local) {
480
0
    return NULL;
481
0
  }
482
  
483
0
  local->family = sock->backend_name;
484
0
  local_addr = talloc(local, struct sockaddr_in);
485
0
  if (!local_addr) {
486
0
    talloc_free(local);
487
0
    return NULL;
488
0
  }
489
490
0
  local->sockaddr = (struct sockaddr *)local_addr;
491
492
0
  ret = getsockname(sock->fd, local->sockaddr, &len);
493
0
  if (ret == -1) {
494
0
    talloc_free(local);
495
0
    return NULL;
496
0
  }
497
498
0
  local->sockaddrlen = len;
499
500
0
  if (inet_ntop(AF_INET, &local_addr->sin_addr, addrstring, 
501
0
       sizeof(addrstring)) == NULL) {
502
0
    talloc_free(local);
503
0
    return NULL;
504
0
  }
505
0
  local->addr = talloc_strdup(local, addrstring);
506
0
  if (!local->addr) {
507
0
    talloc_free(local);
508
0
    return NULL;
509
0
  }
510
0
  local->port = ntohs(local_addr->sin_port);
511
512
0
  return local;
513
0
}
514
static int ip_get_fd(struct socket_context *sock)
515
0
{
516
0
  return sock->fd;
517
0
}
518
519
static NTSTATUS ip_pending(struct socket_context *sock, size_t *npending)
520
0
{
521
0
  int value = 0;
522
0
  if (ioctl(sock->fd, FIONREAD, &value) == 0) {
523
0
    *npending = value;
524
0
    return NT_STATUS_OK;
525
0
  }
526
0
  return map_nt_error_from_unix_common(errno);
527
0
}
528
529
static const struct socket_ops ipv4_ops = {
530
  .name     = "ipv4",
531
  .fn_init    = ipv4_init,
532
  .fn_connect   = ipv4_connect,
533
  .fn_connect_complete  = ip_connect_complete,
534
  .fn_listen    = ipv4_listen,
535
  .fn_accept    = ipv4_accept,
536
  .fn_recv    = ip_recv,
537
  .fn_recvfrom    = ipv4_recvfrom,
538
  .fn_send    = ip_send,
539
  .fn_sendto    = ipv4_sendto,
540
  .fn_pending   = ip_pending,
541
  .fn_close   = ip_close,
542
543
  .fn_set_option    = ipv4_set_option,
544
545
  .fn_get_peer_name = ipv4_get_peer_name,
546
  .fn_get_peer_addr = ipv4_get_peer_addr,
547
  .fn_get_my_addr   = ipv4_get_my_addr,
548
549
  .fn_get_fd    = ip_get_fd
550
};
551
552
_PUBLIC_ const struct socket_ops *socket_ipv4_ops(enum socket_type type)
553
0
{
554
0
  return &ipv4_ops;
555
0
}
556
557
#ifdef HAVE_IPV6
558
559
static struct in6_addr interpret_addr6(const char *name)
560
0
{
561
0
  char addr[INET6_ADDRSTRLEN];
562
0
  struct in6_addr dest6;
563
0
  const char *sp = name;
564
0
  char *p;
565
0
  int ret;
566
567
0
  if (sp == NULL) return in6addr_any;
568
569
0
  p = strchr_m(sp, '%');
570
571
0
  if (strcasecmp(sp, "localhost") == 0) {
572
0
    sp = "::1";
573
0
  }
574
575
  /*
576
   * Cope with link-local.
577
   * This is IP:v6:addr%ifname.
578
   */
579
580
0
  if (p && (p > sp) && (if_nametoindex(p+1) != 0)) {
581
0
    strlcpy(addr, sp,
582
0
      MIN(PTR_DIFF(p,sp)+1,
583
0
        sizeof(addr)));
584
0
    sp = addr;
585
0
  }
586
587
0
  ret = inet_pton(AF_INET6, sp, &dest6);
588
0
  if (ret > 0) {
589
0
    return dest6;
590
0
  }
591
592
0
  return in6addr_any;
593
0
}
594
595
static NTSTATUS ipv6_init(struct socket_context *sock)
596
0
{
597
0
  int type;
598
599
0
  switch (sock->type) {
600
0
  case SOCKET_TYPE_STREAM:
601
0
    type = SOCK_STREAM;
602
0
    break;
603
0
  case SOCKET_TYPE_DGRAM:
604
0
    type = SOCK_DGRAM;
605
0
    break;
606
0
  default:
607
0
    return NT_STATUS_INVALID_PARAMETER;
608
0
  }
609
610
0
  sock->fd = socket(PF_INET6, type, 0);
611
0
  if (sock->fd == -1) {
612
0
    return map_nt_error_from_unix_common(errno);
613
0
  }
614
615
0
  smb_set_close_on_exec(sock->fd);
616
617
0
  sock->backend_name = "ipv6";
618
0
  sock->family = AF_INET6;
619
620
0
  return NT_STATUS_OK;
621
0
}
622
623
static NTSTATUS ipv6_tcp_connect(struct socket_context *sock,
624
         const struct socket_address *my_address,
625
         const struct socket_address *srv_address,
626
         uint32_t flags)
627
0
{
628
0
  int ret;
629
630
0
  if (my_address && my_address->sockaddr) {
631
0
    ret = bind(sock->fd, my_address->sockaddr, my_address->sockaddrlen);
632
0
    if (ret == -1) {
633
0
      return map_nt_error_from_unix_common(errno);
634
0
    }
635
0
  } else if (my_address) {
636
0
    struct in6_addr my_ip;
637
0
    my_ip = interpret_addr6(my_address->addr);
638
639
0
    if (memcmp(&my_ip, &in6addr_any, sizeof(my_ip)) || my_address->port != 0) {
640
0
      struct sockaddr_in6 my_addr;
641
0
      ZERO_STRUCT(my_addr);
642
0
      my_addr.sin6_addr = my_ip;
643
0
      my_addr.sin6_port = htons(my_address->port);
644
0
      my_addr.sin6_family = PF_INET6;
645
      
646
0
      ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr));
647
0
      if (ret == -1) {
648
0
        return map_nt_error_from_unix_common(errno);
649
0
      }
650
0
    }
651
0
  }
652
653
0
  if (srv_address->sockaddr) {
654
0
    ret = connect(sock->fd, srv_address->sockaddr, srv_address->sockaddrlen);
655
0
  } else {
656
0
    struct in6_addr srv_ip;
657
0
    struct sockaddr_in6 srv_addr;
658
0
    srv_ip = interpret_addr6(srv_address->addr);
659
0
    if (memcmp(&srv_ip, &in6addr_any, sizeof(srv_ip)) == 0) {
660
0
      return NT_STATUS_BAD_NETWORK_NAME;
661
0
    }
662
    
663
0
    ZERO_STRUCT(srv_addr);
664
0
    srv_addr.sin6_addr  = srv_ip;
665
0
    srv_addr.sin6_port  = htons(srv_address->port);
666
0
    srv_addr.sin6_family  = PF_INET6;
667
    
668
0
    ret = connect(sock->fd, (const struct sockaddr *)&srv_addr, sizeof(srv_addr));
669
0
  }
670
0
  if (ret == -1) {
671
0
    return map_nt_error_from_unix_common(errno);
672
0
  }
673
674
0
  return ip_connect_complete(sock, flags);
675
0
}
676
677
/*
678
  fix the sin6_scope_id based on the address interface
679
 */
680
static void fix_scope_id(struct sockaddr_in6 *in6,
681
       const char *address)
682
0
{
683
0
  const char *p = strchr(address, '%');
684
0
  if (p != NULL) {
685
0
    in6->sin6_scope_id = if_nametoindex(p+1);
686
0
  }
687
0
}
688
689
690
static NTSTATUS ipv6_listen(struct socket_context *sock,
691
          const struct socket_address *my_address,
692
          int queue_size, uint32_t flags)
693
0
{
694
0
  struct sockaddr_in6 my_addr;
695
0
  struct in6_addr ip_addr;
696
0
  int ret;
697
698
0
  socket_set_option(sock, "SO_REUSEADDR=1", NULL);
699
700
0
  if (my_address->sockaddr) {
701
0
    ret = bind(sock->fd, my_address->sockaddr, my_address->sockaddrlen);
702
0
  } else {
703
0
    int one = 1;
704
0
    ip_addr = interpret_addr6(my_address->addr);
705
    
706
0
    ZERO_STRUCT(my_addr);
707
0
    my_addr.sin6_addr = ip_addr;
708
0
    my_addr.sin6_port = htons(my_address->port);
709
0
    my_addr.sin6_family = PF_INET6;
710
0
    fix_scope_id(&my_addr, my_address->addr);
711
712
    /* when binding on ipv6 we always want to only bind on v6 */
713
0
    ret = setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY,
714
0
         (const void *)&one, sizeof(one));
715
0
    if (ret != -1) {
716
0
      ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr));
717
0
    }
718
0
  }
719
720
0
  if (ret == -1) {
721
0
    return map_nt_error_from_unix_common(errno);
722
0
  }
723
724
0
  if (sock->type == SOCKET_TYPE_STREAM) {
725
0
    ret = listen(sock->fd, queue_size);
726
0
    if (ret == -1) {
727
0
      return map_nt_error_from_unix_common(errno);
728
0
    }
729
0
  }
730
731
0
  ret = set_blocking(sock->fd, false);
732
0
  if (ret == -1) {
733
0
    return map_nt_error_from_unix_common(errno);
734
0
  }
735
736
0
  sock->state= SOCKET_STATE_SERVER_LISTEN;
737
738
0
  return NT_STATUS_OK;
739
0
}
740
741
static NTSTATUS ipv6_tcp_accept(struct socket_context *sock, struct socket_context **new_sock)
742
0
{
743
0
  struct sockaddr_in6 cli_addr;
744
0
  socklen_t cli_addr_len = sizeof(cli_addr);
745
0
  int new_fd, ret;
746
  
747
0
  if (sock->type != SOCKET_TYPE_STREAM) {
748
0
    return NT_STATUS_INVALID_PARAMETER;
749
0
  }
750
751
0
  new_fd = accept(sock->fd, (struct sockaddr *)&cli_addr, &cli_addr_len);
752
0
  if (new_fd == -1) {
753
0
    return map_nt_error_from_unix_common(errno);
754
0
  }
755
756
0
  ret = set_blocking(new_fd, false);
757
0
  if (ret == -1) {
758
0
    close(new_fd);
759
0
    return map_nt_error_from_unix_common(errno);
760
0
  }
761
0
  smb_set_close_on_exec(new_fd);
762
763
  /* TODO: we could add a 'accept_check' hook here
764
   *   which get the black/white lists via socket_set_accept_filter()
765
   *   or something like that
766
   *   --metze
767
   */
768
769
0
  (*new_sock) = talloc(NULL, struct socket_context);
770
0
  if (!(*new_sock)) {
771
0
    close(new_fd);
772
0
    return NT_STATUS_NO_MEMORY;
773
0
  }
774
775
  /* copy the socket_context */
776
0
  (*new_sock)->type   = sock->type;
777
0
  (*new_sock)->state    = SOCKET_STATE_SERVER_CONNECTED;
778
0
  (*new_sock)->flags    = sock->flags;
779
780
0
  (*new_sock)->fd     = new_fd;
781
782
0
  (*new_sock)->private_data = NULL;
783
0
  (*new_sock)->ops    = sock->ops;
784
0
  (*new_sock)->backend_name = sock->backend_name;
785
786
0
  return NT_STATUS_OK;
787
0
}
788
789
static NTSTATUS ipv6_recvfrom(struct socket_context *sock, void *buf, 
790
            size_t wantlen, size_t *nread, 
791
            TALLOC_CTX *addr_ctx, struct socket_address **_src)
792
0
{
793
0
  ssize_t gotlen;
794
0
  struct sockaddr_in6 *from_addr;
795
0
  socklen_t from_len = sizeof(*from_addr);
796
0
  struct socket_address *src;
797
0
  char addrstring[INET6_ADDRSTRLEN];
798
  
799
0
  src = talloc(addr_ctx, struct socket_address);
800
0
  if (!src) {
801
0
    return NT_STATUS_NO_MEMORY;
802
0
  }
803
  
804
0
  src->family = sock->backend_name;
805
806
0
  from_addr = talloc(src, struct sockaddr_in6);
807
0
  if (!from_addr) {
808
0
    talloc_free(src);
809
0
    return NT_STATUS_NO_MEMORY;
810
0
  }
811
812
0
  src->sockaddr = (struct sockaddr *)from_addr;
813
814
0
  *nread = 0;
815
816
0
  gotlen = recvfrom(sock->fd, buf, wantlen, 0, 
817
0
        src->sockaddr, &from_len);
818
0
  if (gotlen == 0) {
819
0
    talloc_free(src);
820
0
    return NT_STATUS_END_OF_FILE;
821
0
  } else if (gotlen == -1) {
822
0
    talloc_free(src);
823
0
    return map_nt_error_from_unix_common(errno);
824
0
  }
825
826
0
  src->sockaddrlen = from_len;
827
828
0
  if (inet_ntop(AF_INET6, &from_addr->sin6_addr, addrstring, sizeof(addrstring)) == NULL) {
829
0
    DEBUG(0, ("Unable to convert address to string: %s\n", strerror(errno)));
830
0
    talloc_free(src);
831
0
        return NT_STATUS_INTERNAL_ERROR;
832
0
  }
833
834
0
  src->addr = talloc_strdup(src, addrstring);
835
0
  if (src->addr == NULL) {
836
0
    talloc_free(src);
837
0
    return NT_STATUS_NO_MEMORY;
838
0
  }
839
0
  src->port = ntohs(from_addr->sin6_port);
840
841
0
  *nread  = gotlen;
842
0
  *_src = src;
843
0
  return NT_STATUS_OK;
844
0
}
845
846
static NTSTATUS ipv6_sendto(struct socket_context *sock, 
847
          const DATA_BLOB *blob, size_t *sendlen, 
848
          const struct socket_address *dest_addr)
849
0
{
850
0
  ssize_t len;
851
852
0
  if (dest_addr->sockaddr) {
853
0
    len = sendto(sock->fd, blob->data, blob->length, 0, 
854
0
           dest_addr->sockaddr, dest_addr->sockaddrlen);
855
0
  } else {
856
0
    struct sockaddr_in6 srv_addr;
857
0
    struct in6_addr addr;
858
    
859
0
    ZERO_STRUCT(srv_addr);
860
0
    addr                     = interpret_addr6(dest_addr->addr);
861
0
    if (memcmp(&addr.s6_addr, &in6addr_any,
862
0
         sizeof(addr.s6_addr)) == 0) {
863
0
      return NT_STATUS_HOST_UNREACHABLE;
864
0
    }
865
0
    srv_addr.sin6_addr = addr;
866
0
    srv_addr.sin6_port        = htons(dest_addr->port);
867
0
    srv_addr.sin6_family      = PF_INET6;
868
    
869
0
    *sendlen = 0;
870
    
871
0
    len = sendto(sock->fd, blob->data, blob->length, 0, 
872
0
           (struct sockaddr *)&srv_addr, sizeof(srv_addr));
873
0
  }
874
0
  if (len == -1) {
875
0
    return map_nt_error_from_unix_common(errno);
876
0
  }  
877
878
0
  *sendlen = len;
879
880
0
  return NT_STATUS_OK;
881
0
}
882
883
static NTSTATUS ipv6_set_option(struct socket_context *sock, const char *option, const char *val)
884
0
{
885
0
  set_socket_options(sock->fd, option);
886
0
  return NT_STATUS_OK;
887
0
}
888
889
static char *ipv6_tcp_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx)
890
0
{
891
0
  struct sockaddr_in6 peer_addr;
892
0
  socklen_t len = sizeof(peer_addr);
893
0
  struct hostent *he;
894
0
  int ret;
895
896
0
  ret = getpeername(sock->fd, (struct sockaddr *)&peer_addr, &len);
897
0
  if (ret == -1) {
898
0
    return NULL;
899
0
  }
900
901
0
  he = gethostbyaddr((char *)&peer_addr.sin6_addr, sizeof(peer_addr.sin6_addr), AF_INET6);
902
0
  if (he == NULL) {
903
0
    return NULL;
904
0
  }
905
906
0
  return talloc_strdup(mem_ctx, he->h_name);
907
0
}
908
909
static struct socket_address *ipv6_tcp_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
910
0
{
911
0
  struct sockaddr_in6 *peer_addr;
912
0
  socklen_t len = sizeof(*peer_addr);
913
0
  struct socket_address *peer;
914
0
  int ret;
915
0
  char addr[128];
916
0
  const char *addr_ret;
917
  
918
0
  peer = talloc(mem_ctx, struct socket_address);
919
0
  if (!peer) {
920
0
    return NULL;
921
0
  }
922
  
923
0
  peer->family = sock->backend_name;
924
0
  peer_addr = talloc(peer, struct sockaddr_in6);
925
0
  if (!peer_addr) {
926
0
    talloc_free(peer);
927
0
    return NULL;
928
0
  }
929
930
0
  peer->sockaddr = (struct sockaddr *)peer_addr;
931
932
0
  ret = getpeername(sock->fd, peer->sockaddr, &len);
933
0
  if (ret == -1) {
934
0
    talloc_free(peer);
935
0
    return NULL;
936
0
  }
937
938
0
  peer->sockaddrlen = len;
939
940
0
  addr_ret = inet_ntop(AF_INET6, &peer_addr->sin6_addr, addr, sizeof(addr));
941
0
  if (addr_ret == NULL) {
942
0
    talloc_free(peer);
943
0
    return NULL;
944
0
  }
945
946
0
  peer->addr = talloc_strdup(peer, addr_ret);
947
0
  if (peer->addr == NULL) {
948
0
    talloc_free(peer);
949
0
    return NULL;
950
0
  }
951
952
0
  peer->port = ntohs(peer_addr->sin6_port);
953
954
0
  return peer;
955
0
}
956
957
static struct socket_address *ipv6_tcp_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
958
0
{
959
0
  struct sockaddr_in6 *local_addr;
960
0
  socklen_t len = sizeof(*local_addr);
961
0
  struct socket_address *local;
962
0
  int ret;
963
0
  char addrstring[INET6_ADDRSTRLEN];
964
  
965
0
  local = talloc(mem_ctx, struct socket_address);
966
0
  if (!local) {
967
0
    return NULL;
968
0
  }
969
  
970
0
  local->family = sock->backend_name;
971
0
  local_addr = talloc(local, struct sockaddr_in6);
972
0
  if (!local_addr) {
973
0
    talloc_free(local);
974
0
    return NULL;
975
0
  }
976
977
0
  local->sockaddr = (struct sockaddr *)local_addr;
978
979
0
  ret = getsockname(sock->fd, local->sockaddr, &len);
980
0
  if (ret == -1) {
981
0
    talloc_free(local);
982
0
    return NULL;
983
0
  }
984
985
0
  local->sockaddrlen = len;
986
987
0
  if (inet_ntop(AF_INET6, &local_addr->sin6_addr, addrstring, 
988
0
           sizeof(addrstring)) == NULL) {
989
0
    DEBUG(0, ("Unable to convert address to string: %s\n", 
990
0
        strerror(errno)));
991
0
    talloc_free(local);
992
0
    return NULL;
993
0
  }
994
  
995
0
  local->addr = talloc_strdup(local, addrstring);
996
0
  if (!local->addr) {
997
0
    talloc_free(local);
998
0
    return NULL;
999
0
  }
1000
0
  local->port = ntohs(local_addr->sin6_port);
1001
1002
0
  return local;
1003
0
}
1004
1005
static const struct socket_ops ipv6_tcp_ops = {
1006
  .name     = "ipv6",
1007
  .fn_init    = ipv6_init,
1008
  .fn_connect   = ipv6_tcp_connect,
1009
  .fn_connect_complete  = ip_connect_complete,
1010
  .fn_listen    = ipv6_listen,
1011
  .fn_accept    = ipv6_tcp_accept,
1012
  .fn_recv    = ip_recv,
1013
  .fn_recvfrom    = ipv6_recvfrom,
1014
  .fn_send    = ip_send,
1015
  .fn_sendto    = ipv6_sendto,
1016
  .fn_pending   = ip_pending,
1017
  .fn_close   = ip_close,
1018
1019
  .fn_set_option    = ipv6_set_option,
1020
1021
  .fn_get_peer_name = ipv6_tcp_get_peer_name,
1022
  .fn_get_peer_addr = ipv6_tcp_get_peer_addr,
1023
  .fn_get_my_addr   = ipv6_tcp_get_my_addr,
1024
1025
  .fn_get_fd    = ip_get_fd
1026
};
1027
1028
_PUBLIC_ const struct socket_ops *socket_ipv6_ops(enum socket_type type)
1029
0
{
1030
0
  return &ipv6_tcp_ops;
1031
0
}
1032
1033
#endif