mirror of
https://hubproxy.babadafafafafa.cn/https://github.com/yunionio/cloudpods.git
synced 2026-09-20 08:03:53 +08:00
fix: host no default routes due to empty ipv6 addr (#22870)
Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
This commit is contained in:
@@ -28,6 +28,7 @@ import (
|
||||
o "yunion.io/x/onecloud/pkg/baremetal/options"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/types"
|
||||
"yunion.io/x/onecloud/pkg/util/dhcp"
|
||||
"yunion.io/x/onecloud/pkg/util/netutils2"
|
||||
)
|
||||
|
||||
func GetNicDHCPConfig(
|
||||
@@ -46,10 +47,10 @@ func GetNicDHCPConfig(
|
||||
return nil, errors.Wrap(errors.ErrEmpty, "Nic no ip or ip6 address")
|
||||
}
|
||||
|
||||
routes4 := make([]dhcp.SRouteInfo, 0)
|
||||
routes6 := make([]dhcp.SRouteInfo, 0)
|
||||
routes4 := make([]netutils2.SRouteInfo, 0)
|
||||
routes6 := make([]netutils2.SRouteInfo, 0)
|
||||
for _, route := range n.Routes {
|
||||
routeInfo, err := dhcp.ParseRouteInfo([]string{route[0], route[1]})
|
||||
routeInfo, err := netutils2.ParseRouteInfo([]string{route[0], route[1]})
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Parse route %s error: %q", route, err)
|
||||
}
|
||||
@@ -62,17 +63,21 @@ func GetNicDHCPConfig(
|
||||
|
||||
if n.IsDefault == nil || *n.IsDefault {
|
||||
if n.Gateway != "" && !strings.HasPrefix(strings.ToLower(osName), "win") {
|
||||
routes4 = append(routes4, dhcp.SRouteInfo{
|
||||
Prefix: net.ParseIP("0.0.0.0"),
|
||||
PrefixLen: 0,
|
||||
Gateway: net.ParseIP(n.Gateway),
|
||||
routes4 = append(routes4, netutils2.SRouteInfo{
|
||||
SPrefixInfo: netutils2.SPrefixInfo{
|
||||
Prefix: net.ParseIP("0.0.0.0"),
|
||||
PrefixLen: 0,
|
||||
},
|
||||
Gateway: net.ParseIP(n.Gateway),
|
||||
})
|
||||
}
|
||||
if n.Gateway6 != "" {
|
||||
routes6 = append(routes6, dhcp.SRouteInfo{
|
||||
Prefix: net.ParseIP("::"),
|
||||
PrefixLen: 0,
|
||||
Gateway: net.ParseIP(n.Gateway6),
|
||||
routes6 = append(routes6, netutils2.SRouteInfo{
|
||||
SPrefixInfo: netutils2.SPrefixInfo{
|
||||
Prefix: net.ParseIP("::"),
|
||||
PrefixLen: 0,
|
||||
},
|
||||
Gateway: net.ParseIP(n.Gateway6),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,6 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/types"
|
||||
deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
|
||||
"yunion.io/x/onecloud/pkg/util/coreosutils"
|
||||
"yunion.io/x/onecloud/pkg/util/dhcp"
|
||||
"yunion.io/x/onecloud/pkg/util/fileutils2"
|
||||
"yunion.io/x/onecloud/pkg/util/fstabutils"
|
||||
"yunion.io/x/onecloud/pkg/util/netutils2"
|
||||
@@ -984,8 +983,8 @@ func (d *sDebianLikeRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics
|
||||
if nicDesc.Mtu > 0 {
|
||||
cmds.WriteString(fmt.Sprintf(" mtu %d\n", nicDesc.Mtu))
|
||||
}
|
||||
routes4 := make([]dhcp.SRouteInfo, 0)
|
||||
routes6 := make([]dhcp.SRouteInfo, 0)
|
||||
routes4 := make([]netutils2.SRouteInfo, 0)
|
||||
routes6 := make([]netutils2.SRouteInfo, 0)
|
||||
routes4, routes6 = netutils2.AddNicRoutes(routes4, routes6, nicDesc, mainIp, mainIp6, nicCnt)
|
||||
for _, r := range routes4 {
|
||||
cmds.WriteString(fmt.Sprintf(" up ip route add %s/%d via %s || true\n", r.Prefix, r.PrefixLen, r.Gateway))
|
||||
@@ -1483,8 +1482,8 @@ func (r *sRedhatLikeRootFs) deployNetworkingScripts(rootFs IDiskPartition, nics
|
||||
cmds.WriteString(nicDesc.Gateway)
|
||||
cmds.WriteString("\n")
|
||||
}
|
||||
routes4 := make([]dhcp.SRouteInfo, 0)
|
||||
routes6 := make([]dhcp.SRouteInfo, 0)
|
||||
routes4 := make([]netutils2.SRouteInfo, 0)
|
||||
routes6 := make([]netutils2.SRouteInfo, 0)
|
||||
routes4, routes6 = netutils2.AddNicRoutes(routes4, routes6, nicDesc, mainIp, mainIp6, nicCnt)
|
||||
var rtbl strings.Builder
|
||||
for _, r := range routes4 {
|
||||
@@ -1576,8 +1575,8 @@ func (r *sRedhatLikeRootFs) deployVlanNetworkingScripts(rootFs IDiskPartition, s
|
||||
cmds.WriteString(nicDesc.Gateway)
|
||||
cmds.WriteString("\n")
|
||||
}
|
||||
routes4 := make([]dhcp.SRouteInfo, 0)
|
||||
routes6 := make([]dhcp.SRouteInfo, 0)
|
||||
routes4 := make([]netutils2.SRouteInfo, 0)
|
||||
routes6 := make([]netutils2.SRouteInfo, 0)
|
||||
routes4, routes6 = netutils2.AddNicRoutes(routes4, routes6, nicDesc, mainIp, mainIp6, nicCnt)
|
||||
var rtbl strings.Builder
|
||||
for _, r := range routes4 {
|
||||
|
||||
@@ -20,7 +20,6 @@ import (
|
||||
"yunion.io/x/log"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/types"
|
||||
"yunion.io/x/onecloud/pkg/util/dhcp"
|
||||
"yunion.io/x/onecloud/pkg/util/netplan"
|
||||
"yunion.io/x/onecloud/pkg/util/netutils2"
|
||||
)
|
||||
@@ -126,8 +125,8 @@ func getNetplanEthernetConfig(nic *types.SServerNic, isBond bool, mainIp, mainIp
|
||||
}
|
||||
}
|
||||
|
||||
routeArrs4 := make([]dhcp.SRouteInfo, 0)
|
||||
routeArrs6 := make([]dhcp.SRouteInfo, 0)
|
||||
routeArrs4 := make([]netutils2.SRouteInfo, 0)
|
||||
routeArrs6 := make([]netutils2.SRouteInfo, 0)
|
||||
routeArrs4, routeArrs6 = netutils2.AddNicRoutes(routeArrs4, routeArrs6, nic, mainIp, mainIp6, nicCnt)
|
||||
|
||||
var routes []*netplan.Route
|
||||
|
||||
@@ -27,7 +27,6 @@ import (
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/types"
|
||||
deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
|
||||
"yunion.io/x/onecloud/pkg/util/dhcp"
|
||||
"yunion.io/x/onecloud/pkg/util/netutils2"
|
||||
)
|
||||
|
||||
@@ -106,22 +105,26 @@ func (r *sSuseLikeRootFs) deployVlanNetworkingScripts(rootFs IDiskPartition, scr
|
||||
cmds.WriteString(fmt.Sprintf("VLAN_ID=%d\n", nicDesc.Vlan))
|
||||
cmds.WriteString(fmt.Sprintf("ETHERDEVICE=%s\n", nicDesc.Name))
|
||||
|
||||
var routes4 = make([]dhcp.SRouteInfo, 0)
|
||||
var routes6 = make([]dhcp.SRouteInfo, 0)
|
||||
var routes4 = make([]netutils2.SRouteInfo, 0)
|
||||
var routes6 = make([]netutils2.SRouteInfo, 0)
|
||||
var dnsSrv []string
|
||||
routes4, routes6 = netutils2.AddNicRoutes(routes4, routes6, nicDesc, mainIp, mainIp6, nicCnt)
|
||||
if len(nicDesc.Gateway) > 0 && nicDesc.Ip == mainIp {
|
||||
routes4 = append(routes4, dhcp.SRouteInfo{
|
||||
Prefix: net.ParseIP("0.0.0.0"),
|
||||
PrefixLen: 0,
|
||||
Gateway: net.ParseIP(nicDesc.Gateway),
|
||||
routes4 = append(routes4, netutils2.SRouteInfo{
|
||||
SPrefixInfo: netutils2.SPrefixInfo{
|
||||
Prefix: net.ParseIP("0.0.0.0"),
|
||||
PrefixLen: 0,
|
||||
},
|
||||
Gateway: net.ParseIP(nicDesc.Gateway),
|
||||
})
|
||||
}
|
||||
if len(nicDesc.Gateway6) > 0 && nicDesc.Ip6 == mainIp6 {
|
||||
routes6 = append(routes6, dhcp.SRouteInfo{
|
||||
Prefix: net.ParseIP("::"),
|
||||
PrefixLen: 0,
|
||||
Gateway: net.ParseIP(nicDesc.Gateway6),
|
||||
routes6 = append(routes6, netutils2.SRouteInfo{
|
||||
SPrefixInfo: netutils2.SPrefixInfo{
|
||||
Prefix: net.ParseIP("::"),
|
||||
PrefixLen: 0,
|
||||
},
|
||||
Gateway: net.ParseIP(nicDesc.Gateway6),
|
||||
})
|
||||
}
|
||||
var rtbl strings.Builder
|
||||
@@ -232,21 +235,25 @@ func (r *sSuseLikeRootFs) deployNetworkingScripts(rootFs IDiskPartition, nics []
|
||||
cmds.WriteString(fmt.Sprintf("IPADDR_V6=%s/%d\n", nicDesc.Ip6, nicDesc.Masklen6))
|
||||
}
|
||||
|
||||
var routes4 = make([]dhcp.SRouteInfo, 0)
|
||||
var routes6 = make([]dhcp.SRouteInfo, 0)
|
||||
var routes4 = make([]netutils2.SRouteInfo, 0)
|
||||
var routes6 = make([]netutils2.SRouteInfo, 0)
|
||||
routes4, routes6 = netutils2.AddNicRoutes(routes4, routes6, nicDesc, mainIp, mainIp6, nicCnt)
|
||||
if len(nicDesc.Gateway) > 0 && nicDesc.Ip == mainIp {
|
||||
routes4 = append(routes4, dhcp.SRouteInfo{
|
||||
Prefix: net.ParseIP("0.0.0.0"),
|
||||
PrefixLen: 0,
|
||||
Gateway: net.ParseIP(nicDesc.Gateway),
|
||||
routes4 = append(routes4, netutils2.SRouteInfo{
|
||||
SPrefixInfo: netutils2.SPrefixInfo{
|
||||
Prefix: net.ParseIP("0.0.0.0"),
|
||||
PrefixLen: 0,
|
||||
},
|
||||
Gateway: net.ParseIP(nicDesc.Gateway),
|
||||
})
|
||||
}
|
||||
if len(nicDesc.Gateway6) > 0 && nicDesc.Ip6 == mainIp6 {
|
||||
routes6 = append(routes6, dhcp.SRouteInfo{
|
||||
Prefix: net.ParseIP("::"),
|
||||
PrefixLen: 0,
|
||||
Gateway: net.ParseIP(nicDesc.Gateway6),
|
||||
routes6 = append(routes6, netutils2.SRouteInfo{
|
||||
SPrefixInfo: netutils2.SPrefixInfo{
|
||||
Prefix: net.ParseIP("::"),
|
||||
PrefixLen: 0,
|
||||
},
|
||||
Gateway: net.ParseIP(nicDesc.Gateway6),
|
||||
})
|
||||
}
|
||||
var rtbl strings.Builder
|
||||
|
||||
@@ -31,7 +31,6 @@ import (
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/types"
|
||||
deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
|
||||
"yunion.io/x/onecloud/pkg/util/dhcp"
|
||||
"yunion.io/x/onecloud/pkg/util/fileutils2"
|
||||
"yunion.io/x/onecloud/pkg/util/netutils2"
|
||||
"yunion.io/x/onecloud/pkg/util/procutils"
|
||||
@@ -332,8 +331,8 @@ func (w *SWindowsRootFs) DeployNetworkingScripts(rootfs IDiskPartition, nics []*
|
||||
lines = append(lines, cfg)
|
||||
}
|
||||
}
|
||||
routes4 := []dhcp.SRouteInfo{}
|
||||
routes6 := []dhcp.SRouteInfo{}
|
||||
routes4 := []netutils2.SRouteInfo{}
|
||||
routes6 := []netutils2.SRouteInfo{}
|
||||
routes4, routes6 = netutils2.AddNicRoutes(routes4, routes6, snic, mainIp, mainIp6, len(nics))
|
||||
for _, r := range routes4 {
|
||||
lines = append(lines, fmt.Sprintf(` netsh interface ip add route %s/%d %s "%%%%b"`, r.Prefix, r.PrefixLen, r.Gateway.String()))
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
package hostman
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
execlient "yunion.io/x/executor/client"
|
||||
"yunion.io/x/log"
|
||||
|
||||
@@ -85,7 +87,9 @@ func (host *SHostService) RunService() {
|
||||
|
||||
hostInstance := hostinfo.Instance()
|
||||
if err := hostInstance.Init(app.GetContext()); err != nil {
|
||||
log.Fatalf("Host instance init error: %v", err)
|
||||
log.Errorf("Host instance init error: %s, wait 3 minutes to retry", err)
|
||||
time.Sleep(time.Minute * 3)
|
||||
log.Fatalf("Host instance init error: %s, reboot now", err)
|
||||
}
|
||||
|
||||
app_common.InitAuth(&options.HostOptions.CommonOptions, func() {
|
||||
|
||||
@@ -39,7 +39,7 @@ import (
|
||||
|
||||
type IBridgeDriver interface {
|
||||
MigrateSlaveConfigs(IBridgeDriver) error
|
||||
ConfirmToConfig() (bool, error)
|
||||
ConfirmToConfig() (bool, string, error)
|
||||
GetMac() string
|
||||
GetVlanId() int
|
||||
FetchConfig()
|
||||
@@ -318,10 +318,10 @@ func (d *SBaseBridgeDriver) MigrateSlaveConfigs(o IBridgeDriver) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *SBaseBridgeDriver) ConfirmToConfig() (bool, error) {
|
||||
func (d *SBaseBridgeDriver) ConfirmToConfig() (bool, string, error) {
|
||||
exist, err := d.drv.Exists()
|
||||
if err != nil {
|
||||
return false, err
|
||||
return false, "", err
|
||||
}
|
||||
if exist {
|
||||
d.bridge.FetchConfig2(d.ip, d.ip6)
|
||||
@@ -329,86 +329,82 @@ func (d *SBaseBridgeDriver) ConfirmToConfig() (bool, error) {
|
||||
if len(d.bridge.Addr) == 0 {
|
||||
log.Infof("bridge %s has no ip assignment initially", d.bridge)
|
||||
if len(d.inter.Addr) == 0 {
|
||||
return false, fmt.Errorf("Neither %s nor %s owner address %s",
|
||||
d.inter, d.bridge, d.ip)
|
||||
return false, "", fmt.Errorf("Neither %s nor %s owner address %s", d.inter, d.bridge, d.ip)
|
||||
}
|
||||
if d.inter.Addr != d.ip {
|
||||
return false, fmt.Errorf("%s!=%s, %s not same as config",
|
||||
d.ip, d.inter.Addr, d.inter)
|
||||
return false, "", fmt.Errorf("%s!=%s, %s not same as config", d.ip, d.inter.Addr, d.inter)
|
||||
}
|
||||
log.Infof("Bridge address is not configured")
|
||||
return false, nil
|
||||
return false, fmt.Sprintf("bridge %s address is empty, should be configured", d.bridge), nil
|
||||
} else {
|
||||
log.Infof("bridge %s already has ip %s", d.bridge, d.bridge.Addr)
|
||||
}
|
||||
if d.bridge.Addr != d.ip {
|
||||
return false, fmt.Errorf("%s IP %s!=%s, mismatch", d.bridge, d.bridge.Addr, d.ip)
|
||||
return false, "", fmt.Errorf("bridge %s IP %s is not expected IP %s, mismatch", d.bridge, d.bridge.Addr, d.ip)
|
||||
}
|
||||
} else {
|
||||
if d.inter != nil && len(d.inter.Addr) > 0 {
|
||||
return false, fmt.Errorf("%s should have no address", d.inter)
|
||||
return false, "", fmt.Errorf("interface %s should have no address", d.inter)
|
||||
}
|
||||
if len(d.bridge.Addr) == 0 {
|
||||
return false, nil
|
||||
return false, "", fmt.Errorf("bridge %s should have 169.254.0.0/16 address", d.bridge)
|
||||
}
|
||||
if !d.bridge.IsSecretInterface() {
|
||||
return false, fmt.Errorf("%s should have address in 169.254.0.0/16", d.bridge)
|
||||
return false, "", fmt.Errorf("%s should have address in 169.254.0.0/16", d.bridge)
|
||||
}
|
||||
}
|
||||
if len(d.ip6) > 0 {
|
||||
if len(d.bridge.Addr6) == 0 {
|
||||
log.Infof("bridge %s has no ipv6 assignment initially", d.bridge)
|
||||
if len(d.inter.Addr6) == 0 {
|
||||
return false, fmt.Errorf("Neither %s nor %s owner ipv6 address %s",
|
||||
d.inter, d.bridge, d.ip6)
|
||||
return false, "", fmt.Errorf("neither interface%s nor bridge %s owner ipv6 address %s", d.inter, d.bridge, d.ip6)
|
||||
}
|
||||
if d.inter.Addr6 != d.ip6 {
|
||||
return false, fmt.Errorf("%s!=%s, %s not same as config",
|
||||
d.ip6, d.inter.Addr6, d.inter)
|
||||
return false, "", fmt.Errorf("interface %s IP %s is not %s as configured", d.inter, d.inter.Addr6, d.ip6)
|
||||
}
|
||||
log.Infof("Bridge ipv6 address is not configured")
|
||||
return false, nil
|
||||
return false, fmt.Sprintf("bridge %s ipv6 address is empty, should be configured", d.bridge), nil
|
||||
} else {
|
||||
log.Infof("bridge %s already has ipv6 address %s", d.bridge, d.bridge.Addr6)
|
||||
}
|
||||
if d.bridge.Addr6 != d.ip6 {
|
||||
return false, fmt.Errorf("%s IP %s!=%s, mismatch", d.bridge, d.bridge.Addr6, d.ip6)
|
||||
return false, "", fmt.Errorf("%s IP %s!=%s, mismatch", d.bridge, d.bridge.Addr6, d.ip6)
|
||||
}
|
||||
} else {
|
||||
if d.inter != nil && len(d.inter.Addr6) > 0 {
|
||||
return false, fmt.Errorf("%s should have no ipv6 address", d.inter)
|
||||
return false, "", fmt.Errorf("interface %s should have no ipv6 address", d.inter)
|
||||
}
|
||||
if len(d.bridge.Addr6) == 0 {
|
||||
return false, nil
|
||||
if len(d.bridge.Addr6) != 0 {
|
||||
return false, "", fmt.Errorf("bridge %s (%s) shoud have no ipv6 address", d.bridge, d.bridge.Addr6)
|
||||
}
|
||||
if !d.bridge.IsSecretInterface6() {
|
||||
return false, fmt.Errorf("%s(%s,%s) should have link local address in fe80::/10", d.bridge, d.bridge.Addr6, d.bridge.Addr6LinkLocal)
|
||||
return false, "", fmt.Errorf("bridge %s(%s,%s) should have link local address in fe80::/10", d.bridge, d.bridge.Addr6, d.bridge.Addr6LinkLocal)
|
||||
}
|
||||
}
|
||||
infs, err := d.drv.Interfaces()
|
||||
if err != nil {
|
||||
return false, err
|
||||
return false, "", fmt.Errorf("get all interfaces of bridge %s failed: %s", d.bridge, err)
|
||||
}
|
||||
if d.inter != nil && !utils.IsInStringArray(d.inter.String(), infs) {
|
||||
log.Infof("Interface %s not in bridge...", d.inter)
|
||||
return false, nil
|
||||
return false, fmt.Sprintf("interface %s not in bridge %s", d.inter, d.bridge), nil
|
||||
}
|
||||
if err := d.BringupInterface(); err != nil {
|
||||
log.Errorln(err)
|
||||
return false, err
|
||||
return false, "", fmt.Errorf("bring up bridge %s failed: %s", d.bridge, err)
|
||||
}
|
||||
return true, nil
|
||||
return true, "", nil
|
||||
} else {
|
||||
if d.bridge.FetchInter() != nil {
|
||||
return false, fmt.Errorf("Bridge %s exists, but not created by this driver????", d.bridge)
|
||||
return false, "", fmt.Errorf("bridge %s exists, but not created by this driver????", d.bridge)
|
||||
}
|
||||
if len(d.ip) > 0 && (d.inter == nil || len(d.inter.Addr) == 0) {
|
||||
return false, fmt.Errorf("Interface %s not configured", d.inter)
|
||||
return false, "", fmt.Errorf("interface %s not configured", d.inter)
|
||||
}
|
||||
if len(d.ip6) > 0 && (d.inter == nil || len(d.inter.Addr6) == 0) {
|
||||
return false, fmt.Errorf("Interface %s ipv6 not configured", d.inter)
|
||||
return false, "", fmt.Errorf("interface %s ipv6 not configured", d.inter)
|
||||
}
|
||||
return false, nil
|
||||
return false, fmt.Sprintf("bridge %s does not exist", d.bridge), nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -420,17 +416,11 @@ func (d *SBaseBridgeDriver) SetupAddresses() error {
|
||||
if err := d.inter.Shutdown(); err != nil {
|
||||
return errors.Wrapf(err, "shutdown bridge %s slave ifname: %s", br, ifname)
|
||||
}
|
||||
for _, cmd := range [][]string{
|
||||
{"/sbin/ifdown", ifname},
|
||||
{"nmcli", "connection", "down", ifname},
|
||||
} {
|
||||
output, err := procutils.NewRemoteCommandAsFarAsPossible(cmd[0], cmd[1:]...).Output()
|
||||
if err != nil {
|
||||
log.Errorf("run cmd: %s, output: %s, error: %s", strings.Join(cmd, " "), string(output), err)
|
||||
} else {
|
||||
log.Infof("run cmd: %s, output: %s", strings.Join(cmd, " "), string(output))
|
||||
break
|
||||
}
|
||||
// ensure the device is not managed by NetworkManager
|
||||
// nmcli dev set <interface_name> managed no
|
||||
output, err := procutils.NewRemoteCommandAsFarAsPossible("nmcli", "dev", "set", ifname, "managed", "no").Output()
|
||||
if err != nil {
|
||||
log.Errorf("run cmd: nmcli dev set %s managed no, output: %s, error: %s", ifname, string(output), err)
|
||||
}
|
||||
}
|
||||
{
|
||||
@@ -466,8 +456,9 @@ func (d *SBaseBridgeDriver) SetupAddresses() error {
|
||||
return errors.Wrapf(err, "setting bridge %s up", br)
|
||||
}
|
||||
if d.inter != nil {
|
||||
ifname := d.inter.String()
|
||||
// bring up the origin interface
|
||||
ethLink := iproute2.NewLink(d.inter.String()).Up()
|
||||
ethLink := iproute2.NewLink(ifname).Up()
|
||||
if options.HostOptions.TunnelPaddingBytes > 0 {
|
||||
mtu := 1500 + int(options.HostOptions.TunnelPaddingBytes)
|
||||
ethLink.MTU(mtu)
|
||||
@@ -475,6 +466,9 @@ func (d *SBaseBridgeDriver) SetupAddresses() error {
|
||||
if err := ethLink.Err(); err != nil {
|
||||
return errors.Wrapf(err, "setting origin interface %s up", d.inter.String())
|
||||
}
|
||||
if err := iproute2.NewAddress(ifname).Exact().Err(); err != nil {
|
||||
return errors.Wrapf(err, "clear interface %s address", ifname)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -591,14 +585,13 @@ func (d *SBaseBridgeDriver) Setup(o IBridgeDriver) error {
|
||||
// sleep 1 second to wait for bridge setup
|
||||
time.Sleep(1 * time.Second)
|
||||
// to setup default routes
|
||||
|
||||
if len(d.ip) > 0 || len(d.ip6) > 0 {
|
||||
setupRoutes := make([]iproute2.RouteSpec, 0)
|
||||
{
|
||||
for i := range routes {
|
||||
find := false
|
||||
if !find {
|
||||
if routes[i].Dst.String() == addr2Prefix(d.ip, d.maskLen) || routes[i].Dst.String() == addr2Prefix(d.ip6, d.mask6Len) {
|
||||
if (len(d.ip) > 0 && routes[i].Dst.String() == addr2Prefix(d.ip, d.maskLen)) || (len(d.ip6) > 0 && routes[i].Dst.String() == addr2Prefix(d.ip6, d.mask6Len)) {
|
||||
find = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,9 +70,8 @@ func (r *SDHCP6Relay) ServeDHCP(pkt dhcp.Packet, cliMac net.HardwareAddr, addr *
|
||||
return pkg, nil, err
|
||||
}
|
||||
|
||||
func (r *SDHCP6Relay) ServeRA(pkt dhcp.Packet, cliMac net.HardwareAddr, addr *net.UDPAddr) (dhcp.Packet, net.IP, net.HardwareAddr, error) {
|
||||
pkg, err := r.serveDHCPInternal(pkt, addr)
|
||||
return pkg, nil, nil, err
|
||||
func (r *SDHCP6Relay) OnRecvICMP6(pkt dhcp.Packet, cliMac net.HardwareAddr, addr *net.UDPAddr) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *SDHCP6Relay) serveDHCPInternal(pkt dhcp.Packet, _ *net.UDPAddr) (dhcp.Packet, error) {
|
||||
|
||||
@@ -221,8 +221,8 @@ func getGuestConfig(
|
||||
mainIp6 = mainNic6.Ip6
|
||||
}
|
||||
|
||||
route4 := make([]dhcp.SRouteInfo, 0)
|
||||
route6 := make([]dhcp.SRouteInfo, 0)
|
||||
route4 := make([]netutils2.SRouteInfo, 0)
|
||||
route6 := make([]netutils2.SRouteInfo, 0)
|
||||
if nicdesc.IsDefault {
|
||||
osName := guestDesc.OsName
|
||||
if len(osName) == 0 {
|
||||
@@ -233,10 +233,12 @@ func getGuestConfig(
|
||||
conf.Gateway = net.ParseIP(nicdesc.Gateway)
|
||||
|
||||
if !strings.HasPrefix(strings.ToLower(osName), "win") {
|
||||
route4 = append(route4, dhcp.SRouteInfo{
|
||||
Prefix: net.ParseIP("0.0.0.0"),
|
||||
PrefixLen: 0,
|
||||
Gateway: net.ParseIP(nicdesc.Gateway),
|
||||
route4 = append(route4, netutils2.SRouteInfo{
|
||||
SPrefixInfo: netutils2.SPrefixInfo{
|
||||
Prefix: net.ParseIP("0.0.0.0"),
|
||||
PrefixLen: 0,
|
||||
},
|
||||
Gateway: net.ParseIP(nicdesc.Gateway),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -244,10 +246,12 @@ func getGuestConfig(
|
||||
if len(nicdesc.Gateway6) > 0 {
|
||||
conf.Gateway6 = net.ParseIP(nicdesc.Gateway6)
|
||||
conf.PrefixLen6 = uint8(nicdesc.Masklen6)
|
||||
route6 = append(route6, dhcp.SRouteInfo{
|
||||
Prefix: net.ParseIP("::"),
|
||||
PrefixLen: 0,
|
||||
Gateway: net.ParseIP(nicdesc.Gateway6),
|
||||
route6 = append(route6, netutils2.SRouteInfo{
|
||||
SPrefixInfo: netutils2.SPrefixInfo{
|
||||
Prefix: net.ParseIP("::"),
|
||||
PrefixLen: 0,
|
||||
},
|
||||
Gateway: net.ParseIP(nicdesc.Gateway6),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,13 +113,9 @@ func (s *SGuestDHCP6Server) ServeDHCP(pkt dhcp.Packet, cliMac net.HardwareAddr,
|
||||
return pkg, nil, err
|
||||
}
|
||||
|
||||
func (s *SGuestDHCP6Server) ServeRA(pkt dhcp.Packet, cliMac net.HardwareAddr, addr *net.UDPAddr) (dhcp.Packet, net.IP, net.HardwareAddr, error) {
|
||||
func (s *SGuestDHCP6Server) OnRecvICMP6(pkt dhcp.Packet, cliMac net.HardwareAddr, addr *net.UDPAddr) error {
|
||||
log.Infof("SGuestDHCP6Server ServeRA from %s", cliMac.String())
|
||||
var conf = s.getConfig(cliMac, nil)
|
||||
if conf != nil {
|
||||
return dhcp.MakeRouterAdverPacket(conf.Gateway6, conf.PrefixLen6, conf.Routes6, uint32(conf.MTU))
|
||||
}
|
||||
return nil, nil, nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SGuestDHCP6Server) serveDHCPInternal(pkt dhcp.Packet, cliMac net.HardwareAddr, addr *net.UDPAddr) (dhcp.Packet, error) {
|
||||
|
||||
@@ -329,12 +329,12 @@ func NewNIC(desc string) (*SNIC, error) {
|
||||
return nil, errors.Wrapf(err, "hostbridge.NewDriver driver: %s, bridge: %s, interface: %s, ip: %s/%d, ip6: %s/%d", options.HostOptions.BridgeDriver, nic.Bridge, nic.Inter, nic.Ip, nic.Mask, nic.Ip6, nic.Mask6)
|
||||
}
|
||||
|
||||
confirm, err := nic.BridgeDev.ConfirmToConfig()
|
||||
confirm, msg, err := nic.BridgeDev.ConfirmToConfig()
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "nic.BridgeDev.ConfirmToConfig %#v", nic.BridgeDev)
|
||||
}
|
||||
if !confirm {
|
||||
log.Infof("Not confirm to configuration")
|
||||
log.Infof("Not confirm to configuration, bridge %s reason: %s", nic.Bridge, msg)
|
||||
if err = nic.BridgeDev.Setup(nic.BridgeDev); err != nil {
|
||||
return nil, errors.Wrapf(err, "nic.BridgeDev.Setup %v", nic.BridgeDev)
|
||||
}
|
||||
|
||||
@@ -71,12 +71,13 @@ const (
|
||||
type conn interface {
|
||||
io.Closer
|
||||
Send(b []byte, addr *net.UDPAddr, destMac net.HardwareAddr) error
|
||||
Recv(b []byte) ([]byte, *net.UDPAddr, net.HardwareAddr, int, error)
|
||||
Recv(b []byte) ([]byte, *net.UDPAddr, net.HardwareAddr, error)
|
||||
Send6(b []byte, addr *net.UDPAddr, destMac net.HardwareAddr) error
|
||||
SendICMP6(b []byte, srcIp net.IP, srcMac, destMac net.HardwareAddr) error
|
||||
Recv6(b []byte) ([]byte, *net.UDPAddr, net.HardwareAddr, int, error)
|
||||
Recv6(b []byte) ([]byte, *net.UDPAddr, net.HardwareAddr, error)
|
||||
SetReadDeadline(t time.Time) error
|
||||
SetWriteDeadline(t time.Time) error
|
||||
|
||||
SendRaw(b []byte, destMac net.HardwareAddr) error
|
||||
}
|
||||
|
||||
// Conn is a DHCP-oriented packet socket.
|
||||
@@ -171,7 +172,7 @@ func (c *Conn) Close() error {
|
||||
// packet and the interface it was received on.
|
||||
func (c *Conn) RecvDHCP() (Packet, *net.UDPAddr, net.HardwareAddr, error) {
|
||||
var buf [1500]byte
|
||||
b, addr, mac, _, err := c.conn.Recv(buf[:])
|
||||
b, addr, mac, err := c.conn.Recv(buf[:])
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
@@ -181,7 +182,7 @@ func (c *Conn) RecvDHCP() (Packet, *net.UDPAddr, net.HardwareAddr, error) {
|
||||
|
||||
func (c *Conn) RecvDHCP6() (Packet, *net.UDPAddr, net.HardwareAddr, error) {
|
||||
var buf [1500]byte
|
||||
b, addr, mac, _, err := c.conn.Recv6(buf[:])
|
||||
b, addr, mac, err := c.conn.Recv6(buf[:])
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
@@ -214,9 +215,9 @@ func (c *Conn) SendDHCP6(pkt Packet, addr *net.UDPAddr, mac net.HardwareAddr) er
|
||||
return c.conn.Send6(b, addr, mac)
|
||||
}
|
||||
|
||||
func (c *Conn) SendICMP6(pkt Packet, srcIp net.IP, srcmac, dstmac net.HardwareAddr) error {
|
||||
func (c *Conn) SendRaw(pkt Packet, dstmac net.HardwareAddr) error {
|
||||
b := pkt.Marshal()
|
||||
return c.conn.SendICMP6(b, srcIp, srcmac, dstmac)
|
||||
return c.conn.SendRaw(b, dstmac)
|
||||
}
|
||||
|
||||
// SetReadDeadline sets the deadline for future Read calls. If the
|
||||
@@ -303,13 +304,13 @@ func (s *socketConn) Close() error {
|
||||
return syscall.Close(s.sock)
|
||||
}
|
||||
|
||||
func (s *socketConn) Recv(b []byte) ([]byte, *net.UDPAddr, net.HardwareAddr, int, error) {
|
||||
func (s *socketConn) Recv(b []byte) ([]byte, *net.UDPAddr, net.HardwareAddr, error) {
|
||||
n, a, err := syscall.Recvfrom(s.sock, b, 0)
|
||||
if err != nil {
|
||||
return nil, nil, nil, 0, err
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
if addr, ok := a.(*syscall.SockaddrInet4); !ok {
|
||||
return nil, nil, nil, 0, errors.Wrap(errors.ErrUnsupportedProtocol, "Recvfrom recevice address is not famliy Inet4")
|
||||
return nil, nil, nil, errors.Wrap(errors.ErrUnsupportedProtocol, "Recvfrom recevice address is not famliy Inet4")
|
||||
} else {
|
||||
ip := net.IP{addr.Addr[0], addr.Addr[1], addr.Addr[2], addr.Addr[3]}
|
||||
udpAddr := &net.UDPAddr{
|
||||
@@ -317,7 +318,7 @@ func (s *socketConn) Recv(b []byte) ([]byte, *net.UDPAddr, net.HardwareAddr, int
|
||||
Port: addr.Port,
|
||||
}
|
||||
// there is no interface index info
|
||||
return b[:n], udpAddr, nil, 0, nil
|
||||
return b[:n], udpAddr, nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -119,13 +119,13 @@ func newSocketConn6(addr net.IP, port int, disableBroadcast bool) (conn, error)
|
||||
return &socketConn{sock}, nil
|
||||
}
|
||||
|
||||
func (s *socketConn) Recv6(b []byte) ([]byte, *net.UDPAddr, net.HardwareAddr, int, error) {
|
||||
func (s *socketConn) Recv6(b []byte) ([]byte, *net.UDPAddr, net.HardwareAddr, error) {
|
||||
n, a, err := syscall.Recvfrom(s.sock, b, 0)
|
||||
if err != nil {
|
||||
return nil, nil, nil, 0, err
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
if addr, ok := a.(*syscall.SockaddrInet6); !ok {
|
||||
return nil, nil, nil, 0, errors.Wrap(errors.ErrUnsupportedProtocol, "Recvfrom recevice address is not famliy Inet6")
|
||||
return nil, nil, nil, errors.Wrap(errors.ErrUnsupportedProtocol, "Recvfrom recevice address is not famliy Inet6")
|
||||
} else {
|
||||
ip := net.IP(addr.Addr[:])
|
||||
udpAddr := &net.UDPAddr{
|
||||
@@ -133,7 +133,7 @@ func (s *socketConn) Recv6(b []byte) ([]byte, *net.UDPAddr, net.HardwareAddr, in
|
||||
Port: addr.Port,
|
||||
}
|
||||
// there is no interface index info
|
||||
return b[:n], udpAddr, nil, 0, nil
|
||||
return b[:n], udpAddr, nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,6 +147,6 @@ func (s *socketConn) Send6(b []byte, addr *net.UDPAddr, destMac net.HardwareAddr
|
||||
return syscall.Sendto(s.sock, b, 0, destAddr)
|
||||
}
|
||||
|
||||
func (s *socketConn) SendICMP6(b []byte, srcIp net.IP, srcMac, destMac net.HardwareAddr) error {
|
||||
func (s *socketConn) SendRaw(b []byte, destMac net.HardwareAddr) error {
|
||||
return errors.Wrap(errors.ErrNotImplemented, "SendICMP6 not implemented")
|
||||
}
|
||||
|
||||
@@ -87,11 +87,11 @@ func (s *rawSocketConn) Close() error {
|
||||
return s.conn.Close()
|
||||
}
|
||||
|
||||
func (s *rawSocketConn) Recv(b []byte) ([]byte, *net.UDPAddr, net.HardwareAddr, int, error) {
|
||||
func (s *rawSocketConn) Recv(b []byte) ([]byte, *net.UDPAddr, net.HardwareAddr, error) {
|
||||
// read packet
|
||||
n, addr, err := s.conn.ReadFrom(b)
|
||||
if err != nil {
|
||||
return nil, nil, nil, 0, errors.Wrap(err, "Read from errror")
|
||||
return nil, nil, nil, errors.Wrap(err, "Read from errror")
|
||||
}
|
||||
log.Debugf("rawSocketConn Recv %d bytes", n)
|
||||
|
||||
@@ -99,12 +99,12 @@ func (s *rawSocketConn) Recv(b []byte) ([]byte, *net.UDPAddr, net.HardwareAddr,
|
||||
|
||||
srcMac, err := net.ParseMAC(addr.String())
|
||||
if err != nil {
|
||||
return nil, nil, nil, 0, errors.Wrap(err, "Parse mac error")
|
||||
return nil, nil, nil, errors.Wrap(err, "Parse mac error")
|
||||
}
|
||||
|
||||
p := gopacket.NewPacket(b, layers.LayerTypeEthernet, gopacket.Default)
|
||||
if p.ErrorLayer() != nil {
|
||||
return nil, nil, nil, 0, errors.Wrap(p.ErrorLayer().Error(), "Failed to decode packet")
|
||||
return nil, nil, nil, errors.Wrap(p.ErrorLayer().Error(), "Failed to decode packet")
|
||||
}
|
||||
|
||||
var srcIp net.IP
|
||||
@@ -115,7 +115,7 @@ func (s *rawSocketConn) Recv(b []byte) ([]byte, *net.UDPAddr, net.HardwareAddr,
|
||||
ip4 := ipLayer.(*layers.IPv4)
|
||||
srcIp = ip4.SrcIP
|
||||
} else {
|
||||
return nil, nil, nil, 0, errors.Wrap(p.ErrorLayer().Error(), "Expect IP packet")
|
||||
return nil, nil, nil, errors.Wrap(p.ErrorLayer().Error(), "Expect IP packet")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ func (s *rawSocketConn) Recv(b []byte) ([]byte, *net.UDPAddr, net.HardwareAddr,
|
||||
udpInfo := udpLayer.(*layers.UDP)
|
||||
srcPort = uint16(udpInfo.SrcPort)
|
||||
} else {
|
||||
return nil, nil, nil, 0, errors.Wrap(p.ErrorLayer().Error(), "Expect UDP packet")
|
||||
return nil, nil, nil, errors.Wrap(p.ErrorLayer().Error(), "Expect UDP packet")
|
||||
}
|
||||
|
||||
dhcpLayer := p.Layer(layers.LayerTypeDHCPv4)
|
||||
@@ -134,11 +134,11 @@ func (s *rawSocketConn) Recv(b []byte) ([]byte, *net.UDPAddr, net.HardwareAddr,
|
||||
dhcp4 := dhcpLayer.(*layers.DHCPv4)
|
||||
sbf := gopacket.NewSerializeBuffer()
|
||||
if err := dhcp4.SerializeTo(sbf, gopacket.SerializeOptions{}); err != nil {
|
||||
return nil, nil, nil, 0, errors.Wrap(err, "Serialize dhcp packet error")
|
||||
return nil, nil, nil, errors.Wrap(err, "Serialize dhcp packet error")
|
||||
}
|
||||
return sbf.Bytes(), &net.UDPAddr{IP: srcIp, Port: int(srcPort)}, srcMac, 0, nil
|
||||
return sbf.Bytes(), &net.UDPAddr{IP: srcIp, Port: int(srcPort)}, srcMac, nil
|
||||
} else {
|
||||
return nil, nil, nil, 0, errors.Wrap(p.ErrorLayer().Error(), "Expect DHCP packet")
|
||||
return nil, nil, nil, errors.Wrap(p.ErrorLayer().Error(), "Expect DHCP packet")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -72,11 +72,11 @@ func newRawSocketConn6(iface string, filter []bpf.RawInstruction, serverPort uin
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *rawSocketConn) Recv6(b []byte) ([]byte, *net.UDPAddr, net.HardwareAddr, int, error) {
|
||||
func (s *rawSocketConn) Recv6(b []byte) ([]byte, *net.UDPAddr, net.HardwareAddr, error) {
|
||||
// read packet
|
||||
n, addr, err := s.conn.ReadFrom(b)
|
||||
if err != nil {
|
||||
return nil, nil, nil, 0, errors.Wrap(err, "Read from errror")
|
||||
return nil, nil, nil, errors.Wrap(err, "Read from errror")
|
||||
}
|
||||
log.Debugf("rawSocketConn Recv6 %d bytes from %s", n, addr.String())
|
||||
|
||||
@@ -84,12 +84,12 @@ func (s *rawSocketConn) Recv6(b []byte) ([]byte, *net.UDPAddr, net.HardwareAddr,
|
||||
|
||||
srcMac, err := net.ParseMAC(addr.String())
|
||||
if err != nil {
|
||||
return nil, nil, nil, 0, errors.Wrap(err, "Parse mac error")
|
||||
return nil, nil, nil, errors.Wrap(err, "Parse mac error")
|
||||
}
|
||||
|
||||
p := gopacket.NewPacket(b, layers.LayerTypeEthernet, gopacket.Default)
|
||||
if p.ErrorLayer() != nil {
|
||||
return nil, nil, nil, 0, errors.Wrap(p.ErrorLayer().Error(), "Failed to decode packet")
|
||||
return nil, nil, nil, errors.Wrap(p.ErrorLayer().Error(), "Failed to decode packet")
|
||||
}
|
||||
|
||||
var srcIp net.IP
|
||||
@@ -100,14 +100,14 @@ func (s *rawSocketConn) Recv6(b []byte) ([]byte, *net.UDPAddr, net.HardwareAddr,
|
||||
ip6 := ipLayer.(*layers.IPv6)
|
||||
srcIp = ip6.SrcIP
|
||||
} else {
|
||||
return nil, nil, nil, 0, errors.Wrap(p.ErrorLayer().Error(), "Expect IPv6 packet")
|
||||
return nil, nil, nil, errors.Wrap(p.ErrorLayer().Error(), "Expect IPv6 packet")
|
||||
}
|
||||
}
|
||||
|
||||
icmpLayer := p.Layer(layers.LayerTypeICMPv6)
|
||||
if icmpLayer != nil {
|
||||
log.Infof("rawSocketConn Recv6 icmpLayer %s", icmpLayer.LayerType())
|
||||
raLayer := p.Layer(layers.LayerTypeICMPv6RouterSolicitation)
|
||||
/*raLayer := p.Layer(layers.LayerTypeICMPv6RouterSolicitation)
|
||||
if raLayer != nil {
|
||||
// icmp6, ra solitation
|
||||
raPkt := raLayer.(*layers.ICMPv6RouterSolicitation)
|
||||
@@ -118,7 +118,8 @@ func (s *rawSocketConn) Recv6(b []byte) ([]byte, *net.UDPAddr, net.HardwareAddr,
|
||||
return sbf.Bytes(), &net.UDPAddr{IP: srcIp, Port: icmpRAFakePort}, srcMac, 0, nil
|
||||
} else {
|
||||
return nil, nil, nil, 0, errors.Wrap(p.ErrorLayer().Error(), "expect an ICMPv6 RA solitation packet")
|
||||
}
|
||||
}*/
|
||||
return b, &net.UDPAddr{IP: srcIp, Port: icmpRAFakePort}, srcMac, nil
|
||||
}
|
||||
|
||||
var srcPort uint16
|
||||
@@ -127,7 +128,7 @@ func (s *rawSocketConn) Recv6(b []byte) ([]byte, *net.UDPAddr, net.HardwareAddr,
|
||||
udpInfo := udpLayer.(*layers.UDP)
|
||||
srcPort = uint16(udpInfo.SrcPort)
|
||||
} else {
|
||||
return nil, nil, nil, 0, errors.Wrap(p.ErrorLayer().Error(), "expect UDP packet")
|
||||
return nil, nil, nil, errors.Wrap(p.ErrorLayer().Error(), "expect UDP packet")
|
||||
}
|
||||
|
||||
dhcpLayer := p.Layer(layers.LayerTypeDHCPv6)
|
||||
@@ -136,51 +137,17 @@ func (s *rawSocketConn) Recv6(b []byte) ([]byte, *net.UDPAddr, net.HardwareAddr,
|
||||
dhcp6 := dhcpLayer.(*layers.DHCPv6)
|
||||
sbf := gopacket.NewSerializeBuffer()
|
||||
if err := dhcp6.SerializeTo(sbf, gopacket.SerializeOptions{}); err != nil {
|
||||
return nil, nil, nil, 0, errors.Wrap(err, "Serialize dhcp6 packet error")
|
||||
return nil, nil, nil, errors.Wrap(err, "Serialize dhcp6 packet error")
|
||||
}
|
||||
return sbf.Bytes(), &net.UDPAddr{IP: srcIp, Port: int(srcPort)}, srcMac, 0, nil
|
||||
return sbf.Bytes(), &net.UDPAddr{IP: srcIp, Port: int(srcPort)}, srcMac, nil
|
||||
} else {
|
||||
return nil, nil, nil, 0, errors.Wrap(p.ErrorLayer().Error(), "Fetch dhcp layer failed")
|
||||
return nil, nil, nil, errors.Wrap(p.ErrorLayer().Error(), "Fetch dhcp layer failed")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *rawSocketConn) SendICMP6(b []byte, srcIP net.IP, srcMac, destMac net.HardwareAddr) error {
|
||||
var icmpRouterAdvMsg = new(layers.ICMPv6RouterAdvertisement)
|
||||
if err := icmpRouterAdvMsg.DecodeFromBytes(b, gopacket.NilDecodeFeedback); err != nil {
|
||||
return errors.Wrap(err, "Decode icmp router advertisement bytes error")
|
||||
}
|
||||
|
||||
var eth = &layers.Ethernet{
|
||||
EthernetType: layers.EthernetTypeIPv6,
|
||||
SrcMAC: s.iface.HardwareAddr,
|
||||
DstMAC: destMac,
|
||||
}
|
||||
|
||||
dstIP := net.ParseIP("ff02::1")
|
||||
|
||||
var ip = &layers.IPv6{
|
||||
Version: 6,
|
||||
HopLimit: 64,
|
||||
SrcIP: srcIP,
|
||||
DstIP: dstIP,
|
||||
NextHeader: layers.IPProtocolICMPv6,
|
||||
}
|
||||
|
||||
var icmp6 = &layers.ICMPv6{
|
||||
TypeCode: layers.CreateICMPv6TypeCode(layers.ICMPv6TypeRouterAdvertisement, 0),
|
||||
}
|
||||
icmp6.SetNetworkLayerForChecksum(ip)
|
||||
|
||||
var (
|
||||
buf = gopacket.NewSerializeBuffer()
|
||||
opts = gopacket.SerializeOptions{ComputeChecksums: true, FixLengths: true}
|
||||
)
|
||||
if err := gopacket.SerializeLayers(buf, opts, eth, ip, icmp6, icmpRouterAdvMsg); err != nil {
|
||||
return errors.Wrap(err, "SerializeLayers error")
|
||||
}
|
||||
|
||||
func (s *rawSocketConn) SendRaw(b []byte, destMac net.HardwareAddr) error {
|
||||
// s.conn.SetWriteDeadline(time.Now().Add(DefaultWriteTimeout)) // 2 second
|
||||
if _, err := s.conn.WriteTo(buf.Bytes(), &packet.Addr{HardwareAddr: destMac}); err != nil {
|
||||
if _, err := s.conn.WriteTo(b, &packet.Addr{HardwareAddr: destMac}); err != nil {
|
||||
return errors.Wrap(err, "Send icmp packet error")
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -22,7 +22,8 @@ import (
|
||||
"time"
|
||||
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/util/netutils2"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -39,24 +40,24 @@ type ResponseConfig struct {
|
||||
OsName string
|
||||
ServerIP net.IP // OptServerIdentifier 54
|
||||
ClientIP net.IP
|
||||
Gateway net.IP // OptRouters 3
|
||||
Domain string // OptDomainName 15
|
||||
LeaseTime time.Duration // OptLeaseTime 51
|
||||
RenewalTime time.Duration // OptRenewalTime 58
|
||||
BroadcastAddr net.IP // OptBroadcastAddr 28
|
||||
Hostname string // OptHostname 12
|
||||
SubnetMask net.IP // OptSubnetMask 1
|
||||
DNSServers []net.IP // OptDNSServers
|
||||
Routes []SRouteInfo // TODO: 249 for windows, 121 for linux
|
||||
NTPServers []net.IP // OptNTPServers 42
|
||||
MTU uint16 // OptMTU 26
|
||||
Gateway net.IP // OptRouters 3
|
||||
Domain string // OptDomainName 15
|
||||
LeaseTime time.Duration // OptLeaseTime 51
|
||||
RenewalTime time.Duration // OptRenewalTime 58
|
||||
BroadcastAddr net.IP // OptBroadcastAddr 28
|
||||
Hostname string // OptHostname 12
|
||||
SubnetMask net.IP // OptSubnetMask 1
|
||||
DNSServers []net.IP // OptDNSServers
|
||||
Routes []netutils2.SRouteInfo // TODO: 249 for windows, 121 for linux
|
||||
NTPServers []net.IP // OptNTPServers 42
|
||||
MTU uint16 // OptMTU 26
|
||||
|
||||
ClientIP6 net.IP
|
||||
Gateway6 net.IP
|
||||
PrefixLen6 uint8
|
||||
DNSServers6 []net.IP
|
||||
NTPServers6 []net.IP
|
||||
Routes6 []SRouteInfo
|
||||
Routes6 []netutils2.SRouteInfo
|
||||
|
||||
// Relay Info https://datatracker.ietf.org/doc/html/rfc3046
|
||||
RelayInfo []byte
|
||||
@@ -95,33 +96,7 @@ func GetOptTime(d time.Duration) []byte {
|
||||
return timeBytes
|
||||
}
|
||||
|
||||
type SRouteInfo struct {
|
||||
Prefix net.IP
|
||||
PrefixLen uint8
|
||||
Gateway net.IP
|
||||
}
|
||||
|
||||
func (r SRouteInfo) String() string {
|
||||
return fmt.Sprintf("%s/%d via %s", r.Prefix.String(), r.PrefixLen, r.Gateway.String())
|
||||
}
|
||||
|
||||
func ParseRouteInfo(route []string) (*SRouteInfo, error) {
|
||||
if len(route) < 2 {
|
||||
return nil, errors.Wrapf(errors.ErrInvalidStatus, "invalid route %#v", route)
|
||||
}
|
||||
_, prefixLen, err := net.ParseCIDR(route[0])
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "net.ParseCIDR %s", route[0])
|
||||
}
|
||||
ones, _ := prefixLen.Mask.Size()
|
||||
return &SRouteInfo{
|
||||
Prefix: prefixLen.IP,
|
||||
PrefixLen: uint8(ones),
|
||||
Gateway: net.ParseIP(route[1]),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func getClasslessRoutePack(route SRouteInfo) []byte {
|
||||
func getClasslessRoutePack(route netutils2.SRouteInfo) []byte {
|
||||
// var snet, gw = route[0], route[1]
|
||||
// tmp := strings.Split(snet, "/")
|
||||
netaddr := route.Prefix
|
||||
|
||||
@@ -16,8 +16,9 @@ package dhcp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/util/netutils2"
|
||||
)
|
||||
|
||||
func compareBytes(b1, b2 []byte) error {
|
||||
@@ -61,7 +62,7 @@ func TestGetClasslessRoutePack(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
routeInfo, err := ParseRouteInfo([]string{c.net, c.gw})
|
||||
routeInfo, err := netutils2.ParseRouteInfo([]string{c.net, c.gw})
|
||||
if err != nil {
|
||||
t.Errorf("parse route %s error: %v", c.net, err)
|
||||
continue
|
||||
@@ -72,58 +73,3 @@ func TestGetClasslessRoutePack(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseRouteInfo(t *testing.T) {
|
||||
cases := []struct {
|
||||
net string
|
||||
gw string
|
||||
want *SRouteInfo
|
||||
}{
|
||||
{
|
||||
net: "10.0.0.0/8",
|
||||
gw: "10.168.120.1",
|
||||
want: &SRouteInfo{
|
||||
Prefix: net.ParseIP("10.0.0.0"),
|
||||
PrefixLen: 8,
|
||||
Gateway: net.ParseIP("10.168.120.1"),
|
||||
},
|
||||
},
|
||||
{
|
||||
net: "::/0",
|
||||
gw: "3ffe:3200:fe::1",
|
||||
want: &SRouteInfo{
|
||||
Prefix: net.ParseIP("::"),
|
||||
PrefixLen: 0,
|
||||
Gateway: net.ParseIP("3ffe:3200:fe::1"),
|
||||
},
|
||||
},
|
||||
{
|
||||
net: "fd00:ec2::254/128",
|
||||
gw: "::",
|
||||
want: &SRouteInfo{
|
||||
Prefix: net.ParseIP("fd00:ec2::254"),
|
||||
PrefixLen: 128,
|
||||
Gateway: net.ParseIP("::"),
|
||||
},
|
||||
},
|
||||
{
|
||||
net: "fe80::a9fe:a9fe/128",
|
||||
gw: "::",
|
||||
want: &SRouteInfo{
|
||||
Prefix: net.ParseIP("fe80::a9fe:a9fe"),
|
||||
PrefixLen: 128,
|
||||
Gateway: net.ParseIP("::"),
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
routeInfo, err := ParseRouteInfo([]string{c.net, c.gw})
|
||||
if err != nil {
|
||||
t.Errorf("parse route %s error: %v", c.net, err)
|
||||
continue
|
||||
}
|
||||
if routeInfo.String() != c.want.String() {
|
||||
t.Errorf("parse route expect %s got: %s", c.want.String(), routeInfo.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,8 +22,13 @@ type DHCPHandler interface {
|
||||
ServeDHCP(pkt Packet, cliMac net.HardwareAddr, addr *net.UDPAddr) (Packet, []string, error)
|
||||
}
|
||||
|
||||
type SendPacket struct {
|
||||
Packet []byte
|
||||
DestMac net.HardwareAddr
|
||||
}
|
||||
|
||||
type DHCP6Handler interface {
|
||||
DHCPHandler
|
||||
|
||||
ServeRA(pkt Packet, cliMac net.HardwareAddr, addr *net.UDPAddr) (Packet, net.IP, net.HardwareAddr, error)
|
||||
OnRecvICMP6(pkt Packet, cliMac net.HardwareAddr, addr *net.UDPAddr) error
|
||||
}
|
||||
|
||||
@@ -16,207 +16,12 @@ package dhcp
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/layers"
|
||||
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
)
|
||||
|
||||
/*
|
||||
https://datatracker.ietf.org/doc/html/rfc4861#section-4.6.4
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Type | Length | Reserved |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| MTU |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
type icmpV6OptMtu struct {
|
||||
MTU uint32
|
||||
}
|
||||
|
||||
func (opt icmpV6OptMtu) Bytes() []byte {
|
||||
buf := make([]byte, 6)
|
||||
binary.BigEndian.PutUint32(buf[2:], opt.MTU)
|
||||
return buf
|
||||
}
|
||||
|
||||
func NewIcmpV6OptMtu(mtu uint32) icmpV6OptMtu {
|
||||
return icmpV6OptMtu{
|
||||
MTU: mtu,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
https://datatracker.ietf.org/doc/html/rfc4861#section-4.6.2
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Type | Length | Prefix Length |L|A| Reserved1 |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Valid Lifetime |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Preferred Lifetime |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Reserved2 |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| |
|
||||
+ +
|
||||
| |
|
||||
+ Prefix +
|
||||
| |
|
||||
+ +
|
||||
| |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
type icmpv6OptPrefixInfo struct {
|
||||
PrefixLen uint8
|
||||
Flag uint8
|
||||
ValidLifetime uint32
|
||||
PreferredLifetime uint32
|
||||
Reserved2 uint32
|
||||
Prefix []byte
|
||||
}
|
||||
|
||||
func (opt icmpv6OptPrefixInfo) Bytes() []byte {
|
||||
buf := make([]byte, 30)
|
||||
buf[0] = opt.PrefixLen
|
||||
buf[1] = opt.Flag
|
||||
binary.BigEndian.PutUint32(buf[2:], opt.ValidLifetime)
|
||||
binary.BigEndian.PutUint32(buf[6:], opt.PreferredLifetime)
|
||||
binary.BigEndian.PutUint32(buf[10:], opt.Reserved2)
|
||||
copy(buf[14:], opt.Prefix[:])
|
||||
return buf
|
||||
}
|
||||
|
||||
func NewIcmpv6OptPrefixInfo(gw net.IP, preflen uint8) icmpv6OptPrefixInfo {
|
||||
_, ipnet, _ := net.ParseCIDR(fmt.Sprintf("%s/%d", gw.String(), preflen))
|
||||
return icmpv6OptPrefixInfo{
|
||||
PrefixLen: preflen,
|
||||
Flag: 0x80,
|
||||
ValidLifetime: 0xffffffff,
|
||||
PreferredLifetime: 0xffffffff,
|
||||
Reserved2: 0,
|
||||
Prefix: ipnet.IP,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
https://datatracker.ietf.org/doc/html/rfc4861#section-4.6.1
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Type | Length | Link-Layer Address ...
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
type icmpv6OptSourceTargetAddress struct {
|
||||
Mac net.HardwareAddr
|
||||
}
|
||||
|
||||
func (opt icmpv6OptSourceTargetAddress) Bytes() []byte {
|
||||
return opt.Mac[0:6]
|
||||
}
|
||||
|
||||
func NewIcmpv6OptSourceTargetAddress(macAddr net.HardwareAddr) icmpv6OptSourceTargetAddress {
|
||||
return icmpv6OptSourceTargetAddress{
|
||||
Mac: macAddr,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
https://datatracker.ietf.org/doc/html/rfc4191#section-2.3
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Type | Length | Prefix Length |Resvd|Prf|Resvd|
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Route Lifetime |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Prefix (Variable Length) |
|
||||
. .
|
||||
. .
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
|
||||
type icmpv6OptRouteInfo struct {
|
||||
PrefixLen uint8
|
||||
Reserved1 uint8
|
||||
RouteLifetime uint32
|
||||
Prefix []byte
|
||||
}
|
||||
|
||||
func (opt icmpv6OptRouteInfo) Bytes() []byte {
|
||||
buf := make([]byte, 6)
|
||||
buf[0] = opt.PrefixLen
|
||||
buf[1] = opt.Reserved1
|
||||
binary.BigEndian.PutUint32(buf[2:6], opt.RouteLifetime)
|
||||
buf = append(buf, opt.Prefix...)
|
||||
return buf
|
||||
}
|
||||
|
||||
func NewIcmpv6OptRouteInfo(routeLifetime uint32, prefix []byte, prefixLen uint8) icmpv6OptRouteInfo {
|
||||
if prefixLen <= 0 {
|
||||
prefix = prefix[0:0]
|
||||
} else if prefixLen <= 64 {
|
||||
prefix = prefix[0:8]
|
||||
} else {
|
||||
prefix = prefix[0:16]
|
||||
}
|
||||
return icmpv6OptRouteInfo{
|
||||
PrefixLen: prefixLen,
|
||||
Reserved1: 0,
|
||||
RouteLifetime: routeLifetime,
|
||||
Prefix: prefix,
|
||||
}
|
||||
}
|
||||
|
||||
func MakeRouterAdverPacket(gwIP net.IP, prefixLen uint8, routes6 []SRouteInfo, mtu uint32) (Packet, net.IP, net.HardwareAddr, error) {
|
||||
pkt := layers.ICMPv6RouterAdvertisement{}
|
||||
// https://datatracker.ietf.org/doc/html/rfc4861#section-4.2
|
||||
// https://datatracker.ietf.org/doc/html/rfc4191
|
||||
pkt.Flags = 0xc0 // M=1, O=1, stateful DHCPv6, pref=00
|
||||
pkt.HopLimit = 64
|
||||
pkt.RouterLifetime = 9000
|
||||
pkt.ReachableTime = 0
|
||||
pkt.RetransTimer = 0
|
||||
|
||||
// gwMac, _ := net.ParseMAC("14:09:dc:cf:16:d5")
|
||||
|
||||
pkt.Options = layers.ICMPv6Options{
|
||||
/*layers.ICMPv6Option{
|
||||
Type: layers.ICMPv6OptSourceAddress,
|
||||
Data: NewIcmpv6OptSourceTargetAddress(gwMac).Bytes(),
|
||||
},*/
|
||||
layers.ICMPv6Option{
|
||||
Type: layers.ICMPv6OptMTU,
|
||||
Data: NewIcmpV6OptMtu(mtu).Bytes(),
|
||||
},
|
||||
layers.ICMPv6Option{
|
||||
Type: layers.ICMPv6OptPrefixInfo,
|
||||
Data: NewIcmpv6OptPrefixInfo(gwIP, prefixLen).Bytes(),
|
||||
},
|
||||
}
|
||||
for i := range routes6 {
|
||||
rt := routes6[i]
|
||||
pkt.Options = append(pkt.Options, layers.ICMPv6Option{
|
||||
Type: 24,
|
||||
Data: NewIcmpv6OptRouteInfo(9000, rt.Prefix.To16(), rt.PrefixLen).Bytes(),
|
||||
})
|
||||
}
|
||||
|
||||
sbf := gopacket.NewSerializeBuffer()
|
||||
err := pkt.SerializeTo(sbf, gopacket.SerializeOptions{})
|
||||
if err != nil {
|
||||
return nil, nil, nil, errors.Wrap(err, "SerializeTo")
|
||||
}
|
||||
return sbf.Bytes(), gwIP, nil, nil
|
||||
}
|
||||
|
||||
// DHCPv6 https://datatracker.ietf.org/doc/html/rfc8415
|
||||
/*
|
||||
0 1 2 3
|
||||
|
||||
@@ -229,9 +229,6 @@ func (s *DHCPServer) serveDHCP(handler DHCPHandler) error {
|
||||
log.Errorf("Receiving DHCP packet: %s", err)
|
||||
continue
|
||||
}
|
||||
// if intf == nil {
|
||||
// return fmt.Errorf("Received DHCP packet with no interface information (this is a violation of dhcp4.Conn's contract)")
|
||||
// }
|
||||
|
||||
go func() {
|
||||
defer func() {
|
||||
@@ -279,8 +276,6 @@ func (s *DHCP6Server) serveDHCP(handler DHCP6Handler) error {
|
||||
continue
|
||||
}
|
||||
|
||||
log.Debugf("[DHCP6] received packet %d from %s mac %s", len(pkt), addr, mac)
|
||||
|
||||
go func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
@@ -291,21 +286,7 @@ func (s *DHCP6Server) serveDHCP(handler DHCP6Handler) error {
|
||||
|
||||
if addr.Port == icmpRAFakePort {
|
||||
// receive a RA solication
|
||||
resp, gwIp, gwMac, err := handler.ServeRA(pkt, mac, addr)
|
||||
if err != nil {
|
||||
log.Warningf("[DHCP6] handler ServeRA error: %s", err)
|
||||
return
|
||||
}
|
||||
if resp == nil {
|
||||
log.Warningf("[DHCP6] hander ServeRA response null packet")
|
||||
return
|
||||
}
|
||||
|
||||
// RA should be sent to FF02::1 from gwIP
|
||||
err = s.conn.SendICMP6(resp, gwIp, gwMac, mac)
|
||||
if err != nil {
|
||||
log.Errorf("[DHCP6] failed to response packet for ICMP6 message: %s", err)
|
||||
}
|
||||
handler.OnRecvICMP6(pkt, mac, addr)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
15
pkg/util/icmp6/doc.go
Normal file
15
pkg/util/icmp6/doc.go
Normal file
@@ -0,0 +1,15 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package icmp6 // import "yunion.io/x/onecloud/pkg/util/icmp6"
|
||||
459
pkg/util/icmp6/messages.go
Normal file
459
pkg/util/icmp6/messages.go
Normal file
@@ -0,0 +1,459 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package icmp6
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/layers"
|
||||
|
||||
"yunion.io/x/pkg/errors"
|
||||
)
|
||||
|
||||
type TPreference int
|
||||
|
||||
const (
|
||||
PreferenceLow TPreference = 0
|
||||
PreferenceMedium TPreference = 1
|
||||
PreferenceHigh TPreference = 2
|
||||
)
|
||||
|
||||
func (pref TPreference) String() string {
|
||||
switch pref {
|
||||
case PreferenceLow:
|
||||
return "low"
|
||||
case PreferenceMedium:
|
||||
return "medium"
|
||||
case PreferenceHigh:
|
||||
return "high"
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
type SBaseICMP6Message struct {
|
||||
SrcMac net.HardwareAddr
|
||||
SrcIP net.IP
|
||||
DstMac net.HardwareAddr
|
||||
DstIP net.IP
|
||||
}
|
||||
|
||||
func (msg SBaseICMP6Message) String() string {
|
||||
return fmt.Sprintf("%s[%s]->%s[%s]", msg.SrcIP.String(), msg.SrcMac.String(), msg.DstIP.String(), msg.DstMac.String())
|
||||
}
|
||||
|
||||
type IICMP6Message interface {
|
||||
Payload() gopacket.SerializableLayer
|
||||
ICMP6TypeCode() layers.ICMPv6TypeCode
|
||||
|
||||
SourceMac() net.HardwareAddr
|
||||
SourceIP() net.IP
|
||||
DestinationMac() net.HardwareAddr
|
||||
DestinationIP() net.IP
|
||||
}
|
||||
|
||||
func (msg SBaseICMP6Message) SourceIP() net.IP {
|
||||
return msg.SrcIP
|
||||
}
|
||||
|
||||
func (msg SBaseICMP6Message) SourceMac() net.HardwareAddr {
|
||||
return msg.SrcMac
|
||||
}
|
||||
|
||||
func (msg SBaseICMP6Message) DestinationIP() net.IP {
|
||||
return msg.DstIP
|
||||
}
|
||||
|
||||
func (msg SBaseICMP6Message) DestinationMac() net.HardwareAddr {
|
||||
return msg.DstMac
|
||||
}
|
||||
|
||||
type SRouterSolicitation struct {
|
||||
SBaseICMP6Message
|
||||
}
|
||||
|
||||
type SPrefixInfoOption struct {
|
||||
IsOnlink bool
|
||||
IsAutoconf bool
|
||||
Prefix net.IP
|
||||
PrefixLen uint8
|
||||
ValidLifetime uint32
|
||||
PreferredLifetime uint32
|
||||
}
|
||||
|
||||
func (opt SPrefixInfoOption) String() string {
|
||||
return fmt.Sprintf("%s/%d (IsOnlink: %t, IsAutoconf: %t) ValidLifetime: %d, PreferredLifetime: %d", opt.Prefix.String(), opt.PrefixLen, opt.IsOnlink, opt.IsAutoconf, opt.ValidLifetime, opt.PreferredLifetime)
|
||||
}
|
||||
|
||||
type SRouteInfoOption struct {
|
||||
RouteLifetime uint32
|
||||
Prefix net.IP
|
||||
PrefixLen uint8
|
||||
Preference TPreference
|
||||
}
|
||||
|
||||
func (opt SRouteInfoOption) String() string {
|
||||
return fmt.Sprintf("%s/%d (Pref: %s) RouteLifetime: %d", opt.Prefix.String(), opt.PrefixLen, opt.Preference.String(), opt.RouteLifetime)
|
||||
}
|
||||
|
||||
type SRouterAdvertisement struct {
|
||||
SBaseICMP6Message
|
||||
|
||||
CurHopLimit uint8
|
||||
|
||||
IsManaged bool
|
||||
IsOther bool
|
||||
IsHomeAgent bool
|
||||
|
||||
Preference TPreference
|
||||
|
||||
RouterLifetime uint16
|
||||
ReachableTime uint32
|
||||
RetransTimer uint32
|
||||
|
||||
MTU uint32
|
||||
PrefixInfo []SPrefixInfoOption
|
||||
RouteInfo []SRouteInfoOption
|
||||
}
|
||||
|
||||
type SNeighborSolicitation struct {
|
||||
SBaseICMP6Message
|
||||
|
||||
/*
|
||||
The IP address of the target of the solicitation.
|
||||
It MUST NOT be a multicast address.
|
||||
*/
|
||||
TargetAddr net.IP
|
||||
}
|
||||
|
||||
type SNeighborAdvertisement struct {
|
||||
SBaseICMP6Message
|
||||
|
||||
/*
|
||||
For solicited advertisements, the Target Address
|
||||
field in the Neighbor Solicitation message that
|
||||
prompted this advertisement. For an unsolicited
|
||||
advertisement, the address whose link-layer address
|
||||
has changed. The Target Address MUST NOT be a
|
||||
multicast address.
|
||||
*/
|
||||
TargetAddr net.IP
|
||||
|
||||
IsRouter bool
|
||||
IsSolicited bool
|
||||
}
|
||||
|
||||
func (msg SNeighborSolicitation) ICMP6TypeCode() layers.ICMPv6TypeCode {
|
||||
return layers.CreateICMPv6TypeCode(layers.ICMPv6TypeNeighborSolicitation, 0)
|
||||
}
|
||||
|
||||
func (msg SNeighborSolicitation) Payload() gopacket.SerializableLayer {
|
||||
pkt := layers.ICMPv6NeighborSolicitation{}
|
||||
pkt.TargetAddress = msg.TargetAddr
|
||||
|
||||
pkt.Options = layers.ICMPv6Options{
|
||||
layers.ICMPv6Option{
|
||||
Type: layers.ICMPv6OptSourceAddress,
|
||||
Data: NewIcmpv6OptSourceTargetAddress(msg.SrcMac).Bytes(),
|
||||
},
|
||||
}
|
||||
|
||||
return &pkt
|
||||
}
|
||||
|
||||
func (msg *SNeighborSolicitation) Unmarshal(data *layers.ICMPv6NeighborSolicitation) error {
|
||||
msg.TargetAddr = data.TargetAddress
|
||||
return nil
|
||||
}
|
||||
|
||||
func (msg SNeighborAdvertisement) ICMP6TypeCode() layers.ICMPv6TypeCode {
|
||||
return layers.CreateICMPv6TypeCode(layers.ICMPv6TypeNeighborAdvertisement, 0)
|
||||
}
|
||||
|
||||
func (msg SNeighborAdvertisement) Payload() gopacket.SerializableLayer {
|
||||
pkt := layers.ICMPv6NeighborAdvertisement{}
|
||||
pkt.TargetAddress = msg.TargetAddr
|
||||
pkt.Flags = 0x00
|
||||
if msg.IsRouter {
|
||||
pkt.Flags |= 0x80
|
||||
}
|
||||
if msg.IsSolicited {
|
||||
pkt.Flags |= 0x40
|
||||
}
|
||||
|
||||
pkt.Options = layers.ICMPv6Options{
|
||||
layers.ICMPv6Option{
|
||||
Type: layers.ICMPv6OptSourceAddress,
|
||||
Data: NewIcmpv6OptSourceTargetAddress(msg.SrcMac).Bytes(),
|
||||
},
|
||||
}
|
||||
|
||||
return &pkt
|
||||
}
|
||||
|
||||
func (msg *SNeighborAdvertisement) Unmarshal(data *layers.ICMPv6NeighborAdvertisement) error {
|
||||
msg.TargetAddr = data.TargetAddress
|
||||
msg.IsRouter = data.Flags&0x80 != 0
|
||||
msg.IsSolicited = data.Flags&0x40 != 0
|
||||
return nil
|
||||
}
|
||||
|
||||
func (msg SRouterSolicitation) ICMP6TypeCode() layers.ICMPv6TypeCode {
|
||||
return layers.CreateICMPv6TypeCode(layers.ICMPv6TypeRouterSolicitation, 0)
|
||||
}
|
||||
|
||||
func (msg SRouterSolicitation) Payload() gopacket.SerializableLayer {
|
||||
pkt := layers.ICMPv6RouterSolicitation{}
|
||||
|
||||
pkt.Options = layers.ICMPv6Options{
|
||||
layers.ICMPv6Option{
|
||||
Type: layers.ICMPv6OptSourceAddress,
|
||||
Data: NewIcmpv6OptSourceTargetAddress(msg.SrcMac).Bytes(),
|
||||
},
|
||||
}
|
||||
|
||||
return &pkt
|
||||
}
|
||||
|
||||
func (msg *SRouterSolicitation) Unmarshal(data *layers.ICMPv6RouterSolicitation) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (msg SRouterAdvertisement) ICMP6TypeCode() layers.ICMPv6TypeCode {
|
||||
return layers.CreateICMPv6TypeCode(layers.ICMPv6TypeRouterAdvertisement, 0)
|
||||
}
|
||||
|
||||
func (msg SRouterAdvertisement) Payload() gopacket.SerializableLayer {
|
||||
pkt := layers.ICMPv6RouterAdvertisement{}
|
||||
// https://datatracker.ietf.org/doc/html/rfc4861#section-4.2
|
||||
// https://datatracker.ietf.org/doc/html/rfc4191
|
||||
pkt.Flags = 0x00 // M=1, O=1, stateful DHCPv6, pref=00
|
||||
if msg.IsManaged {
|
||||
pkt.Flags |= 0x80
|
||||
}
|
||||
if msg.IsOther {
|
||||
pkt.Flags |= 0x40
|
||||
}
|
||||
if msg.IsHomeAgent {
|
||||
pkt.Flags |= 0x20
|
||||
}
|
||||
|
||||
switch msg.Preference {
|
||||
case PreferenceLow:
|
||||
pkt.Flags |= 0x18
|
||||
case PreferenceMedium:
|
||||
// do nothing
|
||||
case PreferenceHigh:
|
||||
pkt.Flags |= 0x08
|
||||
}
|
||||
|
||||
pkt.HopLimit = msg.CurHopLimit
|
||||
pkt.RouterLifetime = msg.RouterLifetime
|
||||
pkt.ReachableTime = msg.ReachableTime
|
||||
pkt.RetransTimer = msg.RetransTimer
|
||||
|
||||
pkt.Options = layers.ICMPv6Options{
|
||||
layers.ICMPv6Option{
|
||||
Type: layers.ICMPv6OptSourceAddress,
|
||||
Data: NewIcmpv6OptSourceTargetAddress(msg.SrcMac).Bytes(),
|
||||
},
|
||||
layers.ICMPv6Option{
|
||||
Type: layers.ICMPv6OptMTU,
|
||||
Data: NewIcmpV6OptMtu(msg.MTU).Bytes(),
|
||||
},
|
||||
}
|
||||
for i := range msg.PrefixInfo {
|
||||
pref := msg.PrefixInfo[i]
|
||||
pkt.Options = append(pkt.Options, layers.ICMPv6Option{
|
||||
Type: layers.ICMPv6OptPrefixInfo,
|
||||
Data: NewIcmpv6OptPrefixInfo(pref).Bytes(),
|
||||
})
|
||||
}
|
||||
for i := range msg.RouteInfo {
|
||||
rt := msg.RouteInfo[i]
|
||||
pkt.Options = append(pkt.Options, layers.ICMPv6Option{
|
||||
Type: 24,
|
||||
Data: NewIcmpv6OptRouteInfo(rt).Bytes(),
|
||||
})
|
||||
}
|
||||
|
||||
return &pkt
|
||||
}
|
||||
|
||||
func (msg *SRouterAdvertisement) Unmarshal(data *layers.ICMPv6RouterAdvertisement) error {
|
||||
msg.CurHopLimit = data.HopLimit
|
||||
msg.IsManaged = data.Flags&0x80 != 0
|
||||
msg.IsOther = data.Flags&0x40 != 0
|
||||
msg.IsHomeAgent = data.Flags&0x20 != 0
|
||||
switch data.Flags & 0x18 {
|
||||
case 0x18:
|
||||
msg.Preference = PreferenceLow
|
||||
case 0x08:
|
||||
msg.Preference = PreferenceHigh
|
||||
default:
|
||||
msg.Preference = PreferenceMedium
|
||||
}
|
||||
msg.RouterLifetime = data.RouterLifetime
|
||||
|
||||
for i := range data.Options {
|
||||
opt := data.Options[i]
|
||||
switch opt.Type {
|
||||
case layers.ICMPv6OptMTU:
|
||||
msg.MTU = DecodeIcmpV6OptMtu(opt.Data)
|
||||
case layers.ICMPv6OptPrefixInfo:
|
||||
prefix := DecodeIcmpv6OptPrefixInfo(opt.Data)
|
||||
msg.PrefixInfo = append(msg.PrefixInfo, prefix)
|
||||
case 24:
|
||||
route := DecodeIcmpv6OptRouteInfo(opt.Data)
|
||||
msg.RouteInfo = append(msg.RouteInfo, route)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (msg SRouterAdvertisement) String() string {
|
||||
return fmt.Sprintf(`RouterAdvertisement %s
|
||||
CurHopLimit: %d, IsManaged: %t, IsOther: %t, IsHomeAgent: %t, Preference: %s, RouterLifetime: %d, ReachableTime: %d, RetransTimer: %d
|
||||
MTU: %d
|
||||
PrefixInfo: %v
|
||||
RouteInfo: %v)`,
|
||||
msg.SBaseICMP6Message.String(),
|
||||
msg.CurHopLimit, msg.IsManaged, msg.IsOther, msg.IsHomeAgent, msg.Preference.String(), msg.RouterLifetime, msg.ReachableTime, msg.RetransTimer,
|
||||
msg.MTU, msg.PrefixInfo, msg.RouteInfo)
|
||||
}
|
||||
|
||||
func EncodePacket(msg IICMP6Message) ([]byte, error) {
|
||||
var eth = &layers.Ethernet{
|
||||
EthernetType: layers.EthernetTypeIPv6,
|
||||
SrcMAC: msg.SourceMac(),
|
||||
DstMAC: msg.DestinationMac(),
|
||||
}
|
||||
|
||||
var ip = &layers.IPv6{
|
||||
Version: 6,
|
||||
HopLimit: 64,
|
||||
SrcIP: msg.SourceIP(),
|
||||
DstIP: msg.DestinationIP(),
|
||||
NextHeader: layers.IPProtocolICMPv6,
|
||||
}
|
||||
|
||||
var icmp6 = &layers.ICMPv6{
|
||||
TypeCode: msg.ICMP6TypeCode(),
|
||||
}
|
||||
icmp6.SetNetworkLayerForChecksum(ip)
|
||||
|
||||
var payload = msg.Payload()
|
||||
|
||||
var (
|
||||
buf = gopacket.NewSerializeBuffer()
|
||||
opts = gopacket.SerializeOptions{ComputeChecksums: true, FixLengths: true}
|
||||
)
|
||||
if err := gopacket.SerializeLayers(buf, opts, eth, ip, icmp6, payload); err != nil {
|
||||
return nil, errors.Wrap(err, "SerializeLayers error")
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func DecodePacket(data []byte) (IICMP6Message, error) {
|
||||
packet := gopacket.NewPacket(data, layers.LayerTypeEthernet, gopacket.Default)
|
||||
if packet.ErrorLayer() != nil {
|
||||
return nil, errors.Wrap(packet.ErrorLayer().Error(), "DecodePacket error")
|
||||
}
|
||||
|
||||
var baseMsg SBaseICMP6Message
|
||||
|
||||
{
|
||||
ethLayer := packet.Layer(layers.LayerTypeEthernet)
|
||||
if ethLayer != nil {
|
||||
eth := ethLayer.(*layers.Ethernet)
|
||||
baseMsg.SrcMac = eth.SrcMAC
|
||||
baseMsg.DstMac = eth.DstMAC
|
||||
} else {
|
||||
return nil, errors.Wrap(packet.ErrorLayer().Error(), "Expect Ethernet layer")
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
ipLayer := packet.Layer(layers.LayerTypeIPv6)
|
||||
if ipLayer != nil {
|
||||
// ipv6
|
||||
ip6 := ipLayer.(*layers.IPv6)
|
||||
baseMsg.SrcIP = ip6.SrcIP
|
||||
baseMsg.DstIP = ip6.DstIP
|
||||
} else {
|
||||
return nil, errors.Wrap(packet.ErrorLayer().Error(), "Expect IPv6 packet")
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
icmpLayer := packet.Layer(layers.LayerTypeICMPv6)
|
||||
if icmpLayer != nil {
|
||||
icmp6 := icmpLayer.(*layers.ICMPv6)
|
||||
if icmp6 == nil {
|
||||
return nil, errors.Wrap(packet.ErrorLayer().Error(), "Expect IPv6 packet")
|
||||
}
|
||||
|
||||
switch icmp6.TypeCode.Type() {
|
||||
case 133:
|
||||
payload := packet.Layer(layers.LayerTypeICMPv6RouterSolicitation)
|
||||
if payload != nil {
|
||||
msg := &SRouterSolicitation{
|
||||
SBaseICMP6Message: baseMsg,
|
||||
}
|
||||
return msg, nil
|
||||
} else {
|
||||
return nil, errors.Wrap(packet.ErrorLayer().Error(), "Expect ICMPv6 Router Solicitation packet")
|
||||
}
|
||||
case 134:
|
||||
payload := packet.Layer(layers.LayerTypeICMPv6RouterAdvertisement)
|
||||
if payload != nil {
|
||||
msg := &SRouterAdvertisement{
|
||||
SBaseICMP6Message: baseMsg,
|
||||
}
|
||||
return msg, nil
|
||||
} else {
|
||||
return nil, errors.Wrap(packet.ErrorLayer().Error(), "Expect ICMPv6 Router Advertisement packet")
|
||||
}
|
||||
case 135:
|
||||
payload := packet.Layer(layers.LayerTypeICMPv6NeighborSolicitation)
|
||||
if payload != nil {
|
||||
msg := &SNeighborSolicitation{
|
||||
SBaseICMP6Message: baseMsg,
|
||||
}
|
||||
return msg, nil
|
||||
} else {
|
||||
return nil, errors.Wrap(packet.ErrorLayer().Error(), "Expect ICMPv6 Neighbor Solicitation packet")
|
||||
}
|
||||
case 136:
|
||||
payload := packet.Layer(layers.LayerTypeICMPv6NeighborAdvertisement)
|
||||
if payload != nil {
|
||||
msg := &SNeighborAdvertisement{
|
||||
SBaseICMP6Message: baseMsg,
|
||||
}
|
||||
return msg, nil
|
||||
} else {
|
||||
return nil, errors.Wrap(packet.ErrorLayer().Error(), "Expect ICMPv6 Neighbor Advertisement packet")
|
||||
}
|
||||
default:
|
||||
return nil, errors.Wrap(packet.ErrorLayer().Error(), "Expect ICMPv6 packet")
|
||||
}
|
||||
} else {
|
||||
return nil, errors.Wrap(packet.ErrorLayer().Error(), "Expect IPv6 packet")
|
||||
}
|
||||
}
|
||||
}
|
||||
246
pkg/util/icmp6/options.go
Normal file
246
pkg/util/icmp6/options.go
Normal file
@@ -0,0 +1,246 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package icmp6
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"net"
|
||||
)
|
||||
|
||||
type ICMP6OptionType int
|
||||
|
||||
const (
|
||||
ICMP6OptMTU ICMP6OptionType = 1
|
||||
ICMP6OptPrefixInfo ICMP6OptionType = 2
|
||||
ICMP6OptLinkLayerAddress ICMP6OptionType = 3
|
||||
ICMP6OptRouteInfo ICMP6OptionType = 24
|
||||
)
|
||||
|
||||
type ICMP6Option struct {
|
||||
Type ICMP6OptionType
|
||||
Data []byte
|
||||
}
|
||||
|
||||
/*
|
||||
https://datatracker.ietf.org/doc/html/rfc4861#section-4.6.4
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Type | Length | Reserved |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| MTU |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
type icmpV6OptMtu struct {
|
||||
MTU uint32
|
||||
}
|
||||
|
||||
func (opt icmpV6OptMtu) Bytes() []byte {
|
||||
buf := make([]byte, 6)
|
||||
binary.BigEndian.PutUint32(buf[2:], opt.MTU)
|
||||
return buf
|
||||
}
|
||||
|
||||
func NewIcmpV6OptMtu(mtu uint32) icmpV6OptMtu {
|
||||
return icmpV6OptMtu{
|
||||
MTU: mtu,
|
||||
}
|
||||
}
|
||||
|
||||
func DecodeIcmpV6OptMtu(data []byte) uint32 {
|
||||
return binary.BigEndian.Uint32(data[2:])
|
||||
}
|
||||
|
||||
/*
|
||||
https://datatracker.ietf.org/doc/html/rfc4861#section-4.6.2
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Type | Length | Prefix Length |L|A| Reserved1 |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Valid Lifetime |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Preferred Lifetime |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Reserved2 |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| |
|
||||
+ +
|
||||
| |
|
||||
+ Prefix +
|
||||
| |
|
||||
+ +
|
||||
| |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
type icmpv6OptPrefixInfo struct {
|
||||
PrefixLen uint8
|
||||
Flag uint8
|
||||
ValidLifetime uint32
|
||||
PreferredLifetime uint32
|
||||
Reserved2 uint32
|
||||
Prefix []byte
|
||||
}
|
||||
|
||||
func (opt icmpv6OptPrefixInfo) Bytes() []byte {
|
||||
buf := make([]byte, 30)
|
||||
buf[0] = opt.PrefixLen
|
||||
buf[1] = opt.Flag
|
||||
binary.BigEndian.PutUint32(buf[2:], opt.ValidLifetime)
|
||||
binary.BigEndian.PutUint32(buf[6:], opt.PreferredLifetime)
|
||||
binary.BigEndian.PutUint32(buf[10:], opt.Reserved2)
|
||||
copy(buf[14:], opt.Prefix[:])
|
||||
return buf
|
||||
}
|
||||
|
||||
func DecodeIcmpv6OptPrefixInfo(data []byte) SPrefixInfoOption {
|
||||
rawInfo := icmpv6OptPrefixInfo{
|
||||
PrefixLen: data[0],
|
||||
Flag: data[1],
|
||||
ValidLifetime: binary.BigEndian.Uint32(data[2:6]),
|
||||
PreferredLifetime: binary.BigEndian.Uint32(data[6:10]),
|
||||
Reserved2: binary.BigEndian.Uint32(data[10:14]),
|
||||
Prefix: data[14:],
|
||||
}
|
||||
return SPrefixInfoOption{
|
||||
IsOnlink: rawInfo.Flag&0x80 != 0,
|
||||
IsAutoconf: rawInfo.Flag&0x40 != 0,
|
||||
Prefix: net.IP(rawInfo.Prefix),
|
||||
PrefixLen: rawInfo.PrefixLen,
|
||||
ValidLifetime: rawInfo.ValidLifetime,
|
||||
PreferredLifetime: rawInfo.PreferredLifetime,
|
||||
}
|
||||
}
|
||||
|
||||
func NewIcmpv6OptPrefixInfo(prefInfo SPrefixInfoOption) icmpv6OptPrefixInfo {
|
||||
flag := uint8(0)
|
||||
if prefInfo.IsOnlink {
|
||||
flag |= 0x80
|
||||
}
|
||||
if prefInfo.IsAutoconf {
|
||||
flag |= 0x40
|
||||
}
|
||||
return icmpv6OptPrefixInfo{
|
||||
PrefixLen: prefInfo.PrefixLen,
|
||||
Flag: flag,
|
||||
ValidLifetime: prefInfo.ValidLifetime,
|
||||
PreferredLifetime: prefInfo.PreferredLifetime,
|
||||
Reserved2: 0,
|
||||
Prefix: prefInfo.Prefix.To16(),
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
https://datatracker.ietf.org/doc/html/rfc4861#section-4.6.1
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Type | Length | Link-Layer Address ...
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
type icmpv6OptSourceTargetAddress struct {
|
||||
Mac net.HardwareAddr
|
||||
}
|
||||
|
||||
func (opt icmpv6OptSourceTargetAddress) Bytes() []byte {
|
||||
return opt.Mac[0:6]
|
||||
}
|
||||
|
||||
func DecodeIcmpv6OptSourceTargetAddress(data []byte) net.HardwareAddr {
|
||||
return net.HardwareAddr(data[0:6])
|
||||
}
|
||||
|
||||
func NewIcmpv6OptSourceTargetAddress(macAddr net.HardwareAddr) icmpv6OptSourceTargetAddress {
|
||||
return icmpv6OptSourceTargetAddress{
|
||||
Mac: macAddr,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
https://datatracker.ietf.org/doc/html/rfc4191#section-2.3
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Type | Length | Prefix Length |Resvd|Prf|Resvd|
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Route Lifetime |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Prefix (Variable Length) |
|
||||
. .
|
||||
. .
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
|
||||
type icmpv6OptRouteInfo struct {
|
||||
PrefixLen uint8
|
||||
Reserved1 uint8
|
||||
RouteLifetime uint32
|
||||
Prefix []byte
|
||||
}
|
||||
|
||||
func (opt icmpv6OptRouteInfo) Bytes() []byte {
|
||||
buf := make([]byte, 6)
|
||||
buf[0] = opt.PrefixLen
|
||||
buf[1] = opt.Reserved1
|
||||
binary.BigEndian.PutUint32(buf[2:6], opt.RouteLifetime)
|
||||
buf = append(buf, opt.Prefix...)
|
||||
return buf
|
||||
}
|
||||
|
||||
func DecodeIcmpv6OptRouteInfo(data []byte) SRouteInfoOption {
|
||||
rawInfo := icmpv6OptRouteInfo{
|
||||
PrefixLen: data[0],
|
||||
Reserved1: data[1],
|
||||
RouteLifetime: binary.BigEndian.Uint32(data[2:6]),
|
||||
Prefix: data[6:],
|
||||
}
|
||||
for i := len(rawInfo.Prefix); i < 16; i++ {
|
||||
rawInfo.Prefix = append(rawInfo.Prefix, 0)
|
||||
}
|
||||
var preference TPreference
|
||||
switch rawInfo.Reserved1 {
|
||||
case 0xc0:
|
||||
preference = PreferenceLow
|
||||
case 0x0:
|
||||
preference = PreferenceMedium
|
||||
case 0x40:
|
||||
preference = PreferenceHigh
|
||||
}
|
||||
return SRouteInfoOption{
|
||||
RouteLifetime: rawInfo.RouteLifetime,
|
||||
Prefix: net.IP(rawInfo.Prefix[:16]),
|
||||
PrefixLen: rawInfo.PrefixLen,
|
||||
Preference: preference,
|
||||
}
|
||||
}
|
||||
|
||||
func NewIcmpv6OptRouteInfo(routeInfo SRouteInfoOption) icmpv6OptRouteInfo {
|
||||
prefix := routeInfo.Prefix.To16()
|
||||
prefixLen := routeInfo.PrefixLen
|
||||
routeLifetime := routeInfo.RouteLifetime
|
||||
if prefixLen <= 0 {
|
||||
prefix = prefix[0:0]
|
||||
} else if prefixLen <= 64 {
|
||||
prefix = prefix[0:8]
|
||||
} else {
|
||||
prefix = prefix[0:16]
|
||||
}
|
||||
return icmpv6OptRouteInfo{
|
||||
PrefixLen: prefixLen,
|
||||
Reserved1: 0,
|
||||
RouteLifetime: routeLifetime,
|
||||
Prefix: prefix,
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,6 @@ import (
|
||||
"yunion.io/x/pkg/util/regutils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/types"
|
||||
"yunion.io/x/onecloud/pkg/util/dhcp"
|
||||
"yunion.io/x/onecloud/pkg/util/procutils"
|
||||
)
|
||||
|
||||
@@ -132,8 +131,8 @@ func Netlen2Mask(netmasklen int) string {
|
||||
return netutils.Netlen2Mask(netmasklen)
|
||||
}
|
||||
|
||||
func addRoute(routes []dhcp.SRouteInfo, net, gw string) []dhcp.SRouteInfo {
|
||||
route, _ := dhcp.ParseRouteInfo([]string{net, gw})
|
||||
func addRoute(routes []SRouteInfo, net, gw string) []SRouteInfo {
|
||||
route, _ := ParseRouteInfo([]string{net, gw})
|
||||
if route != nil {
|
||||
for _, rt := range routes {
|
||||
if rt.Prefix.String() == route.Prefix.String() && rt.PrefixLen == route.PrefixLen {
|
||||
@@ -146,7 +145,7 @@ func addRoute(routes []dhcp.SRouteInfo, net, gw string) []dhcp.SRouteInfo {
|
||||
return routes
|
||||
}
|
||||
|
||||
func extendRoutes(routes4, routes6 []dhcp.SRouteInfo, nicRoutes []types.SRoute) ([]dhcp.SRouteInfo, []dhcp.SRouteInfo) {
|
||||
func extendRoutes(routes4, routes6 []SRouteInfo, nicRoutes []types.SRoute) ([]SRouteInfo, []SRouteInfo) {
|
||||
for i := 0; i < len(nicRoutes); i++ {
|
||||
if regutils.MatchCIDR6(nicRoutes[i][0]) {
|
||||
routes6 = addRoute(routes6, nicRoutes[i][0], nicRoutes[i][1])
|
||||
@@ -166,7 +165,7 @@ func isExitAddress(ip string) bool {
|
||||
return netutils.IsExitAddress(ipv4)
|
||||
}
|
||||
|
||||
func AddNicRoutes(routes4 []dhcp.SRouteInfo, routes6 []dhcp.SRouteInfo, nicDesc *types.SServerNic, mainIp string, mainIp6 string, nicCnt int) ([]dhcp.SRouteInfo, []dhcp.SRouteInfo) {
|
||||
func AddNicRoutes(routes4 []SRouteInfo, routes6 []SRouteInfo, nicDesc *types.SServerNic, mainIp string, mainIp6 string, nicCnt int) ([]SRouteInfo, []SRouteInfo) {
|
||||
// always add static routes, even if this is the default NIC
|
||||
// if mainIp == nicDesc.Ip {
|
||||
// return routes
|
||||
|
||||
@@ -63,9 +63,8 @@ func (n *SNetInterface) getAddresses(listFunc func() ([]net.IPNet, error)) []SNi
|
||||
|
||||
func (n *SNetInterface) GetRouteSpecs() []iproute2.RouteSpec {
|
||||
routeList := iproute2.NewRoute(n.name)
|
||||
routes4 := getRouteSpecs(routeList.List4)
|
||||
routes6 := getRouteSpecs(routeList.List6)
|
||||
rets := make([]iproute2.RouteSpec, 0)
|
||||
routes4 := getRouteSpecs(routeList.List4)
|
||||
for i := range routes4 {
|
||||
if routes4[i].Gw == nil {
|
||||
continue
|
||||
@@ -75,6 +74,7 @@ func (n *SNetInterface) GetRouteSpecs() []iproute2.RouteSpec {
|
||||
}
|
||||
rets = append(rets, routes4[i])
|
||||
}
|
||||
routes6 := getRouteSpecs(routeList.List6)
|
||||
for i := range routes6 {
|
||||
if routes6[i].Gw == nil {
|
||||
continue
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
package netutils2
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
@@ -182,3 +183,15 @@ func TestGetMainNicFromDeployApi(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRouteSpecs(t *testing.T) {
|
||||
dirs, _ := os.ReadDir("/sys/class/net")
|
||||
for _, file := range dirs {
|
||||
t.Logf("dir: %s", file.Name())
|
||||
n := NewNetInterface(file.Name())
|
||||
routes := n.GetRouteSpecs()
|
||||
for i := range routes {
|
||||
t.Logf("route %s via %s", routes[i].Dst.String(), routes[i].Gw.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
59
pkg/util/netutils2/routeinfo.go
Normal file
59
pkg/util/netutils2/routeinfo.go
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package netutils2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"yunion.io/x/pkg/errors"
|
||||
)
|
||||
|
||||
type SPrefixInfo struct {
|
||||
Prefix net.IP
|
||||
PrefixLen uint8
|
||||
}
|
||||
|
||||
func (p SPrefixInfo) String() string {
|
||||
return fmt.Sprintf("%s/%d", p.Prefix.String(), p.PrefixLen)
|
||||
}
|
||||
|
||||
type SRouteInfo struct {
|
||||
SPrefixInfo
|
||||
|
||||
Gateway net.IP
|
||||
}
|
||||
|
||||
func (r SRouteInfo) String() string {
|
||||
return fmt.Sprintf("%s via %s", r.SPrefixInfo.String(), r.Gateway.String())
|
||||
}
|
||||
|
||||
func ParseRouteInfo(route []string) (*SRouteInfo, error) {
|
||||
if len(route) < 2 {
|
||||
return nil, errors.Wrapf(errors.ErrInvalidStatus, "invalid route %#v", route)
|
||||
}
|
||||
_, prefixLen, err := net.ParseCIDR(route[0])
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "net.ParseCIDR %s", route[0])
|
||||
}
|
||||
ones, _ := prefixLen.Mask.Size()
|
||||
return &SRouteInfo{
|
||||
SPrefixInfo: SPrefixInfo{
|
||||
Prefix: prefixLen.IP,
|
||||
PrefixLen: uint8(ones),
|
||||
},
|
||||
Gateway: net.ParseIP(route[1]),
|
||||
}, nil
|
||||
}
|
||||
83
pkg/util/netutils2/routeinfo_test.go
Normal file
83
pkg/util/netutils2/routeinfo_test.go
Normal file
@@ -0,0 +1,83 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package netutils2
|
||||
|
||||
import (
|
||||
"net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParseRouteInfo(t *testing.T) {
|
||||
cases := []struct {
|
||||
net string
|
||||
gw string
|
||||
want *SRouteInfo
|
||||
}{
|
||||
{
|
||||
net: "10.0.0.0/8",
|
||||
gw: "10.168.120.1",
|
||||
want: &SRouteInfo{
|
||||
SPrefixInfo: SPrefixInfo{
|
||||
Prefix: net.ParseIP("10.0.0.0"),
|
||||
PrefixLen: 8,
|
||||
},
|
||||
Gateway: net.ParseIP("10.168.120.1"),
|
||||
},
|
||||
},
|
||||
{
|
||||
net: "::/0",
|
||||
gw: "3ffe:3200:fe::1",
|
||||
want: &SRouteInfo{
|
||||
SPrefixInfo: SPrefixInfo{
|
||||
Prefix: net.ParseIP("::"),
|
||||
PrefixLen: 0,
|
||||
},
|
||||
Gateway: net.ParseIP("3ffe:3200:fe::1"),
|
||||
},
|
||||
},
|
||||
{
|
||||
net: "fd00:ec2::254/128",
|
||||
gw: "::",
|
||||
want: &SRouteInfo{
|
||||
SPrefixInfo: SPrefixInfo{
|
||||
Prefix: net.ParseIP("fd00:ec2::254"),
|
||||
PrefixLen: 128,
|
||||
},
|
||||
Gateway: net.ParseIP("::"),
|
||||
},
|
||||
},
|
||||
{
|
||||
net: "fe80::a9fe:a9fe/128",
|
||||
gw: "::",
|
||||
want: &SRouteInfo{
|
||||
SPrefixInfo: SPrefixInfo{
|
||||
Prefix: net.ParseIP("fe80::a9fe:a9fe"),
|
||||
PrefixLen: 128,
|
||||
},
|
||||
Gateway: net.ParseIP("::"),
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
routeInfo, err := ParseRouteInfo([]string{c.net, c.gw})
|
||||
if err != nil {
|
||||
t.Errorf("parse route %s error: %v", c.net, err)
|
||||
continue
|
||||
}
|
||||
if routeInfo.String() != c.want.String() {
|
||||
t.Errorf("parse route expect %s got: %s", c.want.String(), routeInfo.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user