1// 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
5package ipv4
6
7import (
8	"net"
9
10	"golang.org/x/net/bpf"
11)
12
13// MulticastTTL returns the time-to-live field value for outgoing
14// multicast packets.
15func (c *dgramOpt) MulticastTTL() (int, error) {
16	if !c.ok() {
17		return 0, errInvalidConn
18	}
19	so, ok := sockOpts[ssoMulticastTTL]
20	if !ok {
21		return 0, errNotImplemented
22	}
23	return so.GetInt(c.Conn)
24}
25
26// SetMulticastTTL sets the time-to-live field value for future
27// outgoing multicast packets.
28func (c *dgramOpt) SetMulticastTTL(ttl int) error {
29	if !c.ok() {
30		return errInvalidConn
31	}
32	so, ok := sockOpts[ssoMulticastTTL]
33	if !ok {
34		return errNotImplemented
35	}
36	return so.SetInt(c.Conn, ttl)
37}
38
39// MulticastInterface returns the default interface for multicast
40// packet transmissions.
41func (c *dgramOpt) MulticastInterface() (*net.Interface, error) {
42	if !c.ok() {
43		return nil, errInvalidConn
44	}
45	so, ok := sockOpts[ssoMulticastInterface]
46	if !ok {
47		return nil, errNotImplemented
48	}
49	return so.getMulticastInterface(c.Conn)
50}
51
52// SetMulticastInterface sets the default interface for future
53// multicast packet transmissions.
54func (c *dgramOpt) SetMulticastInterface(ifi *net.Interface) error {
55	if !c.ok() {
56		return errInvalidConn
57	}
58	so, ok := sockOpts[ssoMulticastInterface]
59	if !ok {
60		return errNotImplemented
61	}
62	return so.setMulticastInterface(c.Conn, ifi)
63}
64
65// MulticastLoopback reports whether transmitted multicast packets
66// should be copied and send back to the originator.
67func (c *dgramOpt) MulticastLoopback() (bool, error) {
68	if !c.ok() {
69		return false, errInvalidConn
70	}
71	so, ok := sockOpts[ssoMulticastLoopback]
72	if !ok {
73		return false, errNotImplemented
74	}
75	on, err := so.GetInt(c.Conn)
76	if err != nil {
77		return false, err
78	}
79	return on == 1, nil
80}
81
82// SetMulticastLoopback sets whether transmitted multicast packets
83// should be copied and send back to the originator.
84func (c *dgramOpt) SetMulticastLoopback(on bool) error {
85	if !c.ok() {
86		return errInvalidConn
87	}
88	so, ok := sockOpts[ssoMulticastLoopback]
89	if !ok {
90		return errNotImplemented
91	}
92	return so.SetInt(c.Conn, boolint(on))
93}
94
95// JoinGroup joins the group address group on the interface ifi.
96// By default all sources that can cast data to group are accepted.
97// It's possible to mute and unmute data transmission from a specific
98// source by using ExcludeSourceSpecificGroup and
99// IncludeSourceSpecificGroup.
100// JoinGroup uses the system assigned multicast interface when ifi is
101// nil, although this is not recommended because the assignment
102// depends on platforms and sometimes it might require routing
103// configuration.
104func (c *dgramOpt) JoinGroup(ifi *net.Interface, group net.Addr) error {
105	if !c.ok() {
106		return errInvalidConn
107	}
108	so, ok := sockOpts[ssoJoinGroup]
109	if !ok {
110		return errNotImplemented
111	}
112	grp := netAddrToIP4(group)
113	if grp == nil {
114		return errMissingAddress
115	}
116	return so.setGroup(c.Conn, ifi, grp)
117}
118
119// LeaveGroup leaves the group address group on the interface ifi
120// regardless of whether the group is any-source group or
121// source-specific group.
122func (c *dgramOpt) LeaveGroup(ifi *net.Interface, group net.Addr) error {
123	if !c.ok() {
124		return errInvalidConn
125	}
126	so, ok := sockOpts[ssoLeaveGroup]
127	if !ok {
128		return errNotImplemented
129	}
130	grp := netAddrToIP4(group)
131	if grp == nil {
132		return errMissingAddress
133	}
134	return so.setGroup(c.Conn, ifi, grp)
135}
136
137// JoinSourceSpecificGroup joins the source-specific group comprising
138// group and source on the interface ifi.
139// JoinSourceSpecificGroup uses the system assigned multicast
140// interface when ifi is nil, although this is not recommended because
141// the assignment depends on platforms and sometimes it might require
142// routing configuration.
143func (c *dgramOpt) JoinSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
144	if !c.ok() {
145		return errInvalidConn
146	}
147	so, ok := sockOpts[ssoJoinSourceGroup]
148	if !ok {
149		return errNotImplemented
150	}
151	grp := netAddrToIP4(group)
152	if grp == nil {
153		return errMissingAddress
154	}
155	src := netAddrToIP4(source)
156	if src == nil {
157		return errMissingAddress
158	}
159	return so.setSourceGroup(c.Conn, ifi, grp, src)
160}
161
162// LeaveSourceSpecificGroup leaves the source-specific group on the
163// interface ifi.
164func (c *dgramOpt) LeaveSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
165	if !c.ok() {
166		return errInvalidConn
167	}
168	so, ok := sockOpts[ssoLeaveSourceGroup]
169	if !ok {
170		return errNotImplemented
171	}
172	grp := netAddrToIP4(group)
173	if grp == nil {
174		return errMissingAddress
175	}
176	src := netAddrToIP4(source)
177	if src == nil {
178		return errMissingAddress
179	}
180	return so.setSourceGroup(c.Conn, ifi, grp, src)
181}
182
183// ExcludeSourceSpecificGroup excludes the source-specific group from
184// the already joined any-source groups by JoinGroup on the interface
185// ifi.
186func (c *dgramOpt) ExcludeSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
187	if !c.ok() {
188		return errInvalidConn
189	}
190	so, ok := sockOpts[ssoBlockSourceGroup]
191	if !ok {
192		return errNotImplemented
193	}
194	grp := netAddrToIP4(group)
195	if grp == nil {
196		return errMissingAddress
197	}
198	src := netAddrToIP4(source)
199	if src == nil {
200		return errMissingAddress
201	}
202	return so.setSourceGroup(c.Conn, ifi, grp, src)
203}
204
205// IncludeSourceSpecificGroup includes the excluded source-specific
206// group by ExcludeSourceSpecificGroup again on the interface ifi.
207func (c *dgramOpt) IncludeSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
208	if !c.ok() {
209		return errInvalidConn
210	}
211	so, ok := sockOpts[ssoUnblockSourceGroup]
212	if !ok {
213		return errNotImplemented
214	}
215	grp := netAddrToIP4(group)
216	if grp == nil {
217		return errMissingAddress
218	}
219	src := netAddrToIP4(source)
220	if src == nil {
221		return errMissingAddress
222	}
223	return so.setSourceGroup(c.Conn, ifi, grp, src)
224}
225
226// ICMPFilter returns an ICMP filter.
227// Currently only Linux supports this.
228func (c *dgramOpt) ICMPFilter() (*ICMPFilter, error) {
229	if !c.ok() {
230		return nil, errInvalidConn
231	}
232	so, ok := sockOpts[ssoICMPFilter]
233	if !ok {
234		return nil, errNotImplemented
235	}
236	return so.getICMPFilter(c.Conn)
237}
238
239// SetICMPFilter deploys the ICMP filter.
240// Currently only Linux supports this.
241func (c *dgramOpt) SetICMPFilter(f *ICMPFilter) error {
242	if !c.ok() {
243		return errInvalidConn
244	}
245	so, ok := sockOpts[ssoICMPFilter]
246	if !ok {
247		return errNotImplemented
248	}
249	return so.setICMPFilter(c.Conn, f)
250}
251
252// SetBPF attaches a BPF program to the connection.
253//
254// Only supported on Linux.
255func (c *dgramOpt) SetBPF(filter []bpf.RawInstruction) error {
256	if !c.ok() {
257		return errInvalidConn
258	}
259	so, ok := sockOpts[ssoAttachFilter]
260	if !ok {
261		return errNotImplemented
262	}
263	return so.setBPF(c.Conn, filter)
264}
265