Skip to content

Commit e921011

Browse files
committed
x/net/ipv6: add sticky source-specific multicast socket options
LGTM=iant R=iant CC=golang-codereviews https://golang.org/cl/175010043
1 parent d6d144d commit e921011

9 files changed

+215
-8
lines changed

ipv6/sockopt.go

+6
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ const (
2020
ssoICMPFilter // icmp filter, RFC 2292 or 3542
2121
ssoJoinGroup // any-source multicast, RFC 3493
2222
ssoLeaveGroup // any-source multicast, RFC 3493
23+
ssoJoinSourceGroup // source-specific multicast
24+
ssoLeaveSourceGroup // source-specific multicast
25+
ssoBlockSourceGroup // any-source or source-specific multicast
26+
ssoUnblockSourceGroup // any-source or source-specific multicast
2327
ssoMax
2428
)
2529

@@ -30,6 +34,8 @@ const (
3034
ssoTypeICMPFilter
3135
ssoTypeMTUInfo
3236
ssoTypeIPMreq
37+
ssoTypeGroupReq
38+
ssoTypeGroupSourceReq
3339
)
3440

3541
// A sockOpt represents a binding for sticky socket option.

ipv6/sockopt_ssmreq_stub.go

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2014 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,!freebsd,!linux
6+
7+
package ipv6
8+
9+
import "net"
10+
11+
func setsockoptGroupReq(fd int, opt *sockOpt, ifi *net.Interface, grp net.IP) error {
12+
return errOpNoSupport
13+
}
14+
15+
func setsockoptGroupSourceReq(fd int, opt *sockOpt, ifi *net.Interface, grp, src net.IP) error {
16+
return errOpNoSupport
17+
}

ipv6/sockopt_ssmreq_unix.go

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright 2014 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 freebsd linux
6+
7+
package ipv6
8+
9+
import (
10+
"net"
11+
"os"
12+
"unsafe"
13+
)
14+
15+
func setsockoptGroupReq(fd int, opt *sockOpt, ifi *net.Interface, grp net.IP) error {
16+
var gr sysGroupReq
17+
if ifi != nil {
18+
gr.Interface = uint32(ifi.Index)
19+
}
20+
gr.setGroup(grp)
21+
return os.NewSyscallError("setsockopt", setsockopt(fd, opt.level, opt.name, unsafe.Pointer(&gr), sysSizeofGroupReq))
22+
}
23+
24+
func setsockoptGroupSourceReq(fd int, opt *sockOpt, ifi *net.Interface, grp, src net.IP) error {
25+
var gsr sysGroupSourceReq
26+
if ifi != nil {
27+
gsr.Interface = uint32(ifi.Index)
28+
}
29+
gsr.setSourceGroup(grp, src)
30+
return os.NewSyscallError("setsockopt", setsockopt(fd, opt.level, opt.name, unsafe.Pointer(&gsr), sysSizeofGroupSourceReq))
31+
}

ipv6/sockopt_unix.go

+16-2
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,22 @@ func getMTUInfo(fd int, opt *sockOpt) (*net.Interface, int, error) {
101101
}
102102

103103
func setGroup(fd int, opt *sockOpt, ifi *net.Interface, grp net.IP) error {
104-
if opt.name < 1 || opt.typ != ssoTypeIPMreq {
104+
if opt.name < 1 {
105105
return errOpNoSupport
106106
}
107-
return setsockoptIPMreq(fd, opt, ifi, grp)
107+
switch opt.typ {
108+
case ssoTypeIPMreq:
109+
return setsockoptIPMreq(fd, opt, ifi, grp)
110+
case ssoTypeGroupReq:
111+
return setsockoptGroupReq(fd, opt, ifi, grp)
112+
default:
113+
return errOpNoSupport
114+
}
115+
}
116+
117+
func setSourceGroup(fd int, opt *sockOpt, ifi *net.Interface, grp, src net.IP) error {
118+
if opt.name < 1 || opt.typ != ssoTypeGroupSourceReq {
119+
return errOpNoSupport
120+
}
121+
return setsockoptGroupSourceReq(fd, opt, ifi, grp, src)
108122
}

ipv6/sockopt_windows.go

+5
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,8 @@ func setGroup(fd syscall.Handle, opt *sockOpt, ifi *net.Interface, grp net.IP) e
7979
}
8080
return setsockoptIPMreq(fd, opt, ifi, grp)
8181
}
82+
83+
func setSourceGroup(fd syscall.Handle, opt *sockOpt, ifi *net.Interface, grp, src net.IP) error {
84+
// TODO(mikio): implement this
85+
return errOpNoSupport
86+
}

ipv6/sys_bsd.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5-
// +build dragonfly freebsd netbsd openbsd
5+
// +build dragonfly netbsd openbsd
66

77
package ipv6
88

ipv6/sys_darwin.go

+39-3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package ipv6
77
import (
88
"net"
99
"syscall"
10+
"unsafe"
1011

1112
"golang.org/x/net/internal/iana"
1213
)
@@ -47,10 +48,11 @@ func init() {
4748
continue
4849
}
4950
}
50-
// The IPV6_RECVPATHMTU and IPV6_PATHMTU options were
51-
// introduced in OS X 10.7 (Darwin 11.0.0).
51+
// The IP_PKTINFO and protocol-independent multicast API were
52+
// introduced in OS X 10.7 (Darwin 11.0.0). But it looks like
53+
// those features require OS X 10.8 (Darwin 12.0.0) and above.
5254
// See http://support.apple.com/kb/HT1633.
53-
if i > 2 || i == 2 && osver[0] >= '1' && osver[1] >= '1' {
55+
if i > 2 || i == 2 && osver[0] >= '1' && osver[1] >= '2' {
5456
ctlOpts[ctlTrafficClass].name = sysIPV6_TCLASS
5557
ctlOpts[ctlTrafficClass].length = 4
5658
ctlOpts[ctlTrafficClass].marshal = marshalTrafficClass
@@ -70,6 +72,22 @@ func init() {
7072
sockOpts[ssoPathMTU].level = iana.ProtocolIPv6
7173
sockOpts[ssoPathMTU].name = sysIPV6_PATHMTU
7274
sockOpts[ssoPathMTU].typ = ssoTypeMTUInfo
75+
sockOpts[ssoJoinGroup].name = sysMCAST_JOIN_GROUP
76+
sockOpts[ssoJoinGroup].typ = ssoTypeGroupReq
77+
sockOpts[ssoLeaveGroup].name = sysMCAST_LEAVE_GROUP
78+
sockOpts[ssoLeaveGroup].typ = ssoTypeGroupReq
79+
sockOpts[ssoJoinSourceGroup].level = iana.ProtocolIPv6
80+
sockOpts[ssoJoinSourceGroup].name = sysMCAST_JOIN_SOURCE_GROUP
81+
sockOpts[ssoJoinSourceGroup].typ = ssoTypeGroupSourceReq
82+
sockOpts[ssoLeaveSourceGroup].level = iana.ProtocolIPv6
83+
sockOpts[ssoLeaveSourceGroup].name = sysMCAST_LEAVE_SOURCE_GROUP
84+
sockOpts[ssoLeaveSourceGroup].typ = ssoTypeGroupSourceReq
85+
sockOpts[ssoBlockSourceGroup].level = iana.ProtocolIPv6
86+
sockOpts[ssoBlockSourceGroup].name = sysMCAST_BLOCK_SOURCE
87+
sockOpts[ssoBlockSourceGroup].typ = ssoTypeGroupSourceReq
88+
sockOpts[ssoUnblockSourceGroup].level = iana.ProtocolIPv6
89+
sockOpts[ssoUnblockSourceGroup].name = sysMCAST_UNBLOCK_SOURCE
90+
sockOpts[ssoUnblockSourceGroup].typ = ssoTypeGroupSourceReq
7391
}
7492
}
7593

@@ -87,3 +105,21 @@ func (pi *sysInet6Pktinfo) setIfindex(i int) {
87105
func (mreq *sysIPv6Mreq) setIfindex(i int) {
88106
mreq.Interface = uint32(i)
89107
}
108+
109+
func (gr *sysGroupReq) setGroup(grp net.IP) {
110+
sa := (*sysSockaddrInet6)(unsafe.Pointer(&gr.Pad_cgo_0[0]))
111+
sa.Len = sysSizeofSockaddrInet6
112+
sa.Family = syscall.AF_INET6
113+
copy(sa.Addr[:], grp)
114+
}
115+
116+
func (gsr *sysGroupSourceReq) setSourceGroup(grp, src net.IP) {
117+
sa := (*sysSockaddrInet6)(unsafe.Pointer(&gsr.Pad_cgo_0[0]))
118+
sa.Len = sysSizeofSockaddrInet6
119+
sa.Family = syscall.AF_INET6
120+
copy(sa.Addr[:], grp)
121+
sa = (*sysSockaddrInet6)(unsafe.Pointer(&gsr.Pad_cgo_1[0]))
122+
sa.Len = sysSizeofSockaddrInet6
123+
sa.Family = syscall.AF_INET6
124+
copy(sa.Addr[:], src)
125+
}

ipv6/sys_freebsd.go

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// Copyright 2013 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+
package ipv6
6+
7+
import (
8+
"net"
9+
"syscall"
10+
"unsafe"
11+
12+
"golang.org/x/net/internal/iana"
13+
)
14+
15+
type sysSockoptLen int32
16+
17+
var (
18+
ctlOpts = [ctlMax]ctlOpt{
19+
ctlTrafficClass: {sysIPV6_TCLASS, 4, marshalTrafficClass, parseTrafficClass},
20+
ctlHopLimit: {sysIPV6_HOPLIMIT, 4, marshalHopLimit, parseHopLimit},
21+
ctlPacketInfo: {sysIPV6_PKTINFO, sysSizeofInet6Pktinfo, marshalPacketInfo, parsePacketInfo},
22+
ctlNextHop: {sysIPV6_NEXTHOP, sysSizeofSockaddrInet6, marshalNextHop, parseNextHop},
23+
}
24+
25+
sockOpts = [ssoMax]sockOpt{
26+
ssoTrafficClass: {iana.ProtocolIPv6, sysIPV6_TCLASS, ssoTypeInt},
27+
ssoHopLimit: {iana.ProtocolIPv6, sysIPV6_UNICAST_HOPS, ssoTypeInt},
28+
ssoMulticastInterface: {iana.ProtocolIPv6, sysIPV6_MULTICAST_IF, ssoTypeInterface},
29+
ssoMulticastHopLimit: {iana.ProtocolIPv6, sysIPV6_MULTICAST_HOPS, ssoTypeInt},
30+
ssoMulticastLoopback: {iana.ProtocolIPv6, sysIPV6_MULTICAST_LOOP, ssoTypeInt},
31+
ssoReceiveTrafficClass: {iana.ProtocolIPv6, sysIPV6_RECVTCLASS, ssoTypeInt},
32+
ssoReceiveHopLimit: {iana.ProtocolIPv6, sysIPV6_RECVHOPLIMIT, ssoTypeInt},
33+
ssoReceivePacketInfo: {iana.ProtocolIPv6, sysIPV6_RECVPKTINFO, ssoTypeInt},
34+
ssoReceivePathMTU: {iana.ProtocolIPv6, sysIPV6_RECVPATHMTU, ssoTypeInt},
35+
ssoPathMTU: {iana.ProtocolIPv6, sysIPV6_PATHMTU, ssoTypeMTUInfo},
36+
ssoChecksum: {iana.ProtocolIPv6, sysIPV6_CHECKSUM, ssoTypeInt},
37+
ssoICMPFilter: {iana.ProtocolIPv6ICMP, sysICMP6_FILTER, ssoTypeICMPFilter},
38+
ssoJoinGroup: {iana.ProtocolIPv6, sysMCAST_JOIN_GROUP, ssoTypeGroupReq},
39+
ssoLeaveGroup: {iana.ProtocolIPv6, sysMCAST_LEAVE_GROUP, ssoTypeGroupReq},
40+
ssoJoinSourceGroup: {iana.ProtocolIPv6, sysMCAST_JOIN_SOURCE_GROUP, ssoTypeGroupSourceReq},
41+
ssoLeaveSourceGroup: {iana.ProtocolIPv6, sysMCAST_LEAVE_SOURCE_GROUP, ssoTypeGroupSourceReq},
42+
ssoBlockSourceGroup: {iana.ProtocolIPv6, sysMCAST_BLOCK_SOURCE, ssoTypeGroupSourceReq},
43+
ssoUnblockSourceGroup: {iana.ProtocolIPv6, sysMCAST_UNBLOCK_SOURCE, ssoTypeGroupSourceReq},
44+
}
45+
)
46+
47+
func (sa *sysSockaddrInet6) setSockaddr(ip net.IP, i int) {
48+
sa.Len = sysSizeofSockaddrInet6
49+
sa.Family = syscall.AF_INET6
50+
copy(sa.Addr[:], ip)
51+
sa.Scope_id = uint32(i)
52+
}
53+
54+
func (pi *sysInet6Pktinfo) setIfindex(i int) {
55+
pi.Ifindex = uint32(i)
56+
}
57+
58+
func (mreq *sysIPv6Mreq) setIfindex(i int) {
59+
mreq.Interface = uint32(i)
60+
}
61+
62+
func (gr *sysGroupReq) setGroup(grp net.IP) {
63+
sa := (*sysSockaddrInet6)(unsafe.Pointer(&gr.Group))
64+
sa.Len = sysSizeofSockaddrInet6
65+
sa.Family = syscall.AF_INET6
66+
copy(sa.Addr[:], grp)
67+
}
68+
69+
func (gsr *sysGroupSourceReq) setSourceGroup(grp, src net.IP) {
70+
sa := (*sysSockaddrInet6)(unsafe.Pointer(&gsr.Group))
71+
sa.Len = sysSizeofSockaddrInet6
72+
sa.Family = syscall.AF_INET6
73+
copy(sa.Addr[:], grp)
74+
sa = (*sysSockaddrInet6)(unsafe.Pointer(&gsr.Source))
75+
sa.Len = sysSizeofSockaddrInet6
76+
sa.Family = syscall.AF_INET6
77+
copy(sa.Addr[:], src)
78+
}

ipv6/sys_linux.go

+22-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package ipv6
77
import (
88
"net"
99
"syscall"
10+
"unsafe"
1011

1112
"golang.org/x/net/internal/iana"
1213
)
@@ -33,8 +34,12 @@ var (
3334
ssoPathMTU: {iana.ProtocolIPv6, sysIPV6_PATHMTU, ssoTypeMTUInfo},
3435
ssoChecksum: {iana.ProtocolReserved, sysIPV6_CHECKSUM, ssoTypeInt},
3536
ssoICMPFilter: {iana.ProtocolIPv6ICMP, sysICMPV6_FILTER, ssoTypeICMPFilter},
36-
ssoJoinGroup: {iana.ProtocolIPv6, sysIPV6_ADD_MEMBERSHIP, ssoTypeIPMreq},
37-
ssoLeaveGroup: {iana.ProtocolIPv6, sysIPV6_DROP_MEMBERSHIP, ssoTypeIPMreq},
37+
ssoJoinGroup: {iana.ProtocolIPv6, sysMCAST_JOIN_GROUP, ssoTypeGroupReq},
38+
ssoLeaveGroup: {iana.ProtocolIPv6, sysMCAST_LEAVE_GROUP, ssoTypeGroupReq},
39+
ssoJoinSourceGroup: {iana.ProtocolIPv6, sysMCAST_JOIN_SOURCE_GROUP, ssoTypeGroupSourceReq},
40+
ssoLeaveSourceGroup: {iana.ProtocolIPv6, sysMCAST_LEAVE_SOURCE_GROUP, ssoTypeGroupSourceReq},
41+
ssoBlockSourceGroup: {iana.ProtocolIPv6, sysMCAST_BLOCK_SOURCE, ssoTypeGroupSourceReq},
42+
ssoUnblockSourceGroup: {iana.ProtocolIPv6, sysMCAST_UNBLOCK_SOURCE, ssoTypeGroupSourceReq},
3843
}
3944
)
4045

@@ -51,3 +56,18 @@ func (pi *sysInet6Pktinfo) setIfindex(i int) {
5156
func (mreq *sysIPv6Mreq) setIfindex(i int) {
5257
mreq.Ifindex = int32(i)
5358
}
59+
60+
func (gr *sysGroupReq) setGroup(grp net.IP) {
61+
sa := (*sysSockaddrInet6)(unsafe.Pointer(&gr.Group))
62+
sa.Family = syscall.AF_INET6
63+
copy(sa.Addr[:], grp)
64+
}
65+
66+
func (gsr *sysGroupSourceReq) setSourceGroup(grp, src net.IP) {
67+
sa := (*sysSockaddrInet6)(unsafe.Pointer(&gsr.Group))
68+
sa.Family = syscall.AF_INET6
69+
copy(sa.Addr[:], grp)
70+
sa = (*sysSockaddrInet6)(unsafe.Pointer(&gsr.Source))
71+
sa.Family = syscall.AF_INET6
72+
copy(sa.Addr[:], src)
73+
}

0 commit comments

Comments
 (0)