// ReplyPacket creates a reply packet that a Server would send to a client. // It uses the req Packet param to copy across common/necessary fields to // associate the reply with the request. func informReplyPacket(req dhcp4.Packet, mt dhcp4.MessageType, serverID net.IP, options []dhcp4.Option) dhcp4.Packet { p := dhcp4.NewPacket(dhcp4.BootReply) p.SetXId(req.XId()) p.SetHType(req.HType()) p[2] = req.HLen() // dhcp4 library does not provide a setter p.SetFlags(req.Flags()) p.SetCIAddr(req.CIAddr()) p.SetCHAddr(req.CHAddr()) p.AddOption(dhcp4.OptionDHCPMessageType, []byte{byte(mt)}) p.AddOption(dhcp4.OptionServerIdentifier, []byte(serverID)) for _, o := range options { p.AddOption(o.Code, o.Value) } p.PadToMinSize() return p }
func main() { if len(os.Args) != 3 { panic("not enough args") } intf, err := net.InterfaceByName(os.Args[1]) if err != nil { panic(err) } containerID := os.Args[2] log.Infof("Requesting for container ID %q on interface %q", containerID, intf.Name) contPid := getContainerInfo(containerID) log.Infof("Container has PID %s", contPid) runtime.LockOSThread() f, err := os.Open(fmt.Sprintf("/proc/%s/ns/net", contPid)) if err != nil { panic(err) } if _, _, err := unix.RawSyscall(unix.SYS_SETNS, f.Fd(), syscall.CLONE_NEWNET, 0); err != 0 { panic(err) } link, err := netlink.LinkByName("eth0") if err != nil { panic(err) } chaddr := link.Attrs().HardwareAddr p := dhcp.RequestPacket(dhcp.Discover, chaddr, nil, []byte{1, 2, 3, 4}, true, []dhcp.Option{}) conn, err := net.ListenPacket("udp", ":68") if err != nil { panic(err) } ipc := ipv4.NewPacketConn(conn) ipc.SetControlMessage(ipv4.FlagInterface, true) to := &net.UDPAddr{ IP: net.IPv4(255, 255, 255, 255), Port: 67, } eth0, err := net.InterfaceByName("eth0") if err != nil { panic(err) } if _, err := ipc.WriteTo(p, &ipv4.ControlMessage{IfIndex: eth0.Index}, to); err != nil { panic(err) } newPacket := dhcp.NewPacket(dhcp.BootReply) for { _, cm, _, err := ipc.ReadFrom(newPacket) if err != nil { panic(err) } if cm != nil && cm.IfIndex == eth0.Index { log.Infof("Received reply: %q", newPacket.YIAddr().String()) break } } addr, err := netlink.ParseAddr(newPacket.YIAddr().String() + "/16") if err != nil { panic(err) } log.Infof("Setting interface eth0...") if err := netlink.AddrAdd(link, addr); err != nil { panic(err) } }