ytcast icon indicating copy to clipboard operation
ytcast copied to clipboard

sendto: operation not permitted

Open thx1111 opened this issue 1 year ago • 5 comments

Arch Linux linux 6.6.3.arch1-1 ytcast-bin 1.3.0-1 go 2:1.21.5-1

$ ytcast -s -verbose
13:08:42 ytcast.go:91: ytcast v1.3.0
13:08:42 ytcast.go:224: mkdir -p /home/james/.cache/ytcast
13:08:42 ytcast.go:233: loading cache /home/james/.cache/ytcast/ytcast.json
13:08:42 ssdp.go:70: M-SEARCH udp 239.255.255.250:1900 ST "urn:dial-multiscreen-org:service:dial:1" MX 3 timeout 4s
13:08:42 ytcast.go:253: saving cache /home/james/.cache/ytcast/ytcast.json
13:08:42 ytcast.go:94: Discover: write udp4 0.0.0.0:54096->239.255.255.250:1900: sendto: operation not permitted
ytcast: Discover: write udp4 0.0.0.0:54096->239.255.255.250:1900: sendto: operation not permitted
$ sudo ytcast -s -verbose
13:10:32 ytcast.go:91: ytcast v1.3.0
13:10:32 ytcast.go:224: mkdir -p /root/.cache/ytcast
13:10:32 ytcast.go:233: loading cache /root/.cache/ytcast/ytcast.json
13:10:32 ssdp.go:70: M-SEARCH udp 239.255.255.250:1900 ST "urn:dial-multiscreen-org:service:dial:1" MX 3 timeout 4s
13:10:32 ytcast.go:253: saving cache /root/.cache/ytcast/ytcast.json
13:10:32 ytcast.go:94: Discover: write udp4 0.0.0.0:46330->239.255.255.250:1900: sendto: operation not permitted
ytcast: Discover: write udp4 0.0.0.0:46330->239.255.255.250:1900: sendto: operation not permitted
$ java RokuDialDiscoverySample
*** sending ROKU m-search req
Exception in thread "main" java.net.SocketException: Operation not permitted
        at java.base/sun.nio.ch.DatagramChannelImpl.send0(Native Method)
        at java.base/sun.nio.ch.DatagramChannelImpl.sendFromNativeBuffer(DatagramChannelImpl.java:953)
        at java.base/sun.nio.ch.DatagramChannelImpl.send(DatagramChannelImpl.java:914)
        at java.base/sun.nio.ch.DatagramChannelImpl.send(DatagramChannelImpl.java:872)
        at java.base/sun.nio.ch.DatagramChannelImpl.blockingSend(DatagramChannelImpl.java:904)
        at java.base/sun.nio.ch.DatagramSocketAdaptor.send(DatagramSocketAdaptor.java:220)
        at java.base/java.net.DatagramSocket.send(DatagramSocket.java:662)
        at RokuDialDiscoverySample.discoverDevice(RokuDialDiscoverySample.java:57)
        at RokuDialDiscoverySample.main(RokuDialDiscoverySample.java:36)

Any suggestions? How does ytcast know which network interface to use?

thx1111 avatar Jan 01 '24 20:01 thx1111

hi, thank you for reporting this!

Any suggestions?

i've never seen this error before, but looks like some problem with the network/firewall, from a quick google search:

https://stackoverflow.com/questions/6240951/sendto-operation-not-permitted-netsnmp https://stackoverflow.com/questions/23859164/linux-udp-socket-sendto-operation-not-permitted

do you have any "particular" firewall/iptables config? what does syslog say when you try to run ytcast?

How does ytcast know which network interface to use?

ytcast uses the net.ListenUDP function to get a "connection" for ssdp m-search like this:

conn, err := net.ListenUDP("udp4", nil)

and from the docs:

func ListenUDP(network string, laddr *UDPAddr) (*UDPConn, error) ... If the IP field of laddr is nil or an unspecified IP address, ListenUDP listens on all available IP addresses of the local system except multicast IP addresses.

so i guess it binds on all available interfaces

MarcoLucidi01 avatar Jan 02 '24 12:01 MarcoLucidi01

If the IP field of laddr is nil or an unspecified IP address, ListenUDP listens on all available IP addresses of the local system except multicast IP addresses.

so i guess it binds on all available interfaces

That would be the problem. I configure nftables to block the 239.0.0.0/8 range on the WAN interface. Wikipedia summarizes:

The 239.0.0.0/8 range is assigned by RFC 2365 for private use within an organization. Per the RFC, packets destined to administratively scoped IPv4 multicast addresses do not cross administratively defined organizational boundaries ...

Might I suggest: https://pkg.go.dev/net#Interfaces and https://pkg.go.dev/net#Interface.Addrs, and a new ytcast option -i <string>, with "restrict ytcast to the specified network interface. if not specified, defaults to all network interfaces. the option can be specified more than once"? That would be backward compatible, and should avoid potential problems with hosts having multiple network interfaces and with hosts acting as routers. You can just select the first or last IP address associated with each network interface specified, or use nil if none is specified, and then still use net.ListenUDP.

thx1111 avatar Jan 02 '24 20:01 thx1111

a new ytcast option -i <string>, with "restrict ytcast to the specified network interface. if not specified, defaults to all network interfaces. the option can be specified more than once"? That would be backward compatible, and should avoid potential problems with hosts having multiple network interfaces and with hosts acting as routers.

yes allowing the user to specify the network interface to use seems a reasonable solution, but i'm not sure what would be the benefit of "specifying the option more than once"? i.e. i'm not sure if there is "simple" api to "bind to multiple selected addresses" and if it's worth it to implement such a feature.

You can just select the first or last IP address associated with each network interface specified, or use nil if none is specified, and then still use net.ListenUDP.

ok, i'll go with the first IP address, maybe in the future we could add some syntax to specify also the IP address of the interface to use, or we could do like curl does:

--interface <name>

Perform an operation using a specified interface. You can enter interface name, IP address or host name

also, it's not just the net.ListenUDP() call: if we implement such option, i expect that all connections made by ytcast (i.e. even http calls etc..) go through the provided network interface/address.

MarcoLucidi01 avatar Jan 05 '24 15:01 MarcoLucidi01

i'm not sure what would be the benefit of "specifying the option more than once"? i.e. i'm not sure if there is "simple" api to "bind to multiple selected addresses"

That would just be to accommodate some host with many different interfaces, each with different sub-networks. So only to be "completely configurable", but not a likely use case.

and if it's worth it to implement such a feature.

Ha! Only if it were easy. But, I suppose that would require iterating through every listed interface, for every operation.

Most likely, there is only ever going to be one interface using ytcast. And the original issue is avoiding sending on multiple interfaces, not how to send on multiple interfaces. And, I suppose that multiple instances of ytcast could be run, specifying different individual interfaces, if someone actually needed to do that.

So, yeah, just ignore that idea about "specified more than once".

thx1111 avatar Jan 05 '24 18:01 thx1111

hi @thx1111, i finally found the time to work on this!

the new version of ytcast (v1.4.0) adds the -i flag which allows to specify the local network interface (or ip address or hostname) that ytcast must use for network operations.

example passing a network interface name (ytcast will choose the first ip address of the interface):

$ ytcast -i wlp3s0 -s -verbose
21:52:50 ytcast.go:94: ytcast v1.4.0
...
21:52:50 ytcast.go:122: using local address 192.168.1.42 for network operations
21:52:50 ssdp.go:77: M-SEARCH udp 239.255.255.250:1900 ST "urn:dial-multiscreen-org:service:dial:1" MX 3 timeout 4s
...
21:52:54 ssdp.go:92: read udp4 192.168.1.42:56827: i/o timeout
...

or directly an ip address:

$ ytcast -i 192.168.1.42 -s -verbose
21:55:34 ytcast.go:94: ytcast v1.4.0
...
21:55:34 ytcast.go:119: 192.168.1.42: addrFromInterface: route ip+net: no such network interface
21:55:34 ytcast.go:122: using local address 192.168.1.42 for network operations
21:55:34 ssdp.go:77: M-SEARCH udp 239.255.255.250:1900 ST "urn:dial-multiscreen-org:service:dial:1" MX 3 timeout 4s
...
21:55:38 ssdp.go:92: read udp4 192.168.1.42:58277: i/o timeout
...

i hope that this solves your problems, if so, please close this issue, otherwise, feel free to report other things.

MarcoLucidi01 avatar Jan 28 '24 21:01 MarcoLucidi01

Sorry about the delay - other commitments.

Yes! That seems to do the magic. Thanks!

I do have one other suggestion to offer, to make using the "specify network interface" option easier to use, for anyone using ytcast for the first time. That is, whenever ytcast encounters the error,

13:32:55 ytcast.go:97: Discover: write udp4 0.0.0.0:41549->239.255.255.250:1900: sendto: operation not permitted

then, in addition to reporting the corresponding error message,

ytcast: Discover: write udp4 0.0.0.0:41549->239.255.255.250:1900: sendto: operation not permitted

ytcast should also output a second line, a "friendly suggestion," such as, "Do you need to ..." or "You may need to..." or simply "Try ...", as for instance:

Try specifying a local network interface with the '-i string' option

Otherwise, very likely, a new user is not going to immediately know how to respond to the sendto: operation not permitted error.

BTW, off on a tangent, to my surprise, a "TCL Roku TV" apparently knows how to do DIAL. I see it may take over 20 seconds for ytcast to receive a "screenId", but, with patience, it works! According to mDNS/DNS-SD/Zeroconf/"Rendezvous"/"Bonjour", this TCL Roku TV also knows '_spotify-connect._tcp' and '_airplay._tcp'.

thx1111 avatar Mar 25 '24 21:03 thx1111

glad to hear your issue is fixed and that it works on a "TCL Roku TV" too :)

as for the error "hint", while it could be a nice feature to have (not only for this specific error but in general), i don't want to "bloat" the code too much. also, this seems to be a rather "remote" case and i assume that if a user is skilled enough to tinker with his firewall, he can certainly do a google search for "ytcast sendto operation not permitted" and find this issue.

MarcoLucidi01 avatar Apr 03 '24 11:04 MarcoLucidi01

Thanks Marco

thx1111 avatar Apr 03 '24 19:04 thx1111