create a udp proxy that injects the proxy protocol from haproxy in go

Here's an example code snippet that uses gopacket library to intercept and relay UDP packets while injecting the HAPROXY protocol header:

main.go
package main

import (
	"log"
	"net"
	"os"

	"github.com/google/gopacket"
	"github.com/google/gopacket/layers"
	"github.com/google/gopacket/pcap"
)

func main() {

	if len(os.Args) < 4 {
		log.Fatalf("USAGE: %s <interface> <haproxy-server> <haproxy-port>", os.Args[0])
	}

	iface := os.Args[1]
	haproxyServer := os.Args[2]
	haproxyPort := os.Args[3]

	handle, err := pcap.OpenLive(iface, 1500, true, pcap.BlockForever)
	if err != nil {
		log.Fatal(err)
	}
	defer handle.Close()

	err = handle.SetBPFFilter("udp and dst port " + haproxyPort)
	if err != nil {
		log.Fatal(err)
	}

	packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
	for packet := range packetSource.Packets() {
		udpLayer := packet.Layer(layers.LayerTypeUDP)
		if udpLayer == nil {
			continue
		}
		udp, _ := udpLayer.(*layers.UDP)
		if udp.DstPort != layers.UDPPort(haproxyPort) {
			continue
		}

		ipLayer := packet.Layer(layers.LayerTypeIPv4)
		if ipLayer == nil {
			continue
		}
		ip, _ := ipLayer.(*layers.IPv4)

		ethernetLayer := packet.Layer(layers.LayerTypeEthernet)
		if ethernetLayer == nil {
			continue
		}
		ethernetPacket, _ := ethernetLayer.(*layers.Ethernet)

		srcAddr := &net.IPAddr{IP: ip.SrcIP}
		dstAddr := &net.UDPAddr{IP: ip.DstIP, Port: int(udp.DstPort)}

		conn, err := net.DialUDP("udp", nil, dstAddr)
		if err != nil {
			log.Println("ERROR", err)
			continue
		}
		defer conn.Close()

		haproxyHeader := []byte{
			0x01,       // protocol version
			0x01,       // command
			0x00, 0x08, // payload length
			0x0d, 0x0a, // CRLF
			0x51, 0x55, 0x49, 0x54, 0x0a, // "QUIT\n"
		}

		conn.Write(haproxyHeader)

		go func() {
			buffer := make([]byte, 1024)
			for {
				n, _, err := conn.ReadFromUDP(buffer)
				if err != nil {
					return
				}
				log.Printf("[%s] %s\n", srcAddr.String(), buffer[:n])
			}
		}()
		log.Printf("[%s -> %s] %s", srcAddr.String(), dstAddr.String(), udp.Payload)
		conn.Write(udp.Payload)
	}
}
1937 chars
91 lines

Note: This is a basic example, and you may want to customize it based on your specific use case.

related categories

gistlibby LogSnag