2017-07-26 18:56:24 +08:00
// https://tools.ietf.org/html/rfc1035
2017-07-13 21:55:41 +08:00
package main
import (
"encoding/binary"
"io/ioutil"
"net"
)
2017-07-26 18:56:24 +08:00
// UDPDNSHeaderLen is the length of UDP dns msg header
const UDPDNSHeaderLen = 12
// TCPDNSHEADERLen is the length of TCP dns msg header
const TCPDNSHEADERLen = 2 + UDPDNSHeaderLen
// MaxUDPDNSLen is the max size of udp dns request.
// https://tools.ietf.org/html/rfc1035#section-4.2.1
// Messages carried by UDP are restricted to 512 bytes (not counting the IP
// or UDP headers). Longer messages are truncated and the TC bit is set in
// the header.
// TODO: If the request length > 512 then the client will send TCP packets instead,
// so we should also serve tcp requests.
const MaxUDPDNSLen = 512
2017-07-13 21:55:41 +08:00
type dnstun struct {
Proxy
addr string
raddr string
}
// DNSTunProxy returns a dns forwarder. client -> dns.udp -> glider -> forwarder -> remote dns addr
func DNSTunProxy ( addr , raddr string , upProxy Proxy ) ( Proxy , error ) {
s := & dnstun {
Proxy : upProxy ,
addr : addr ,
raddr : raddr ,
}
return s , nil
}
2017-07-16 12:16:50 +08:00
// ListenAndServe .
2017-07-13 21:55:41 +08:00
func ( s * dnstun ) ListenAndServe ( ) {
l , err := net . ListenPacket ( "udp" , s . addr )
if err != nil {
logf ( "failed to listen on %s: %v" , s . addr , err )
return
}
2017-07-16 12:16:50 +08:00
defer l . Close ( )
2017-07-13 21:55:41 +08:00
logf ( "listening UDP on %s" , s . addr )
for {
2017-07-26 18:56:24 +08:00
data := make ( [ ] byte , MaxUDPDNSLen )
2017-07-13 21:55:41 +08:00
n , clientAddr , err := l . ReadFrom ( data )
if err != nil {
logf ( "DNS local read error: %v" , err )
continue
}
data = data [ : n ]
2017-07-26 18:56:24 +08:00
2017-07-13 21:55:41 +08:00
go func ( ) {
2017-07-26 18:56:24 +08:00
// TODO: check domain rules and get a proper proxy.
domain := getDomain ( data )
2017-07-13 21:55:41 +08:00
rc , err := s . GetProxy ( ) . Dial ( "tcp" , s . raddr )
if err != nil {
logf ( "failed to connect to server %v: %v" , s . raddr , err )
return
}
defer rc . Close ( )
2017-07-26 18:56:24 +08:00
logf ( "proxy-dnstun %s, %s <-> %s" , domain , clientAddr . String ( ) , s . raddr )
2017-07-13 21:55:41 +08:00
// 2 bytes length after tcp header, before dns message
length := make ( [ ] byte , 2 )
binary . BigEndian . PutUint16 ( length , uint16 ( len ( data ) ) )
rc . Write ( length )
rc . Write ( data )
2017-07-16 12:16:50 +08:00
resp , err := ioutil . ReadAll ( rc )
2017-07-13 21:55:41 +08:00
if err != nil {
logf ( "error in ioutil.ReadAll: %s\n" , err )
return
}
// length is not needed in udp dns response. (2 bytes)
// SEE RFC1035, section 4.2.2 TCP: The message is prefixed with a two byte length field which gives the message length, excluding the two byte length field.
2017-07-16 12:16:50 +08:00
if len ( resp ) > 2 {
msg := resp [ 2 : ]
2017-07-13 21:55:41 +08:00
_ , err = l . WriteTo ( msg , clientAddr )
if err != nil {
logf ( "error in local write: %s\n" , err )
}
}
} ( )
}
}
2017-07-26 18:56:24 +08:00
// getDomain from dns request playload, return []byte like:
// []byte{'w', 'w', 'w', '.', 'm', 's', 'n', '.', 'c', 'o', 'm', '.'}
// []byte("www.msn.com.")
func getDomain ( p [ ] byte ) [ ] byte {
var ret [ ] byte
for i := UDPDNSHeaderLen ; i < len ( p ) ; {
l := int ( p [ i ] )
if l == 0 {
break
}
ret = append ( ret , p [ i + 1 : i + l + 1 ] ... )
ret = append ( ret , '.' )
i = i + l + 1
}
return ret
}