initial commit
This commit is contained in:
commit
43d20527ba
|
@ -0,0 +1,4 @@
|
|||
# nlup
|
||||
|
||||
nlup is a small domain name lookup utility that interacts
|
||||
directly with the nameserver.
|
|
@ -0,0 +1,143 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
ARecord = 0x0001
|
||||
INClass = 0x0001
|
||||
)
|
||||
|
||||
const DNSPort = 53
|
||||
const Timeout = 2
|
||||
|
||||
type dnsConn struct {
|
||||
net.Conn
|
||||
}
|
||||
|
||||
type header struct {
|
||||
Id, Flags uint16
|
||||
Qdcount uint16
|
||||
Ancount uint16
|
||||
Nscount uint16
|
||||
Arcount uint16
|
||||
}
|
||||
|
||||
type answer struct {
|
||||
Ntype byte
|
||||
Ptr uint16
|
||||
Qtype uint16
|
||||
Class uint16
|
||||
Ttl uint32
|
||||
Addrlen uint16
|
||||
Addr uint32
|
||||
}
|
||||
|
||||
func findNsAddr() (string, error) {
|
||||
conf := []string{
|
||||
"/etc/resolv.conf",
|
||||
}
|
||||
|
||||
for _, i := range conf {
|
||||
f, err := os.Open(i)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
defer f.Close()
|
||||
scanner := bufio.NewScanner(f)
|
||||
|
||||
for scanner.Scan() {
|
||||
s := scanner.Text()
|
||||
|
||||
if s[0] == '#' {
|
||||
continue
|
||||
}
|
||||
|
||||
args := strings.Split(s, " ")
|
||||
if args[0] == "nameserver" && len(args) > 1 {
|
||||
return args[1], nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "", errors.New("nameserver not found")
|
||||
}
|
||||
|
||||
func read(buf *bytes.Buffer, data any) error {
|
||||
return binary.Read(buf, binary.BigEndian, data)
|
||||
}
|
||||
|
||||
func write(buf *bytes.Buffer, data any) error {
|
||||
return binary.Write(buf, binary.BigEndian, data)
|
||||
}
|
||||
|
||||
func writeName(buf *bytes.Buffer, name string) (n int) {
|
||||
for _, i := range strings.Split(name, ".") {
|
||||
buf.WriteByte(byte(len(i)))
|
||||
n++
|
||||
buf.WriteString(i)
|
||||
n += len(i)
|
||||
}
|
||||
|
||||
buf.WriteByte(0)
|
||||
return
|
||||
}
|
||||
|
||||
func dial(server string) (dnsConn, error) {
|
||||
c, err := net.Dial("udp", fmt.Sprintf("%s:%d", server, DNSPort))
|
||||
|
||||
if err == nil {
|
||||
c.SetDeadline(time.Now().Add(Timeout * time.Second))
|
||||
}
|
||||
|
||||
return dnsConn{c}, err
|
||||
}
|
||||
|
||||
func (c dnsConn) sendQuery(name string) (answer, error) {
|
||||
buf := &bytes.Buffer{}
|
||||
ah := &header{}
|
||||
a := &answer{}
|
||||
|
||||
h := header{
|
||||
0x4c3f,
|
||||
1 << 8, // recursion
|
||||
0x0001, // single question
|
||||
0x0000,
|
||||
0x0000,
|
||||
0x0000,
|
||||
}
|
||||
|
||||
write(buf, h)
|
||||
nc := writeName(buf, name)
|
||||
write(buf, []uint16{ARecord, INClass})
|
||||
if _, err := c.Write(buf.Bytes()); err != nil {
|
||||
return *a, err
|
||||
}
|
||||
|
||||
b := make([]byte, 64)
|
||||
if _, err := c.Read(b); err != nil {
|
||||
return *a, err
|
||||
}
|
||||
|
||||
abuf := bytes.NewBuffer(b)
|
||||
read(abuf, ah)
|
||||
abuf.Next(nc + 4)
|
||||
read(abuf, a)
|
||||
|
||||
if a.Addrlen != 4 {
|
||||
return *a, errors.New("invalid name")
|
||||
}
|
||||
|
||||
return *a, nil
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ns := flag.String("n", "", "nameserver to use")
|
||||
v := flag.Bool("v", false, "verbose output")
|
||||
flag.Parse()
|
||||
|
||||
if len(flag.Args()) == 0 {
|
||||
fmt.Printf("usage: %s [-n nameserver] [-v] name\n", os.Args[0])
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if *ns == "" {
|
||||
if s, err := findNsAddr(); err != nil {
|
||||
fmt.Printf("error: %s\n", err)
|
||||
os.Exit(1)
|
||||
} else {
|
||||
*ns = s
|
||||
}
|
||||
}
|
||||
|
||||
name := flag.Arg(0)
|
||||
c, err := dial(*ns)
|
||||
if err != nil {
|
||||
fmt.Printf("error: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
ans, err := c.sendQuery(name)
|
||||
if err != nil {
|
||||
fmt.Printf("error: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if *v {
|
||||
fmt.Printf("nameserver: %s\ntype: %d\nttl: %d\n",
|
||||
*ns, ans.Ntype, ans.Ttl)
|
||||
}
|
||||
|
||||
fmt.Printf("%s: %d.%d.%d.%d\n", name,
|
||||
(ans.Addr>>24)&0xff, (ans.Addr>>16)&0xff, (ans.Addr>>8)&0xff,
|
||||
ans.Addr&0xff)
|
||||
}
|
Loading…
Reference in New Issue