网络开发

TCP服务器

使用Go实现TCP服务器。

package main

import (
    "fmt"
    "net"
    "log"
)

func handleConnection(conn net.Conn) {
    defer conn.Close()
    
    buffer := make([]byte, 1024)
    for {
        n, err := conn.Read(buffer)
        if err != nil {
            log.Printf("Error reading: %v", err)
            return
        }
        
        // 处理接收到的数据
        message := string(buffer[:n])
        fmt.Printf("Received: %s", message)
        
        // 发送响应
        response := fmt.Sprintf("Echo: %s", message)
        conn.Write([]byte(response))
    }
}

func main() {
    listener, err := net.Listen("tcp", ":8080")
    if err != nil {
        log.Fatalf("Error listening: %v", err)
    }
    defer listener.Close()
    
    fmt.Println("Server listening on :8080")
    
    for {
        conn, err := listener.Accept()
        if err != nil {
            log.Printf("Error accepting connection: %v", err)
            continue
        }
        
        go handleConnection(conn)
    }
}

UDP服务器

使用Go实现UDP服务器。

package main

import (
    "fmt"
    "net"
    "log"
)

func main() {
    addr := net.UDPAddr{
        Port: 8080,
        IP:   net.ParseIP("0.0.0.0"),
    }
    
    conn, err := net.ListenUDP("udp", &addr)
    if err != nil {
        log.Fatalf("Error listening: %v", err)
    }
    defer conn.Close()
    
    fmt.Println("UDP Server listening on :8080")
    
    buffer := make([]byte, 1024)
    for {
        n, remoteAddr, err := conn.ReadFromUDP(buffer)
        if err != nil {
            log.Printf("Error reading: %v", err)
            continue
        }
        
        message := string(buffer[:n])
        fmt.Printf("Received from %v: %s", remoteAddr, message)
        
        // 发送响应
        response := fmt.Sprintf("Echo: %s", message)
        conn.WriteToUDP([]byte(response), remoteAddr)
    }
}

Ping实现

使用Go实现Ping功能。

package main

import (
    "fmt"
    "net"
    "os"
    "time"
)

func ping(host string) error {
    // 创建ICMP连接
    c, err := net.Dial("ip4:icmp", host)
    if err != nil {
        return err
    }
    defer c.Close()
    
    // 设置超时
    c.SetDeadline(time.Now().Add(5 * time.Second))
    
    // 构造ICMP Echo请求
    msg := []byte{8, 0, 0, 0, 0, 1, 0, 1}
    
    // 发送请求
    start := time.Now()
    _, err = c.Write(msg)
    if err != nil {
        return err
    }
    
    // 接收响应
    reply := make([]byte, 1024)
    _, err = c.Read(reply)
    if err != nil {
        return err
    }
    
    // 计算往返时间
    duration := time.Since(start)
    fmt.Printf("Reply from %s: time=%v\n", host, duration)
    
    return nil
}

func main() {
    if len(os.Args) != 2 {
        fmt.Println("Usage: ping ")
        os.Exit(1)
    }
    
    host := os.Args[1]
    for i := 0; i < 4; i++ {
        err := ping(host)
        if err != nil {
            fmt.Printf("Error: %v\n", err)
        }
        time.Sleep(time.Second)
    }
}

DHCP客户端

使用Go实现DHCP客户端。

package main

import (
    "fmt"
    "net"
    "time"
)

type DHCPMessage struct {
    Op      byte
    Htype   byte
    Hlen    byte
    Hops    byte
    Xid     uint32
    Secs    uint16
    Flags   uint16
    Ciaddr  net.IP
    Yiaddr  net.IP
    Siaddr  net.IP
    Giaddr  net.IP
    Chaddr  []byte
    Sname   []byte
    File    []byte
    Options []byte
}

func sendDHCPDiscover() error {
    // 创建UDP连接
    conn, err := net.Dial("udp", "255.255.255.255:67")
    if err != nil {
        return err
    }
    defer conn.Close()
    
    // 构造DHCP Discover消息
    msg := &DHCPMessage{
        Op:    1, // BOOTREQUEST
        Htype: 1, // Ethernet
        Hlen:  6, // MAC地址长度
        Xid:   uint32(time.Now().Unix()),
        Chaddr: []byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55},
    }
    
    // 发送消息
    _, err = conn.Write(marshalDHCPMessage(msg))
    return err
}

func marshalDHCPMessage(msg *DHCPMessage) []byte {
    // 实现DHCP消息序列化
    // 这里简化处理,实际实现需要完整的DHCP协议支持
    return []byte{}
}

func main() {
    err := sendDHCPDiscover()
    if err != nil {
        fmt.Printf("Error sending DHCP discover: %v\n", err)
        return
    }
    
    fmt.Println("DHCP discover sent")
}

DHCP服务端

使用Go实现DHCP服务端。

实现原理

DHCP(Dynamic Host Configuration Protocol)是一种用于自动分配IP地址的协议。以下是DHCP服务端的主要实现原理:

1. DHCP消息格式

DHCP消息使用UDP协议传输,标准端口为67(服务器)和68(客户端)。消息格式包含:

2. DHCP工作流程

DHCP服务端需要处理以下主要消息类型:

3. IP地址管理

服务端需要维护:

4. 关键功能实现

5. 安全考虑

在实际应用中,还需要考虑:

package main

import (
    "encoding/binary"
    "fmt"
    "log"
    "net"
    "time"
)

const (
    DHCPDISCOVER = 1
    DHCPOFFER    = 2
    DHCPREQUEST  = 3
    DHCPACK      = 5
)

type DHCPMessage struct {
    Op      byte
    Htype   byte
    Hlen    byte
    Hops    byte
    Xid     uint32
    Secs    uint16
    Flags   uint16
    Ciaddr  [4]byte
    Yiaddr  [4]byte
    Siaddr  [4]byte
    Giaddr  [4]byte
    Chaddr  [16]byte
    Sname   [64]byte
    File    [128]byte
    Options []byte
}

type DHCPServer struct {
    serverIP    net.IP
    startIP     net.IP
    endIP       net.IP
    leaseTime   time.Duration
    ipPool      map[string]time.Time
    options     map[byte][]byte
}

func NewDHCPServer(serverIP, startIP, endIP net.IP, leaseTime time.Duration) *DHCPServer {
    return &DHCPServer{
        serverIP:  serverIP,
        startIP:   startIP,
        endIP:     endIP,
        leaseTime: leaseTime,
        ipPool:    make(map[string]time.Time),
        options: map[byte][]byte{
            1:  []byte{255, 255, 255, 0},     // 子网掩码
            3:  serverIP.To4(),               // 路由器
            6:  []byte{8, 8, 8, 8},          // DNS服务器
            51: []byte{0, 0, 0, 60},         // 租约时间(1小时)
        },
    }
}

func (s *DHCPServer) Start() error {
    conn, err := net.ListenUDP("udp4", &net.UDPAddr{
        IP:   net.IPv4(0, 0, 0, 0),
        Port: 67,
    })
    if err != nil {
        return fmt.Errorf("监听UDP端口失败: %v", err)
    }
    defer conn.Close()

    log.Printf("DHCP服务器启动在 %s", conn.LocalAddr())

    for {
        buf := make([]byte, 1024)
        n, addr, err := conn.ReadFromUDP(buf)
        if err != nil {
            log.Printf("读取数据失败: %v", err)
            continue
        }

        msg := &DHCPMessage{}
        if err := s.parseMessage(buf[:n], msg); err != nil {
            log.Printf("解析DHCP消息失败: %v", err)
            continue
        }

        go s.handleMessage(conn, addr, msg)
    }
}

func (s *DHCPServer) parseMessage(data []byte, msg *DHCPMessage) error {
    if len(data) < 240 {
        return fmt.Errorf("消息太短")
    }

    msg.Op = data[0]
    msg.Htype = data[1]
    msg.Hlen = data[2]
    msg.Hops = data[3]
    msg.Xid = binary.BigEndian.Uint32(data[4:8])
    msg.Secs = binary.BigEndian.Uint16(data[8:10])
    msg.Flags = binary.BigEndian.Uint16(data[10:12])
    copy(msg.Ciaddr[:], data[12:16])
    copy(msg.Yiaddr[:], data[16:20])
    copy(msg.Siaddr[:], data[20:24])
    copy(msg.Giaddr[:], data[24:28])
    copy(msg.Chaddr[:], data[28:44])
    copy(msg.Sname[:], data[44:108])
    copy(msg.File[:], data[108:236])
    msg.Options = data[236:]

    return nil
}

func (s *DHCPServer) handleMessage(conn *net.UDPConn, addr *net.UDPAddr, msg *DHCPMessage) {
    switch msg.Options[0] {
    case DHCPDISCOVER:
        s.handleDiscover(conn, addr, msg)
    case DHCPREQUEST:
        s.handleRequest(conn, addr, msg)
    }
}

func (s *DHCPServer) handleDiscover(conn *net.UDPConn, addr *net.UDPAddr, msg *DHCPMessage) {
    // 分配IP地址
    ip := s.allocateIP(msg.Chaddr[:msg.Hlen])
    if ip == nil {
        log.Printf("无法分配IP地址")
        return
    }

    // 构建DHCP OFFER消息
    offer := &DHCPMessage{
        Op:    2, // BOOTREPLY
        Htype: msg.Htype,
        Hlen:  msg.Hlen,
        Xid:   msg.Xid,
        Flags: msg.Flags,
    }
    copy(offer.Yiaddr[:], ip.To4())
    copy(offer.Chaddr[:], msg.Chaddr[:])
    copy(offer.Sname[:], []byte("DHCP Server"))

    // 添加DHCP选项
    options := []byte{53, 1, DHCPOFFER} // 消息类型
    for k, v := range s.options {
        options = append(options, k, byte(len(v)))
        options = append(options, v...)
    }
    options = append(options, 255) // 结束标记
    offer.Options = options

    // 发送OFFER
    if err := s.sendMessage(conn, addr, offer); err != nil {
        log.Printf("发送OFFER失败: %v", err)
    }
}

func (s *DHCPServer) handleRequest(conn *net.UDPConn, addr *net.UDPAddr, msg *DHCPMessage) {
    // 获取请求的IP地址
    var requestedIP net.IP
    for i := 0; i < len(msg.Options); {
        if msg.Options[i] == 50 { // 请求的IP地址
            requestedIP = net.IP(msg.Options[i+2 : i+6])
            break
        }
        i += 2 + int(msg.Options[i+1])
    }

    // 分配IP地址
    ip := s.allocateIP(msg.Chaddr[:msg.Hlen])
    if ip == nil {
        log.Printf("无法分配IP地址")
        return
    }

    // 构建DHCP ACK消息
    ack := &DHCPMessage{
        Op:    2, // BOOTREPLY
        Htype: msg.Htype,
        Hlen:  msg.Hlen,
        Xid:   msg.Xid,
        Flags: msg.Flags,
    }
    copy(ack.Yiaddr[:], ip.To4())
    copy(ack.Chaddr[:], msg.Chaddr[:])
    copy(ack.Sname[:], []byte("DHCP Server"))

    // 添加DHCP选项
    options := []byte{53, 1, DHCPACK} // 消息类型
    for k, v := range s.options {
        options = append(options, k, byte(len(v)))
        options = append(options, v...)
    }
    options = append(options, 255) // 结束标记
    ack.Options = options

    // 发送ACK
    if err := s.sendMessage(conn, addr, ack); err != nil {
        log.Printf("发送ACK失败: %v", err)
    }
}

func (s *DHCPServer) allocateIP(chaddr []byte) net.IP {
    // 检查是否已有分配
    for ip, expiry := range s.ipPool {
        if time.Now().After(expiry) {
            delete(s.ipPool, ip)
        }
    }

    // 分配新IP
    currentIP := make(net.IP, 4)
    copy(currentIP, s.startIP.To4())
    for {
        ipStr := currentIP.String()
        if _, exists := s.ipPool[ipStr]; !exists {
            s.ipPool[ipStr] = time.Now().Add(s.leaseTime)
            return currentIP
        }

        // 增加IP
        for i := len(currentIP) - 1; i >= 0; i-- {
            currentIP[i]++
            if currentIP[i] != 0 {
                break
            }
        }

        // 检查是否超出范围
        if currentIP.Equal(s.endIP) {
            return nil
        }
    }
}

func (s *DHCPServer) sendMessage(conn *net.UDPConn, addr *net.UDPAddr, msg *DHCPMessage) error {
    // 构建消息
    data := make([]byte, 240+len(msg.Options))
    data[0] = msg.Op
    data[1] = msg.Htype
    data[2] = msg.Hlen
    data[3] = msg.Hops
    binary.BigEndian.PutUint32(data[4:8], msg.Xid)
    binary.BigEndian.PutUint16(data[8:10], msg.Secs)
    binary.BigEndian.PutUint16(data[10:12], msg.Flags)
    copy(data[12:16], msg.Ciaddr[:])
    copy(data[16:20], msg.Yiaddr[:])
    copy(data[20:24], msg.Siaddr[:])
    copy(data[24:28], msg.Giaddr[:])
    copy(data[28:44], msg.Chaddr[:])
    copy(data[44:108], msg.Sname[:])
    copy(data[108:236], msg.File[:])
    copy(data[236:], msg.Options)

    // 发送消息
    _, err := conn.WriteToUDP(data, addr)
    return err
}

func main() {
    server := NewDHCPServer(
        net.IPv4(192, 168, 1, 1),    // 服务器IP
        net.IPv4(192, 168, 1, 100),  // 起始IP
        net.IPv4(192, 168, 1, 200),  // 结束IP
        time.Hour,                   // 租约时间
    )

    if err := server.Start(); err != nil {
        log.Fatalf("启动DHCP服务器失败: %v", err)
    }
}

DNS解析

使用Go实现DNS解析。

package main

import (
    "fmt"
    "net"
)

func resolveDNS(hostname string) ([]string, error) {
    ips, err := net.LookupIP(hostname)
    if err != nil {
        return nil, err
    }
    
    var result []string
    for _, ip := range ips {
        result = append(result, ip.String())
    }
    
    return result, nil
}

func reverseDNS(ip string) ([]string, error) {
    names, err := net.LookupAddr(ip)
    if err != nil {
        return nil, err
    }
    
    return names, nil
}

func main() {
    // 正向DNS解析
    hostname := "www.example.com"
    ips, err := resolveDNS(hostname)
    if err != nil {
        fmt.Printf("Error resolving %s: %v\n", hostname, err)
        return
    }
    
    fmt.Printf("IP addresses for %s:\n", hostname)
    for _, ip := range ips {
        fmt.Println(ip)
    }
    
    // 反向DNS解析
    ip := "8.8.8.8"
    names, err := reverseDNS(ip)
    if err != nil {
        fmt.Printf("Error reverse resolving %s: %v\n", ip, err)
        return
    }
    
    fmt.Printf("Hostnames for %s:\n", ip)
    for _, name := range names {
        fmt.Println(name)
    }
}

网络扫描

使用Go实现网络端口扫描。

package main

import (
    "fmt"
    "net"
    "sync"
    "time"
)

func scanPort(host string, port int, wg *sync.WaitGroup) {
    defer wg.Done()
    
    address := fmt.Sprintf("%s:%d", host, port)
    conn, err := net.DialTimeout("tcp", address, time.Second)
    
    if err != nil {
        return
    }
    
    conn.Close()
    fmt.Printf("Port %d is open\n", port)
}

func scanHost(host string, startPort, endPort int) {
    var wg sync.WaitGroup
    
    for port := startPort; port <= endPort; port++ {
        wg.Add(1)
        go scanPort(host, port, &wg)
    }
    
    wg.Wait()
}

func main() {
    host := "localhost"
    startPort := 1
    endPort := 1024
    
    fmt.Printf("Scanning %s from port %d to %d...\n", host, startPort, endPort)
    scanHost(host, startPort, endPort)
}