github.com/geph-official/geph2@v0.22.6-0.20210211030601-f527cb59b0df/cmd/geph-client/dnsproxy.go (about)

     1  package main
     2  
     3  import (
     4  	"encoding/base64"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"math/rand"
     8  	"net"
     9  	"net/http"
    10  	"strings"
    11  	"sync"
    12  	"time"
    13  
    14  	log "github.com/sirupsen/logrus"
    15  
    16  	"github.com/miekg/dns"
    17  	"golang.org/x/net/proxy"
    18  )
    19  
    20  func doDNS() {
    21  	log.Println("DNS on", dnsAddr)
    22  	if fakeDNS {
    23  		doDNSFaker()
    24  	} else {
    25  		doDNSProxy()
    26  	}
    27  }
    28  
    29  func doDNSProxy() {
    30  	tunProx, err := proxy.SOCKS5("tcp", socksAddr, nil, proxy.Direct)
    31  	if err != nil {
    32  		panic(err)
    33  	}
    34  	hclient := &http.Client{
    35  		Transport: &http.Transport{
    36  			Dial:            tunProx.Dial,
    37  			IdleConnTimeout: time.Minute * 30,
    38  		},
    39  	}
    40  	socket, err := net.ListenPacket("udp", dnsAddr)
    41  	if err != nil {
    42  		panic(err)
    43  	}
    44  	log.Println("DNS listening at", socket.LocalAddr())
    45  	reqbuf := make([]byte, 512)
    46  	for {
    47  		n, addr, err := socket.ReadFrom(reqbuf)
    48  		if err != nil {
    49  			panic(err)
    50  		}
    51  		smabuf := make([]byte, n)
    52  		copy(smabuf, reqbuf)
    53  		go func() {
    54  			burl := base64.RawURLEncoding.EncodeToString(smabuf)
    55  			rsp, err := hclient.Get("https://cloudflare-dns.com/dns-query?dns=" + burl)
    56  			if err != nil {
    57  				return
    58  			}
    59  			response, err := ioutil.ReadAll(rsp.Body)
    60  			if err != nil {
    61  				log.Println("error from Cloudflare reader:", err)
    62  				return
    63  			}
    64  			socket.WriteTo(response, addr)
    65  		}()
    66  	}
    67  }
    68  
    69  func doDNSFaker() {
    70  	// our server
    71  	serv := &dns.Server{
    72  		Net:  "udp",
    73  		Addr: dnsAddr,
    74  		Handler: dns.HandlerFunc(func(w dns.ResponseWriter, r *dns.Msg) {
    75  			q := r.Question[0]
    76  			// we can't do anything if not A or CNAME
    77  			if q.Qtype == dns.TypeA || q.Qtype == dns.TypeCNAME {
    78  				ans := nameToFakeIP(q.Name)
    79  				ip, _ := net.ResolveIPAddr("ip4", ans)
    80  				m := new(dns.Msg)
    81  				m.SetReply(r)
    82  				m.Answer = append(m.Answer, &dns.A{
    83  					Hdr: dns.RR_Header{
    84  						Name:   q.Name,
    85  						Rrtype: dns.TypeA,
    86  						Class:  dns.ClassINET,
    87  						Ttl:    1,
    88  					},
    89  					A: ip.IP,
    90  				})
    91  				w.WriteMsg(m)
    92  			} else if q.Qtype == dns.TypeAAAA {
    93  				// we claim that we don't have AAAA records
    94  				m := new(dns.Msg)
    95  				m.SetReply(r)
    96  				w.WriteMsg(m)
    97  			}
    98  			dns.HandleFailed(w, r)
    99  		}),
   100  	}
   101  	err := serv.ListenAndServe()
   102  	if err != nil {
   103  		log.Println("Uh oh!")
   104  		panic(err.Error())
   105  	}
   106  }
   107  
   108  var fakeIPCache struct {
   109  	mapping map[string]string
   110  	revmap  map[string]string
   111  	lock    sync.Mutex
   112  }
   113  
   114  func init() {
   115  	fakeIPCache.mapping = make(map[string]string)
   116  	fakeIPCache.revmap = make(map[string]string)
   117  }
   118  
   119  func nameToFakeIP(name string) string {
   120  	fakeIPCache.lock.Lock()
   121  	defer fakeIPCache.lock.Unlock()
   122  	if fakeIPCache.mapping[name] != "" {
   123  		return fakeIPCache.mapping[name]
   124  	}
   125  	genFakeIP := func() string {
   126  		return fmt.Sprintf("100.%v.%v.%v", rand.Int()%64+64, rand.Int()%256, rand.Int()%256)
   127  	}
   128  	// find an unallocated name
   129  	retval := genFakeIP()
   130  	for fakeIPCache.revmap[retval] != "" {
   131  		retval = genFakeIP()
   132  	}
   133  	log.Debugf("mapped fake IP %v => %v", retval, name)
   134  	fakeIPCache.revmap[retval] = strings.Trim(name, ".")
   135  	fakeIPCache.mapping[name] = retval
   136  	return retval
   137  }
   138  
   139  func fakeIPToName(ip string) string {
   140  	fakeIPCache.lock.Lock()
   141  	defer fakeIPCache.lock.Unlock()
   142  	return fakeIPCache.revmap[ip]
   143  }