MarcoLucidi01 / ytcast

cast YouTube videos to your smart TV from command-line

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

sendto: operation not permitted

thx1111 opened this issue · 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?

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

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.

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.

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".

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.