New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adding DNS header #587
base: master
Are you sure you want to change the base?
Adding DNS header #587
Conversation
I love the idea of adding a DNS mode but I have some concerns about this implementation - using Maybe we should consider adding a new field in config to provide arguments to fake protocols like this? |
It would be better for sure. But I met difficulty in implementing it, the type of function won't match after adding a new parameter... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
package dns
import (
"encoding/binary"
"math/rand"
"net"
"os"
"sync"
"syscall"
"time"
"github.com/miekg/dns"
)
const udpBufferSize = 4096
type DnsUDPPacketConn struct {
orig *net.UDPConn
readBuf []byte
writeBuf []byte
header []byte
readMutex sync.RWMutex
}
func NewDnsUDPConn(orig *net.UDPConn, domain string) *DnsUDPPacketConn {
header := make([]byte, 0, 512)
header = append(header, 0, 0) // Transaction ID (placeholder)
header = append(header, 0x01, 0x00) // Flags: Standard query
header = append(header, 0x00, 0x01) // Questions
header = append(header, 0x00, 0x00, 0x00, 0x00) // Answer RRs, Authority RRs, Additional RRs
buf := make([]byte, 256)
off1, err := dns.PackDomainName(dns.Fqdn(domain), buf, 0, nil, false)
if err != nil {
return nil
}
header = append(header, buf[:off1]...)
header = append(header, 0x00, 0x01, 0x00, 0x01) // Type: A, Class: IN
return &DnsUDPPacketConn{
orig: orig,
readBuf: make([]byte, udpBufferSize),
writeBuf: make([]byte, udpBufferSize),
header: header,
}
}
func (c *DnsUDPPacketConn) ReadFrom(p []byte) (int, net.Addr, error) {
for {
c.readMutex.RLock()
n, addr, err := c.orig.ReadFrom(c.readBuf)
if n <= len(c.header) {
c.readMutex.RUnlock()
return 0, addr, err
}
newN := copy(p, c.readBuf[len(c.header):n])
c.readMutex.RUnlock()
if newN > 0 {
// Valid packet
return newN, addr, err
} else if err != nil {
// Not valid and orig.ReadFrom had some error
return 0, addr, err
}
}
}
func (c *DnsUDPPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
c.readMutex.Lock()
defer c.readMutex.Unlock()
copy(c.writeBuf, c.header)
binary.BigEndian.PutUint16(c.writeBuf, uint16(rand.Uint32()))
bn := copy(c.writeBuf[len(c.header):], p)
_, err = c.orig.WriteTo(c.writeBuf[:len(c.header)+bn], addr)
if err != nil {
return 0, err
}
return len(p), nil
}
func (c *DnsUDPPacketConn) Close() error {
return c.orig.Close()
}
func (c *DnsUDPPacketConn) LocalAddr() net.Addr {
return c.orig.LocalAddr()
}
func (c *DnsUDPPacketConn) SetDeadline(t time.Time) error {
return c.orig.SetDeadline(t)
}
func (c *DnsUDPPacketConn) SetReadDeadline(t time.Time) error {
return c.orig.SetReadDeadline(t)
}
func (c *DnsUDPPacketConn) SetWriteDeadline(t time.Time) error {
return c.orig.SetWriteDeadline(t)
}
func (c *DnsUDPPacketConn) SetReadBuffer(bytes int) error {
return c.orig.SetReadBuffer(bytes)
}
func (c *DnsUDPPacketConn) SetWriteBuffer(bytes int) error {
return c.orig.SetWriteBuffer(bytes)
}
func (c *DnsUDPPacketConn) SyscallConn() (syscall.RawConn, error) {
return c.orig.SyscallConn()
}
func (c *DnsUDPPacketConn) File() (f *os.File, err error) {
return c.orig.File()
}
The main changes made to the code are:
-
The
readBuf
andwriteBuf
slices are now reused across multiple calls toNewDnsUDPConn
, reducing memory allocations. -
The
sync.Mutex
has been replaced with async.RWMutex
to allow concurrent read operations while protecting write operations. -
In the
ReadFrom
method, the code now directly returns a slice pointing to the data inc.readBuf
, avoiding unnecessary copying. -
In the
WriteTo
method, the transaction ID is now directly assigned to thec.writeBuf
slice, avoiding the use ofbinary.BigEndian.PutUint16
. -
The
writeMutex
has been removed, and thereadMutex
is used to protect both read and write operations.
Mostly copied from Xray-core's DNS header, useful for bypassing school network's login.