Задача заключается в том, чтобы связать сокет специально для адреса 1.0.0.2:520 (назначенный eth2), а затем прочитать многоадресные UDP-пакеты, адресованные 224.0.0.9:520.В Голанге, как получать многоадресные пакеты с сокетом, привязанным к определенному адресу/порту?
Я пытаюсь ниже код, основанный на https://godoc.org/golang.org/x/net/ipv4
К сожалению, результат этого debbuging сообщение никогда не достигается: log.Printf("udpReader: recv %d bytes from %s to %s on %s", n, cm.Src, cm.Dst, ifname)
Я знаю eth2 получает нужные пакеты, потому что у меня есть этот пакет снифер работает на это:
sudo tcpdump -n -i eth2
18:40:28.571456 IP 1.0.0.1.520 > 224.0.0.9.520: RIPv2, Request, length: 24
18:40:29.556503 IP 1.0.0.1.520 > 224.0.0.9.520: RIPv2, Response, length: 64
Это пример кода. Можете ли вы понять, почему это не работает?
package main
import (
"fmt"
"log"
"net"
"golang.org/x/net/ipv4"
)
func main() {
if err := interfaceAdd("eth2"); err != nil {
log.Printf("main: error: %v", err)
}
log.Printf("main: waiting forever")
<-make(chan int)
}
func interfaceAdd(s string) error {
iface, err1 := net.InterfaceByName(s)
if err1 != nil {
return err1
}
addrList, err2 := iface.Addrs()
if err2 != nil {
return err2
}
for _, a := range addrList {
addr, _, err3 := net.ParseCIDR(a.String())
if err3 != nil {
log.Printf("interfaceAdd: parse CIDR error for '%s' on '%s': %v", addr, s, err3)
continue
}
if err := join(iface, addr); err != nil {
log.Printf("interfaceAdd: join error for '%s' on '%s': %v", addr, s, err)
}
}
return nil
}
func join(iface *net.Interface, addr net.IP) error {
proto := "udp"
var a string
if addr.To4() == nil {
// IPv6
a = fmt.Sprintf("[%s]", addr.String())
} else {
// IPv4
a = addr.String()
}
hostPort := fmt.Sprintf("%s:520", a) // rip multicast port
// open socket (connection)
conn, err2 := net.ListenPacket(proto, hostPort)
if err2 != nil {
return fmt.Errorf("join: %s/%s listen error: %v", proto, hostPort, err2)
}
// join multicast address
pc := ipv4.NewPacketConn(conn)
if err := pc.JoinGroup(iface, &net.UDPAddr{IP: net.IPv4(224, 0, 0, 9)}); err != nil {
conn.Close()
return fmt.Errorf("join: join error: %v", err)
}
// request control messages
/*
if err := pc.SetControlMessage(ipv4.FlagTTL|ipv4.FlagSrc|ipv4.FlagDst|ipv4.FlagInterface, true); err != nil {
// warning only
log.Printf("join: control message flags error: %v", err)
}
*/
go udpReader(pc, iface.Name, addr.String())
return nil
}
func udpReader(c *ipv4.PacketConn, ifname, ifaddr string) {
log.Printf("udpReader: reading from '%s' on '%s'", ifaddr, ifname)
defer c.Close()
buf := make([]byte, 10000)
for {
n, cm, _, err := c.ReadFrom(buf)
if err != nil {
log.Printf("udpReader: ReadFrom: error %v", err)
break
}
// make a copy because we will overwrite buf
b := make([]byte, n)
copy(b, buf)
log.Printf("udpReader: recv %d bytes from %s to %s on %s", n, cm.Src, cm.Dst, ifname)
}
log.Printf("udpReader: exiting '%s'", ifname)
}
Выход:
2016/02/09 18:44:20 interfaceAdd: join error for 'fe80::a00:27ff:fe52:9575' on 'eth2': join: udp/[fe80::a00:27ff:fe52:9575]:520 listen error: listen udp [fe80::a00:27ff:fe52:9575]:520: bind: invalid argument
2016/02/09 18:44:20 main: waiting forever
2016/02/09 18:44:20 udpReader: reading from '1.0.0.2' on 'eth2'
Просто, чтобы сделать его Кристал ясно: Задача состоит в том, чтобы не связываться интерфейс, который прослушивает этот IP-адрес, но конкретно и положительно относится к самому IP-адресу? –
Задача состоит в получении пакетов, адресованных 224.0.0.9, но только на определенном интерфейсе. Связывание с IP-адресом - это механизм, который, я полагаю, должен использовать для достижения этой цели. – Everton
Nope. Определите интерфейс для привязки его IP-адресом, затем привяжите его и присоедините к группе многоадресной рассылки. –