author | Alberto Bertogli
<albertito@blitiri.com.ar> 2015-09-06 22:06:39 UTC |
committer | Alberto Bertogli
<albertito@blitiri.com.ar> 2015-09-06 22:06:39 UTC |
parent | cea85ab3a8d0aaf3e65af83d7d0b4ebf5f56d3a0 |
.gitignore | +1 | -0 |
dnsproxy.go | +78 | -0 |
dnss.go | +17 | -64 |
dnss.pb.go | +136 | -0 |
dnss.proto | +13 | -0 |
dnstogrpc/dnstogrpc.go | +82 | -0 |
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a01ee28 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.*.swp diff --git a/dnsproxy.go b/dnsproxy.go new file mode 100644 index 0000000..31a06b6 --- /dev/null +++ b/dnsproxy.go @@ -0,0 +1,78 @@ +// Generate the protobuf+grpc service. +//go:generate protoc --go_out=plugins=grpc:. dnss.proto + +package main + +import ( + "fmt" + "strings" + "sync" + + "github.com/miekg/dns" +) + +func questionsToString(qs []dns.Question) string { + var s []string + for _, q := range qs { + s = append(s, fmt.Sprintf("(%s %s %s)", q.Name, + dns.TypeToString[q.Qtype], dns.ClassToString[q.Qclass])) + } + return "Q[" + strings.Join(s, " ") + "]" +} + +func rrsToString(rrs []dns.RR) string { + var s []string + for _, rr := range rrs { + s = append(s, fmt.Sprintf("(%s)", rr)) + } + return "RR[" + strings.Join(s, " ") + "]" + +} + +func L(w dns.ResponseWriter, r *dns.Msg) string { + return fmt.Sprintf("%v %v", w.RemoteAddr(), r.Id) +} + +func Handler(w dns.ResponseWriter, r *dns.Msg) { + fmt.Printf("%v %v\n", L(w, r), questionsToString(r.Question)) + + // TODO: we should create our own IDs, in case different users pick the + // same id and we pass that upstream. + + from_up, err := dns.Exchange(r, "8.8.8.8:53") + if err != nil { + fmt.Printf("%v ERR: %v\n", L(w, r), err) + fmt.Printf("%v UP: %v\n", L(w, r), from_up) + } + + if from_up != nil { + if from_up.Rcode != dns.RcodeSuccess { + rcode := dns.RcodeToString[from_up.Rcode] + fmt.Printf("%v !-> %v\n", L(w, r), rcode) + + } + for _, rr := range from_up.Answer { + fmt.Printf("%v -> %v\n", L(w, r), rr) + } + w.WriteMsg(from_up) + } +} + +func main() { + var wg sync.WaitGroup + wg.Add(1) + go func() { + defer wg.Done() + err := dns.ListenAndServe(":5354", "udp", dns.HandlerFunc(Handler)) + fmt.Printf("Exiting UDP: %v\n", err) + }() + + wg.Add(1) + go func() { + defer wg.Done() + err := dns.ListenAndServe(":5354", "tcp", dns.HandlerFunc(Handler)) + fmt.Printf("Exiting TCP: %v\n", err) + }() + + wg.Wait() +} diff --git a/dnss.go b/dnss.go index 56016d2..ea6df66 100644 --- a/dnss.go +++ b/dnss.go @@ -1,75 +1,28 @@ +// Generate the protobuf+grpc service. +//go:generate protoc --go_out=plugins=grpc:. dnss.proto + package main import ( - "fmt" - "strings" - "sync" + "flag" - "github.com/miekg/dns" + "blitiri.com.ar/go/dnss/dnstogrpc" + "blitiri.com.ar/go/profile" ) -func questionsToString(qs []dns.Question) string { - var s []string - for _, q := range qs { - s = append(s, fmt.Sprintf("(%s %s %s)", q.Name, - dns.TypeToString[q.Qtype], dns.ClassToString[q.Qclass])) - } - return "Q[" + strings.Join(s, " ") + "]" -} - -func rrsToString(rrs []dns.RR) string { - var s []string - for _, rr := range rrs { - s = append(s, fmt.Sprintf("(%s)", rr)) - } - return "RR[" + strings.Join(s, " ") + "]" - -} - -func L(w dns.ResponseWriter, r *dns.Msg) string { - return fmt.Sprintf("%v %v", w.RemoteAddr(), r.Id) -} - -func Handler(w dns.ResponseWriter, r *dns.Msg) { - fmt.Printf("%v %v\n", L(w, r), questionsToString(r.Question)) - - // TODO: we should create our own IDs, in case different users pick the - // same id and we pass that upstream. - - from_up, err := dns.Exchange(r, "8.8.8.8:53") - if err != nil { - fmt.Printf("%v ERR: %v\n", L(w, r), err) - fmt.Printf("%v UP: %v\n", L(w, r), from_up) - } - - if from_up != nil { - if from_up.Rcode != dns.RcodeSuccess { - rcode := dns.RcodeToString[from_up.Rcode] - fmt.Printf("%v !-> %v\n", L(w, r), rcode) - - } - for _, rr := range from_up.Answer { - fmt.Printf("%v -> %v\n", L(w, r), rr) - } - w.WriteMsg(from_up) - } -} +var ( + dnsaddr = flag.String("dnsaddr", ":53", "address to listen on") + dnsupstream = flag.String("dnsupstream", "8.8.8.8:53", "upstream address") +) func main() { - var wg sync.WaitGroup - wg.Add(1) - go func() { - defer wg.Done() - err := dns.ListenAndServe(":5354", "udp", dns.HandlerFunc(Handler)) - fmt.Printf("Exiting UDP: %v\n", err) - }() + flag.Parse() - wg.Add(1) - go func() { - defer wg.Done() - err := dns.ListenAndServe(":5354", "tcp", dns.HandlerFunc(Handler)) - fmt.Printf("Exiting TCP: %v\n", err) - }() + profile.Init() - wg.Wait() + dtg := &dnstogrpc.Server{ + Addr: *dnsaddr, + Upstream: *dnsupstream, + } + dtg.ListenAndServe() } diff --git a/dnss.pb.go b/dnss.pb.go new file mode 100644 index 0000000..0ffc7ba --- /dev/null +++ b/dnss.pb.go @@ -0,0 +1,136 @@ +// Code generated by protoc-gen-go. +// source: dnss.proto +// DO NOT EDIT! + +/* +Package dnss is a generated protocol buffer package. + +It is generated from these files: + dnss.proto + +It has these top-level messages: + GobMsg +*/ +package dnss + +import proto "github.com/golang/protobuf/proto" + +import ( + context "golang.org/x/net/context" + grpc "google.golang.org/grpc" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal + +type GobMsg struct { + // gob-encoded message. + // A horrible hack, but will do for now. + Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` +} + +func (m *GobMsg) Reset() { *m = GobMsg{} } +func (m *GobMsg) String() string { return proto.CompactTextString(m) } +func (*GobMsg) ProtoMessage() {} + +func init() { +} + +// Client API for DNSService service + +type DNSServiceClient interface { + Query(ctx context.Context, opts ...grpc.CallOption) (DNSService_QueryClient, error) +} + +type dNSServiceClient struct { + cc *grpc.ClientConn +} + +func NewDNSServiceClient(cc *grpc.ClientConn) DNSServiceClient { + return &dNSServiceClient{cc} +} + +func (c *dNSServiceClient) Query(ctx context.Context, opts ...grpc.CallOption) (DNSService_QueryClient, error) { + stream, err := grpc.NewClientStream(ctx, &_DNSService_serviceDesc.Streams[0], c.cc, "/.DNSService/Query", opts...) + if err != nil { + return nil, err + } + x := &dNSServiceQueryClient{stream} + return x, nil +} + +type DNSService_QueryClient interface { + Send(*GobMsg) error + Recv() (*GobMsg, error) + grpc.ClientStream +} + +type dNSServiceQueryClient struct { + grpc.ClientStream +} + +func (x *dNSServiceQueryClient) Send(m *GobMsg) error { + return x.ClientStream.SendProto(m) +} + +func (x *dNSServiceQueryClient) Recv() (*GobMsg, error) { + m := new(GobMsg) + if err := x.ClientStream.RecvProto(m); err != nil { + return nil, err + } + return m, nil +} + +// Server API for DNSService service + +type DNSServiceServer interface { + Query(DNSService_QueryServer) error +} + +func RegisterDNSServiceServer(s *grpc.Server, srv DNSServiceServer) { + s.RegisterService(&_DNSService_serviceDesc, srv) +} + +func _DNSService_Query_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(DNSServiceServer).Query(&dNSServiceQueryServer{stream}) +} + +type DNSService_QueryServer interface { + Send(*GobMsg) error + Recv() (*GobMsg, error) + grpc.ServerStream +} + +type dNSServiceQueryServer struct { + grpc.ServerStream +} + +func (x *dNSServiceQueryServer) Send(m *GobMsg) error { + return x.ServerStream.SendProto(m) +} + +func (x *dNSServiceQueryServer) Recv() (*GobMsg, error) { + m := new(GobMsg) + if err := x.ServerStream.RecvProto(m); err != nil { + return nil, err + } + return m, nil +} + +var _DNSService_serviceDesc = grpc.ServiceDesc{ + ServiceName: ".DNSService", + HandlerType: (*DNSServiceServer)(nil), + Methods: []grpc.MethodDesc{}, + Streams: []grpc.StreamDesc{ + { + StreamName: "Query", + Handler: _DNSService_Query_Handler, + ServerStreams: true, + ClientStreams: true, + }, + }, +} diff --git a/dnss.proto b/dnss.proto new file mode 100644 index 0000000..92d204c --- /dev/null +++ b/dnss.proto @@ -0,0 +1,13 @@ + +syntax = "proto3"; + +message GobMsg { + // gob-encoded message. + // A horrible hack, but will do for now. + bytes data = 1; +} + +service DNSService { + rpc Query(stream GobMsg) returns (stream GobMsg); +} + diff --git a/dnstogrpc/dnstogrpc.go b/dnstogrpc/dnstogrpc.go new file mode 100644 index 0000000..ced0d05 --- /dev/null +++ b/dnstogrpc/dnstogrpc.go @@ -0,0 +1,82 @@ +// DNS to GRPC. + +package dnstogrpc + +import ( + "fmt" + "strings" + "sync" + + "github.com/miekg/dns" +) + +func questionsToString(qs []dns.Question) string { + var s []string + for _, q := range qs { + s = append(s, fmt.Sprintf("(%s %s %s)", q.Name, + dns.TypeToString[q.Qtype], dns.ClassToString[q.Qclass])) + } + return "Q[" + strings.Join(s, " ") + "]" +} + +func rrsToString(rrs []dns.RR) string { + var s []string + for _, rr := range rrs { + s = append(s, fmt.Sprintf("(%s)", rr)) + } + return "RR[" + strings.Join(s, " ") + "]" + +} + +func l(w dns.ResponseWriter, r *dns.Msg) string { + return fmt.Sprintf("%v %v", w.RemoteAddr(), r.Id) +} + +type Server struct { + Addr string + Upstream string +} + +func (s *Server) Handler(w dns.ResponseWriter, r *dns.Msg) { + fmt.Printf("%v %v\n", l(w, r), questionsToString(r.Question)) + + // TODO: we should create our own IDs, in case different users pick the + // same id and we pass that upstream. + + from_up, err := dns.Exchange(r, s.Upstream) + if err != nil { + fmt.Printf("%v ERR: %v\n", l(w, r), err) + fmt.Printf("%v UP: %v\n", l(w, r), from_up) + } + + if from_up != nil { + if from_up.Rcode != dns.RcodeSuccess { + rcode := dns.RcodeToString[from_up.Rcode] + fmt.Printf("%v !-> %v\n", l(w, r), rcode) + + } + for _, rr := range from_up.Answer { + fmt.Printf("%v -> %v\n", l(w, r), rr) + } + w.WriteMsg(from_up) + } +} + +func (s *Server) ListenAndServe() { + var wg sync.WaitGroup + wg.Add(1) + go func() { + defer wg.Done() + err := dns.ListenAndServe(s.Addr, "udp", dns.HandlerFunc(s.Handler)) + fmt.Printf("Exiting UDP: %v\n", err) + }() + + wg.Add(1) + go func() { + defer wg.Done() + err := dns.ListenAndServe(s.Addr, "tcp", dns.HandlerFunc(s.Handler)) + fmt.Printf("Exiting TCP: %v\n", err) + }() + + wg.Wait() +}