mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-05-14 10:00:34 +00:00
107 lines
3.2 KiB
Go
107 lines
3.2 KiB
Go
package icmp
|
|
|
|
import (
|
|
"github.com/xtls/xray-core/common/errors"
|
|
"gvisor.dev/gvisor/pkg/tcpip"
|
|
"gvisor.dev/gvisor/pkg/tcpip/checksum"
|
|
"gvisor.dev/gvisor/pkg/tcpip/header"
|
|
)
|
|
|
|
func ProtocolLabel(netProto tcpip.NetworkProtocolNumber) string {
|
|
switch netProto {
|
|
case header.IPv4ProtocolNumber:
|
|
return "ipv4"
|
|
case header.IPv6ProtocolNumber:
|
|
return "ipv6"
|
|
default:
|
|
return "unknown"
|
|
}
|
|
}
|
|
|
|
func ParseEchoRequest(netProto tcpip.NetworkProtocolNumber, message []byte) (uint16, uint16, bool) {
|
|
switch netProto {
|
|
case header.IPv4ProtocolNumber:
|
|
if len(message) < header.ICMPv4MinimumSize {
|
|
return 0, 0, false
|
|
}
|
|
icmpHdr := header.ICMPv4(message)
|
|
if icmpHdr.Type() != header.ICMPv4Echo || icmpHdr.Code() != header.ICMPv4UnusedCode {
|
|
return 0, 0, false
|
|
}
|
|
return icmpHdr.Ident(), icmpHdr.Sequence(), true
|
|
case header.IPv6ProtocolNumber:
|
|
if len(message) < header.ICMPv6MinimumSize {
|
|
return 0, 0, false
|
|
}
|
|
icmpHdr := header.ICMPv6(message)
|
|
if icmpHdr.Type() != header.ICMPv6EchoRequest || icmpHdr.Code() != header.ICMPv6UnusedCode {
|
|
return 0, 0, false
|
|
}
|
|
return icmpHdr.Ident(), icmpHdr.Sequence(), true
|
|
default:
|
|
return 0, 0, false
|
|
}
|
|
}
|
|
|
|
func RewriteChecksum(netProto tcpip.NetworkProtocolNumber, message []byte, srcIP, dstIP tcpip.Address) error {
|
|
switch netProto {
|
|
case header.IPv4ProtocolNumber:
|
|
if len(message) < header.ICMPv4MinimumSize {
|
|
return errors.New("invalid icmpv4 packet")
|
|
}
|
|
icmpHdr := header.ICMPv4(message)
|
|
icmpHdr.SetChecksum(0)
|
|
icmpHdr.SetChecksum(header.ICMPv4Checksum(icmpHdr[:header.ICMPv4MinimumSize], checksum.Checksum(icmpHdr.Payload(), 0)))
|
|
return nil
|
|
case header.IPv6ProtocolNumber:
|
|
if len(message) < header.ICMPv6MinimumSize {
|
|
return errors.New("invalid icmpv6 packet")
|
|
}
|
|
icmpHdr := header.ICMPv6(message)
|
|
icmpHdr.SetChecksum(0)
|
|
icmpHdr.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{
|
|
Header: icmpHdr[:header.ICMPv6MinimumSize],
|
|
Src: srcIP,
|
|
Dst: dstIP,
|
|
PayloadCsum: checksum.Checksum(icmpHdr.Payload(), 0),
|
|
PayloadLen: len(icmpHdr.Payload()),
|
|
}))
|
|
return nil
|
|
default:
|
|
return errors.New("unsupported icmp network protocol")
|
|
}
|
|
}
|
|
|
|
func BuildLocalEchoReply(netProto tcpip.NetworkProtocolNumber, request []byte, srcIP, dstIP tcpip.Address) ([]byte, error) {
|
|
reply := append([]byte(nil), request...)
|
|
|
|
switch netProto {
|
|
case header.IPv4ProtocolNumber:
|
|
if len(reply) < header.ICMPv4MinimumSize {
|
|
return nil, errors.New("invalid icmpv4 echo packet")
|
|
}
|
|
icmpHdr := header.ICMPv4(reply)
|
|
if icmpHdr.Type() != header.ICMPv4Echo || icmpHdr.Code() != header.ICMPv4UnusedCode {
|
|
return nil, errors.New("not an icmpv4 echo request")
|
|
}
|
|
reply[0] = byte(header.ICMPv4EchoReply)
|
|
case header.IPv6ProtocolNumber:
|
|
if len(reply) < header.ICMPv6MinimumSize {
|
|
return nil, errors.New("invalid icmpv6 echo packet")
|
|
}
|
|
icmpHdr := header.ICMPv6(reply)
|
|
if icmpHdr.Type() != header.ICMPv6EchoRequest || icmpHdr.Code() != header.ICMPv6UnusedCode {
|
|
return nil, errors.New("not an icmpv6 echo request")
|
|
}
|
|
reply[0] = byte(header.ICMPv6EchoReply)
|
|
default:
|
|
return nil, errors.New("unsupported icmp network protocol")
|
|
}
|
|
|
|
if err := RewriteChecksum(netProto, reply, srcIP, dstIP); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return reply, nil
|
|
}
|