网络开发
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(客户端)。消息格式包含:
- 固定头部(240字节):包含操作码、硬件类型、事务ID等基本信息
- 可变选项部分:包含各种DHCP选项,如消息类型、请求的IP地址等
2. DHCP工作流程
DHCP服务端需要处理以下主要消息类型:
- DHCPDISCOVER:客户端广播发现可用服务器
- DHCPOFFER:服务器响应并提供IP地址
- DHCPREQUEST:客户端请求使用特定IP地址
- DHCPACK:服务器确认IP地址分配
3. IP地址管理
服务端需要维护:
- IP地址池:可用IP地址范围
- 租约信息:已分配IP地址的租约时间
- 地址分配策略:确保IP地址不重复分配
4. 关键功能实现
- 消息解析:解析UDP数据包中的DHCP消息
- 地址分配:从地址池中选择可用IP地址
- 租约管理:跟踪IP地址的分配状态和过期时间
- 选项处理:处理各种DHCP选项,如子网掩码、网关等
5. 安全考虑
在实际应用中,还需要考虑:
- 防止IP地址耗尽攻击
- 验证客户端MAC地址
- 限制租约时间
- 日志记录和监控
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)
}