Как использовать Golang для создания необработанного TCP-пакета (используя gopacket) и отправки его через необработанный сокет
Я хотел бы создать обычные TCP-пакеты с использованием gopacket, а затем отправить их с помощью необработанных сокетов.
Вот краткий и понятный пример программы go, которая демонстрирует, что я хотел бы сделать:
package main
import (
"code.google.com/p/gopacket"
"code.google.com/p/gopacket/examples/util"
"code.google.com/p/gopacket/layers"
"log"
"net"
)
func main() {
defer util.Run()()
// XXX create tcp/ip packet
srcIP := net.ParseIP("127.0.0.1")
dstIP := net.ParseIP("192.168.0.1")
//srcIPaddr := net.IPAddr{
// IP: srcIP,
//}
dstIPaddr := net.IPAddr{
IP: dstIP,
}
ipLayer := layers.IPv4{
SrcIP: srcIP,
DstIP: dstIP,
Protocol: layers.IPProtocolTCP,
}
tcpLayer := layers.TCP{
SrcPort: layers.TCPPort(666),
DstPort: layers.TCPPort(22),
SYN: true,
}
tcpLayer.SetNetworkLayerForChecksum(&ipLayer)
buf := gopacket.NewSerializeBuffer()
opts := gopacket.SerializeOptions{
FixLengths: true,
ComputeChecksums: true,
}
err := gopacket.SerializeLayers(buf, opts, &ipLayer, &tcpLayer)
if err != nil {
panic(err)
}
// XXX end of packet creation
// XXX send packet
ipConn, err := net.ListenPacket("ip4:tcp", "0.0.0.0")
if err != nil {
panic(err)
}
_, err = ipConn.WriteTo(buf.Bytes(), &dstIPaddr)
if err != nil {
panic(err)
}
log.Print("packet sent!\n")
}
Однако запуск этой программы не работает... SerializeLayer не удается. Вот такая паника:
паника: неверный IP-адрес источника 127.0.0.1
маршрут 16 [выполняется]: runtime.panic(0x5bb020, 0xc2090723e0) /home/human/golang-empire/go/src/pkg/runtime/panic.c:279 +0xf5 main.main() /home/human/golang-empire/gopkg/src/github.com/david415/HoneyBadger/packetSendTest.go:41 +0x464
программа 19 [ожидание финализатора]: runtime.park(0x413cc0, 0x7bc6c0, 0x7bb189) /home/human/golang-empire/go/src/pkg/runtime/proc.c:1369 +0x89 runtime.parkunlock(0x7bxbb0, 0x9 187) home/human/golang-empire/go/src/pkg/runtime/proc.c:1385 +0x3b runfinq() /home/human/golang-empire/go/src/pkg/runtime/mgc0.c:2644 +0xcf runtime.goexit() /home/human/golang-empire/go/src/pkg/runtime/proc.c:1445
1 ответ
В вашем вопросе написано "craft custom [sic] TCP-пакеты", но ваш код проясняет, что вы также хотите создать собственные заголовки IP уровня 3, и между ними есть разница. Кроме того, вы не упоминаете IPv4 против IPv6, но опять же ваш код кажется специфичным для IPv4.
Учитывая ваш пример кода, я предполагаю, что вы хотите установить полный заголовок IPv4.
Начиная с Go 1.3.3 и скоро выпускаемого Go 1.4, вы не можете делать то, что хотите, используя пакеты Core Go. Чтобы выполнить то, что вы хотите, вам нужно сделать две вещи:
- Вам нужно создать необработанный сокет в Go. В отличие от других неправильных ответов на этом сайте, вы можете создать необработанный сокет в Go, используя один из
net.ListenPacket
,net.DialIP
, или жеnet.ListenIP
,
Например:
conn, err := net.ListenIP("ip4:tcp", netaddr)
if err != nil {
log.Fatalf("ListenIP: %s\n", err)
}
создает необработанный сокет.
- Если вы хотите установить свой собственный заголовок уровня 3 IPv4, вам нужно установить опцию сокета, чтобы включить функциональность.
В вашем вопросе не указано, какую ОС и архитектуру вы используете. На моем ноутбуке работает Mac OS X:
% man ip
. . .
Outgoing packets automatically have an IP header prepended to them
(based on the destination address and the protocol number the socket is created with),
unless the IP_HDRINCL option has been set.
IP_HDRINCL
также доступен в Linux. К сожалению, в Core Go нет способа установить IP_HDRINCL
Опция сокета, и при этом у него нет способа установить другие параметры сокета IP, такие как IP_TTL
, У меня есть набор закрытых патчей, которые активируют эту функцию с Core Go, но это вам не поможет.
Я считаю, что следующий пакет имеет все функции, которые вы хотите ipv4. Обратите внимание, что это большой пакет, и я не использовал его сам. Я сделал grep и он поддерживает IP_HDRINCL
на нескольких платформах. Вы хотите позвонить NewRawConn
создать необработанное соединение, и эта функция создает необработанный сокет и устанавливает IP_HDRINCL
опция сокета.
См. Также здесь: raw-sockets-in-go и код, который он написал здесь, задержка, чтобы получить представление о гораздо более простом подходе, который может удовлетворить ваши потребности, если вы просто хотите установить заголовки TCP. Однако обратите внимание, что этот код не позволяет вам устанавливать IP-адреса в IP-заголовке IPv4, что, как я подозреваю, вы хотите сделать.