Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
yinxulai committed Mar 6, 2024
1 parent 0b4d3cd commit 1f30910
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 41 deletions.
20 changes: 20 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
// 使用 IntelliSense 了解相关属性。
// 悬停以查看现有属性的描述。
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Launch file",
"type": "go",
"request": "launch",
"mode": "debug",
"env": {
"DOMAIN": "example.com"
},
"program": "main.go",
"console": "integratedTerminal",
"asRoot": true
}
]
}
12 changes: 2 additions & 10 deletions main.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package main

import (
"fmt"
"log"
"os"

"github.com/yinxulai/lookup-dns-ip/packages/dnsserver"
Expand All @@ -11,12 +9,6 @@ import (

func main() {
domain := os.Getenv("DOMAIN")
if domain == "" {
err := fmt.Errorf("%s is not configured with the correct dns record", domain)
log.Fatal(err)
panic(err)
}

dnsserver.StartServer(domain, 8080)
httpserver.StartServer(domain, 8081)
go dnsserver.StartServer(domain, 53)
httpserver.StartServer(domain, 53)
}
8 changes: 7 additions & 1 deletion packages/cache/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,16 @@ package cache
import "sync"

var mu sync.Mutex
var globalCache map[string]string
var globalCache = make(map[string]string)

func GetCache(id string) (string, bool) {
value, ok := globalCache[id]

mu.Lock()
// 查一次就删掉
delete(globalCache, id)
mu.Unlock()

return value, ok
}

Expand Down
70 changes: 47 additions & 23 deletions packages/dnsserver/dnsserver.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package dnsserver

import (
"encoding/binary"
"fmt"
"log"
"net"
Expand All @@ -10,9 +11,14 @@ import (
)

func StartServer(domain string, port int) {
// DNS 系统中域名都以 . 结尾
if !strings.HasSuffix(domain, ".") {
domain = domain + "."
}

serverIPs, err := net.LookupIP(domain)
if err != nil || len(serverIPs) == 0 {
log.Fatalf("%s is not configured with the correct dns record", domain)
log.Printf("%s is not configured with the correct dns record", domain)
}

// 创建UDP监听地址
Expand All @@ -28,7 +34,7 @@ func StartServer(domain string, port int) {
}
defer conn.Close()

log.Println("DNS server started on port 53")
log.Printf("DNS server started on port %d", port)

buffer := make([]byte, 512)
for {
Expand Down Expand Up @@ -58,7 +64,7 @@ func StartServer(domain string, port int) {
}

// 构建响应报文
response := buildDNSResponse(question.Name, serverIPs[0].String())
response := buildDNSResponse(question, "127.0.0.1")

// 发送响应报文
_, err := conn.WriteToUDP(response, clientAddr)
Expand All @@ -75,36 +81,58 @@ func StartServer(domain string, port int) {
// 解析DNS请求报文中的问题部分
func parseDNSQuestion(data []byte) (*dnsQuestion, error) {
var question dnsQuestion

var headerOffset = 12
// 解析域名
domainName, _, err := parseDomainName(data, 12)
domainName, _, err := parseDomainName(data, headerOffset)
if err != nil {
return nil, fmt.Errorf("failed to parse domain name: %w", err)
}

// 解析问题的类型和类
offset := headerOffset + len(domainName)
if len(data) < offset+4 {
return nil, fmt.Errorf("invalid DNS question data")
}

// 解析类型和类
question.Name = domainName
question.Type = uint16(data[len(data)-4])<<8 | uint16(data[len(data)-3])
question.Class = uint16(data[len(data)-2])<<8 | uint16(data[len(data)-1])
question.ID = binary.BigEndian.Uint16(data[0:2])
question.Type = binary.BigEndian.Uint16(data[offset+1 : offset+3])
question.Class = binary.BigEndian.Uint16(data[offset+3 : offset+5])

return &question, nil
}

// 构建DNS响应报文
func buildDNSResponse(name string, ip string) []byte {
func buildDNSResponse(requestQuestion *dnsQuestion, ip string) []byte {
// 构建报文头部
header := make([]byte, 12)
header[1] = 0x81 // 设置标志位为响应报文
header[3] = 0x01 // 设置问题数为1
header[0] = byte(requestQuestion.ID >> 8)
header[1] = byte(requestQuestion.ID)
header[2] = 0x81 // 设置标志位为响应报文

header[5] = 0x01 // 设置问题数为 1
header[7] = 0x01 // 设置回答数为 1
header[9] = 0x00 // 设置 Authority RRs 数为 0
header[11] = 0x00 // 设置 Additional RRs 数为 0

// 构建问题部分
question, _ := buildDNSQuestion(name, dnsTypeA, dnsClassIN)
responseQuestion, _ := buildDNSQuestion(
requestQuestion.Name,
requestQuestion.Type,
requestQuestion.Class,
)

// 构建回答部分
answer, _ := buildDNSAnswer(name, dnsTypeA, dnsClassIN, 5, ip)
answer, _ := buildDNSAnswer(
requestQuestion.Type,
requestQuestion.Class,
5, // ttl
ip,
)

// 拼接报文头部、问题部分和回答部分
response := append(header, question...)
response := append(header, responseQuestion...)
response = append(response, answer...)

return response
Expand All @@ -130,12 +158,9 @@ func buildDNSQuestion(name string, qType uint16, qClass uint16) ([]byte, error)
}

// 构建DNS回答部分
func buildDNSAnswer(name string, aType uint16, aClass uint16, ttl uint32, ip string) ([]byte, error) {
// 构建域名
domainName, err := buildDomainName(name)
if err != nil {
return nil, fmt.Errorf("failed to build domain name: %w", err)
}
func buildDNSAnswer(aType uint16, aClass uint16, ttl uint32, ip string) ([]byte, error) {
// 域名指针
domain := []byte{0xc0, 0x0c}

// 构建类型和类
aTypeBytes := []byte{byte(aType >> 8), byte(aType)}
Expand All @@ -149,14 +174,14 @@ func buildDNSAnswer(name string, aType uint16, aClass uint16, ttl uint32, ip str
byte(ttl),
}

// 构建数据```go
// 构建数据
ipBytes := net.ParseIP(ip).To4()

// 构建数据长度
dataLength := []byte{0x00, 0x04}

// 拼接域名、类型、类、TTL、数据长度和数据
answer := append(domainName, aTypeBytes...)
answer := append(domain, aTypeBytes...)
answer = append(answer, aClassBytes...)
answer = append(answer, ttlBytes...)
answer = append(answer, dataLength...)
Expand Down Expand Up @@ -189,8 +214,6 @@ func buildDomainName(name string) ([]byte, error) {
domainName = append(domainName, []byte(l)...)
}

domainName = append(domainName, 0x00)

return domainName, nil
}

Expand Down Expand Up @@ -230,6 +253,7 @@ func parseDomainName(data []byte, offset int) (string, int, error) {

// DNS请求报文中的问题部分
type dnsQuestion struct {
ID uint16
Name string
Type uint16
Class uint16
Expand Down
15 changes: 8 additions & 7 deletions packages/httpserver/httpserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ import (
func StartServer(domain string, port int) {
// 注册请求处理函数
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
requestHostname := r.URL.Hostname()
requestHost := r.Host

// 请求不是来自设定的域名,直接报错,不进行处理
if !strings.HasSuffix(requestHostname, domain) {
if !strings.HasSuffix(requestHost, domain) {
err := fmt.Errorf("only supports access using %s domain name", domain)
http.Error(w, err.Error(), http.StatusBadRequest)
return
Expand All @@ -31,7 +31,7 @@ func StartServer(domain string, port int) {
// http-server 将 dns-server 记录的 remote ip 返回

// 如果直接访问 domain
if requestHostname == domain {
if requestHost == domain {
subdomain, err := generateRandomSubDomain(domain)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
Expand All @@ -42,8 +42,8 @@ func StartServer(domain string, port int) {
}

// 如果是子域名访问
if strings.HasSuffix(requestHostname, "."+domain) {
id, _ := strings.CutSuffix(requestHostname, "."+domain)
if strings.HasSuffix(requestHost, "."+domain) {
id, _ := strings.CutSuffix(requestHost, "."+domain)
ip, exits := cache.GetCache(id)

if !exits {
Expand All @@ -60,8 +60,9 @@ func StartServer(domain string, port int) {
})

// 启动 HTTP 服务,监听在端口808
log.Println("start the server on port 8080")
err := http.ListenAndServe(":8080", nil)
listenAddr := fmt.Sprintf(":%d", port)
log.Printf("HTTP server started on port %d", port)
err := http.ListenAndServe(listenAddr, nil)
if err != nil {
log.Fatal("Failed to start the server:", err)
}
Expand Down

0 comments on commit 1f30910

Please sign in to comment.