Skip to content

Commit

Permalink
feat: support dns hijack [WIP]
Browse files Browse the repository at this point in the history
  • Loading branch information
cxz66666 committed Oct 28, 2023
1 parent 396d89f commit a27fb13
Show file tree
Hide file tree
Showing 15 changed files with 586 additions and 32 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ require (
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8
github.com/things-go/go-socks5 v0.0.4
golang.org/x/net v0.17.0
golang.org/x/sys v0.13.0
golang.zx2c4.com/wireguard v0.0.0-20231022001213-2e0774f246fb
golang.zx2c4.com/wireguard/windows v0.5.3
Expand All @@ -31,6 +30,7 @@ require (
go4.org/unsafe/assume-no-moving-gc v0.0.0-20230525183740-e7c30c78aeb2 // indirect
golang.org/x/crypto v0.14.0 // indirect
golang.org/x/mod v0.13.0 // indirect
golang.org/x/net v0.17.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.14.0 // indirect
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
Expand Down
10 changes: 10 additions & 0 deletions internal/zcdns/local_server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package zcdns

import (
"context"
"github.com/miekg/dns"
)

type LocalServer interface {
HandleDnsMsg(ctx context.Context, msg *dns.Msg) (*dns.Msg, error)
}
40 changes: 40 additions & 0 deletions internal/zctcpip/icmp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package zctcpip

import (
"encoding/binary"
)

type ICMPType = byte

const (
ICMPTypePingRequest byte = 0x8
ICMPTypePingResponse byte = 0x0
)

type ICMPPacket []byte

func (p ICMPPacket) Type() ICMPType {
return p[0]
}

func (p ICMPPacket) SetType(v ICMPType) {
p[0] = v
}

func (p ICMPPacket) Code() byte {
return p[1]
}

func (p ICMPPacket) Checksum() uint16 {
return binary.BigEndian.Uint16(p[2:])
}

func (p ICMPPacket) SetChecksum(sum [2]byte) {
p[2] = sum[0]
p[3] = sum[1]
}

func (p ICMPPacket) ResetChecksum() {
p.SetChecksum(zeroChecksum)
p.SetChecksum(Checksum(0, p))
}
209 changes: 209 additions & 0 deletions internal/zctcpip/ip.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
package zctcpip

import (
"encoding/binary"
"errors"
"net"
)

type IPProtocol = byte

type IP interface {
Payload() []byte
SourceIP() net.IP
DestinationIP() net.IP
SetSourceIP(ip net.IP)
SetDestinationIP(ip net.IP)
Protocol() IPProtocol
DecTimeToLive()
ResetChecksum()
PseudoSum() uint32
}

// IPProtocol type
const (
ICMP IPProtocol = 0x01
TCP IPProtocol = 0x06
UDP IPProtocol = 0x11
ICMPv6 IPProtocol = 0x3a
)

const (
FlagDontFragment = 1 << 1
FlagMoreFragment = 1 << 2
)

const (
IPv4HeaderSize = 20

IPv4Version = 4

IPv4OptionsOffset = 20
IPv4PacketMinLength = IPv4OptionsOffset
)

var (
ErrInvalidLength = errors.New("invalid packet length")
ErrInvalidIPVersion = errors.New("invalid ip version")
ErrInvalidChecksum = errors.New("invalid checksum")
)

type IPv4Packet []byte

func (p IPv4Packet) TotalLen() uint16 {
return binary.BigEndian.Uint16(p[2:])
}

func (p IPv4Packet) SetTotalLength(length uint16) {
binary.BigEndian.PutUint16(p[2:], length)
}

func (p IPv4Packet) HeaderLen() uint16 {
return uint16(p[0]&0xf) * 4
}

func (p IPv4Packet) SetHeaderLen(length uint16) {
p[0] &= 0xF0
p[0] |= byte(length / 4)
}

func (p IPv4Packet) TypeOfService() byte {
return p[1]
}

func (p IPv4Packet) SetTypeOfService(tos byte) {
p[1] = tos
}

func (p IPv4Packet) Identification() uint16 {
return binary.BigEndian.Uint16(p[4:])
}

func (p IPv4Packet) SetIdentification(id uint16) {
binary.BigEndian.PutUint16(p[4:], id)
}

func (p IPv4Packet) FragmentOffset() uint16 {
return binary.BigEndian.Uint16([]byte{p[6] & 0x7, p[7]}) * 8
}

func (p IPv4Packet) SetFragmentOffset(offset uint32) {
flags := p.Flags()
binary.BigEndian.PutUint16(p[6:], uint16(offset/8))
p.SetFlags(flags)
}

func (p IPv4Packet) DataLen() uint16 {
return p.TotalLen() - p.HeaderLen()
}

func (p IPv4Packet) Payload() []byte {
return p[p.HeaderLen():p.TotalLen()]
}

func (p IPv4Packet) Protocol() IPProtocol {
return p[9]
}

func (p IPv4Packet) SetProtocol(protocol IPProtocol) {
p[9] = protocol
}

func (p IPv4Packet) Flags() byte {
return p[6] >> 5
}

func (p IPv4Packet) SetFlags(flags byte) {
p[6] &= 0x1F
p[6] |= flags << 5
}

func (p IPv4Packet) SourceIP() net.IP {
return net.IPv4(p[12], p[13], p[14], p[15])
}

func (p IPv4Packet) SetSourceIP(ip net.IP) {
if newIP := ip.To4(); newIP != nil {
copy(p[12:16], newIP)
}
}

func (p IPv4Packet) DestinationIP() net.IP {
return net.IPv4(p[16], p[17], p[18], p[19])
}

func (p IPv4Packet) SetDestinationIP(ip net.IP) {
if newIP := ip.To4(); newIP != nil {
copy(p[16:20], newIP)
}
}

func (p IPv4Packet) Checksum() uint16 {
return binary.BigEndian.Uint16(p[10:])
}

func (p IPv4Packet) SetChecksum(sum [2]byte) {
p[10] = sum[0]
p[11] = sum[1]
}

func (p IPv4Packet) TimeToLive() uint8 {
return p[8]
}

func (p IPv4Packet) SetTimeToLive(ttl uint8) {
p[8] = ttl
}

func (p IPv4Packet) DecTimeToLive() {
p[8] = p[8] - uint8(1)
}

func (p IPv4Packet) ResetChecksum() {
p.SetChecksum(zeroChecksum)
p.SetChecksum(Checksum(0, p[:p.HeaderLen()]))
}

// PseudoSum for tcp checksum
func (p IPv4Packet) PseudoSum() uint32 {
sum := Sum(p[12:20])
sum += uint32(p.Protocol())
sum += uint32(p.DataLen())
return sum
}

func (p IPv4Packet) Valid() bool {
return len(p) >= IPv4HeaderSize && p.TotalLen() >= p.HeaderLen() && uint16(len(p)) >= p.TotalLen()
}

func (p IPv4Packet) Verify() error {
if len(p) < IPv4PacketMinLength {
return ErrInvalidLength
}

checksum := []byte{p[10], p[11]}
headerLength := uint16(p[0]&0xF) * 4
packetLength := binary.BigEndian.Uint16(p[2:])

if p[0]>>4 != 4 {
return ErrInvalidIPVersion
}

if uint16(len(p)) < packetLength || packetLength < headerLength {
return ErrInvalidLength
}

p[10] = 0
p[11] = 0
defer copy(p[10:12], checksum)

answer := Checksum(0, p[:headerLength])

if answer[0] != checksum[0] || answer[1] != checksum[1] {
return ErrInvalidChecksum
}

return nil
}

var _ IP = (*IPv4Packet)(nil)
90 changes: 90 additions & 0 deletions internal/zctcpip/tcp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package zctcpip

import (
"encoding/binary"
"net"
)

const (
TCPFin uint16 = 1 << 0
TCPSyn uint16 = 1 << 1
TCPRst uint16 = 1 << 2
TCPPuh uint16 = 1 << 3
TCPAck uint16 = 1 << 4
TCPUrg uint16 = 1 << 5
TCPEce uint16 = 1 << 6
TCPEwr uint16 = 1 << 7
TCPNs uint16 = 1 << 8
)

const TCPHeaderSize = 20

type TCPPacket []byte

func (p TCPPacket) SourcePort() uint16 {
return binary.BigEndian.Uint16(p)
}

func (p TCPPacket) SetSourcePort(port uint16) {
binary.BigEndian.PutUint16(p, port)
}

func (p TCPPacket) DestinationPort() uint16 {
return binary.BigEndian.Uint16(p[2:])
}

func (p TCPPacket) SetDestinationPort(port uint16) {
binary.BigEndian.PutUint16(p[2:], port)
}

func (p TCPPacket) Flags() uint16 {
return uint16(p[13] | (p[12] & 0x1))
}

func (p TCPPacket) Checksum() uint16 {
return binary.BigEndian.Uint16(p[16:])
}

func (p TCPPacket) SetChecksum(sum [2]byte) {
p[16] = sum[0]
p[17] = sum[1]
}

func (p TCPPacket) ResetChecksum(psum uint32) {
p.SetChecksum(zeroChecksum)
p.SetChecksum(Checksum(psum, p))
}

func (p TCPPacket) Valid() bool {
return len(p) >= TCPHeaderSize
}

func (p TCPPacket) Verify(sourceAddress net.IP, targetAddress net.IP) error {
var checksum [2]byte
checksum[0] = p[16]
checksum[1] = p[17]

// reset checksum
p[16] = 0
p[17] = 0

// restore checksum
defer func() {
p[16] = checksum[0]
p[17] = checksum[1]
}()

// check checksum
s := uint32(0)
s += Sum(sourceAddress)
s += Sum(targetAddress)
s += uint32(TCP)
s += uint32(len(p))

check := Checksum(s, p)
if checksum[0] != check[0] || checksum[1] != check[1] {
return ErrInvalidChecksum
}

return nil
}
Loading

0 comments on commit a27fb13

Please sign in to comment.