blob: 0388cba00c38c4cdd28d1cd3b6d6d537d95f6feb [file] [log] [blame]
David K. Bainbridge215e0242017-09-05 23:18:24 -07001// Copyright 2012 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// +build darwin dragonfly freebsd netbsd openbsd solaris windows
6
7package ipv4
8
9import (
10 "net"
11 "unsafe"
12
13 "golang.org/x/net/internal/socket"
14)
15
16func (so *sockOpt) setIPMreq(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
17 mreq := ipMreq{Multiaddr: [4]byte{grp[0], grp[1], grp[2], grp[3]}}
18 if err := setIPMreqInterface(&mreq, ifi); err != nil {
19 return err
20 }
21 b := (*[sizeofIPMreq]byte)(unsafe.Pointer(&mreq))[:sizeofIPMreq]
22 return so.Set(c, b)
23}
24
25func (so *sockOpt) getMulticastIf(c *socket.Conn) (*net.Interface, error) {
26 var b [4]byte
27 if _, err := so.Get(c, b[:]); err != nil {
28 return nil, err
29 }
30 ifi, err := netIP4ToInterface(net.IPv4(b[0], b[1], b[2], b[3]))
31 if err != nil {
32 return nil, err
33 }
34 return ifi, nil
35}
36
37func (so *sockOpt) setMulticastIf(c *socket.Conn, ifi *net.Interface) error {
38 ip, err := netInterfaceToIP4(ifi)
39 if err != nil {
40 return err
41 }
42 var b [4]byte
43 copy(b[:], ip)
44 return so.Set(c, b[:])
45}
46
47func setIPMreqInterface(mreq *ipMreq, ifi *net.Interface) error {
48 if ifi == nil {
49 return nil
50 }
51 ifat, err := ifi.Addrs()
52 if err != nil {
53 return err
54 }
55 for _, ifa := range ifat {
56 switch ifa := ifa.(type) {
57 case *net.IPAddr:
58 if ip := ifa.IP.To4(); ip != nil {
59 copy(mreq.Interface[:], ip)
60 return nil
61 }
62 case *net.IPNet:
63 if ip := ifa.IP.To4(); ip != nil {
64 copy(mreq.Interface[:], ip)
65 return nil
66 }
67 }
68 }
69 return errNoSuchInterface
70}
71
72func netIP4ToInterface(ip net.IP) (*net.Interface, error) {
73 ift, err := net.Interfaces()
74 if err != nil {
75 return nil, err
76 }
77 for _, ifi := range ift {
78 ifat, err := ifi.Addrs()
79 if err != nil {
80 return nil, err
81 }
82 for _, ifa := range ifat {
83 switch ifa := ifa.(type) {
84 case *net.IPAddr:
85 if ip.Equal(ifa.IP) {
86 return &ifi, nil
87 }
88 case *net.IPNet:
89 if ip.Equal(ifa.IP) {
90 return &ifi, nil
91 }
92 }
93 }
94 }
95 return nil, errNoSuchInterface
96}
97
98func netInterfaceToIP4(ifi *net.Interface) (net.IP, error) {
99 if ifi == nil {
100 return net.IPv4zero.To4(), nil
101 }
102 ifat, err := ifi.Addrs()
103 if err != nil {
104 return nil, err
105 }
106 for _, ifa := range ifat {
107 switch ifa := ifa.(type) {
108 case *net.IPAddr:
109 if ip := ifa.IP.To4(); ip != nil {
110 return ip, nil
111 }
112 case *net.IPNet:
113 if ip := ifa.IP.To4(); ip != nil {
114 return ip, nil
115 }
116 }
117 }
118 return nil, errNoSuchInterface
119}