wireguard源码分析(九)

package tunnel

import (
	"golang.org/x/sys/windows"
	"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
)

func findDefaultLUID(family winipcfg.AddressFamily, ourLUID winipcfg.LUID, lastLUID *winipcfg.LUID, lastIndex *uint32) error {
	r, err := winipcfg.GetIPForwardTable2(family)
	if err != nil {
		return err
	}
	lowestMetric := ^uint32(0)
	index := uint32(0)
	luid := winipcfg.LUID(0)
	for i := range r {
		if r[i].DestinationPrefix.PrefixLength != 0 || r[i].InterfaceLUID == ourLUID {
			continue
		}
		ifrow, err := r[i].InterfaceLUID.Interface()
		if err != nil || ifrow.OperStatus != winipcfg.IfOperStatusUp {
			continue
		}

		iface, err := r[i].InterfaceLUID.IPInterface(family)
		if err != nil {
			continue
		}

		if r[i].Metric+iface.Metric < lowestMetric {
			lowestMetric = r[i].Metric + iface.Metric
			index = r[i].InterfaceIndex
			luid = r[i].InterfaceLUID
		}
	}
	if luid == *lastLUID && index == *lastIndex {
		return nil
	}
	*lastLUID = luid
	*lastIndex = index
	return nil
}

func monitorMTU(family winipcfg.AddressFamily, ourLUID winipcfg.LUID) ([]winipcfg.ChangeCallback, error) {
	var minMTU uint32
	if family == windows.AF_INET {
		minMTU = 576
	} else if family == windows.AF_INET6 {
		minMTU = 1280
	}
	lastLUID := winipcfg.LUID(0)
	lastIndex := ^uint32(0)
	lastMTU := uint32(0)
	doIt := func() error {
		err := findDefaultLUID(family, ourLUID, &lastLUID, &lastIndex)
		if err != nil {
			return err
		}
		mtu := uint32(0)
		if lastLUID != 0 {
			iface, err := lastLUID.Interface()
			if err != nil {
				return err
			}
			if iface.MTU > 0 {
				mtu = iface.MTU
			}
		}
		if mtu > 0 && lastMTU != mtu {
			iface, err := ourLUID.IPInterface(family)
			if err != nil {
				return err
			}
			iface.NLMTU = mtu - 80
			if iface.NLMTU < minMTU {
				iface.NLMTU = minMTU
			}
			err = iface.Set()
			if err != nil {
				return err
			}
			lastMTU = mtu
		}
		return nil
	}
	err := doIt()
	if err != nil {
		return nil, err
	}
	cbr, err := winipcfg.RegisterRouteChangeCallback(func(notificationType winipcfg.MibNotificationType, route *winipcfg.MibIPforwardRow2) {
		if route != nil && route.DestinationPrefix.PrefixLength == 0 {
			doIt()
		}
	})
	if err != nil {
		return nil, err
	}
	cbi, err := winipcfg.RegisterInterfaceChangeCallback(func(notificationType winipcfg.MibNotificationType, iface *winipcfg.MibIPInterfaceRow) {
		if notificationType == winipcfg.MibParameterNotification {
			doIt()
		}
	})
	if err != nil {
		cbr.Unregister()
		return nil, err
	}
	return []winipcfg.ChangeCallback{cbr, cbi}, nil
}

这段Go代码实现了监控和管理网络接口MTU(最大传输单元)的功能,尤其是用于WireGuard网络适配器在Windows系统中的操作。主要有两个核心函数:findDefaultLUIDmonitorMTU,它们共同协作以确保网络接口的MTU设置符合预期。

主要函数分析

1. findDefaultLUID

这个函数的目的是找到默认路由的接口LUID(Locally Unique Identifier)。它在指定的地址族(IPv4或IPv6)中查找当前系统的默认路由接口LUID和接口索引。

  • 参数:

    • family: 指定地址族(IPv4 或 IPv6)。
    • ourLUID: 当前接口的LUID,用于排除自身。
    • lastLUID: 上次记录的默认路由接口LUID。
    • lastIndex: 上次记录的默认路由接口索引。
  • 逻辑:

    • 调用 GetIPForwardTable2 获取路由表,根据前缀长度为0和接口操作状态为“Up”的条件筛选出默认路由。
    • 遍历路由表,找出具有最低路由度量(Metric)的接口,记录其LUID和接口索引。
    • 如果找到的新LUID和索引与上次记录的相同,函数直接返回。
    • 否则,更新 lastLUIDlastIndex
  • 应用场景:

    • 用于动态查找系统默认的网络接口,这在需要基于路由表的动态配置时非常重要。
2. monitorMTU

这个函数负责监控并调整网络接口的MTU值,确保它符合默认路由的MTU设置,并注册路由变化和接口变化的回调函数,以便动态调整MTU。

  • 参数:

    • family: 地址族(IPv4 或 IPv6)。
    • ourLUID: 当前接口的LUID,用于排除自身。
  • 逻辑:

    • 根据地址族确定最小MTU值(IPv4的最小MTU是576字节,IPv6是1280字节)。
    • 定义一个内部函数 doIt,用于查找默认路由LUID并更新当前接口的MTU:
      • 调用 findDefaultLUID 获取默认路由的LUID和接口索引。
      • 如果找到有效的MTU且与上次记录的MTU不同,则设置当前接口的MTU。
      • 如果计算得出的MTU值低于最小MTU值,则设置为最小MTU。
    • 初次调用 doIt 以立即应用MTU设置。
    • 注册两个回调函数:
      • RegisterRouteChangeCallback:监控路由表变化,重新执行 doIt 以更新MTU。
      • RegisterInterfaceChangeCallback:监控接口参数变化,重新执行 doIt 以更新MTU。
    • 返回注册的回调函数数组。
  • 应用场景:

    • 用于确保网络接口的MTU值动态跟随默认路由的MTU,特别是在路由或接口状态发生变化时。此功能在保持网络传输效率和避免分片传输中至关重要。

总结

  • 动态配置与监控: 代码展示了如何通过实时监控和回调机制动态调整网络接口的配置,确保其MTU与系统默认路由相一致。这对于保持网络传输的稳定性和优化传输性能非常关键。

  • 错误处理与回退: 代码中对错误处理也非常小心,在回调注册失败时,会确保先注销已成功注册的回调,避免资源泄漏或不一致的状态。

  • 系统集成: 该代码紧密集成了Windows系统的网络接口配置API(如 winipcfg 包),展示了如何在Go语言中使用这些底层API来管理网络配置,尤其是在特定的VPN场景下,如WireGuard。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值