1

I am trying to send raw TCP packet with custom Ethernet header through raw socket in Go language. I am trying to reproduce similar code in c language.

package main

import (
    "fmt"
    "syscall"
)

func main() {

    fmt.Println("=============================================================================")
    fmt.Println("= Start sending                                                             =")
    fmt.Println("=============================================================================")

    pkt := []byte{
        0x6c, 0x62, 0x6d, 0x50, 0xe6, 0xe4, 0x94, 0xde, 0x80, 0xa5, 0xec, 0x79, 0x08, 0x00, 0x45, 0x00,
        0x00, 0x3c, 0x47, 0xd9, 0x40, 0x00, 0x40, 0x06, 0xb5, 0x94, 0xc0, 0xa8, 0x34, 0x7b, 0x36, 0xe7,
        0x11, 0x44, 0xc3, 0x66, 0x00, 0x50, 0x09, 0x58, 0x6b, 0xeb, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02,
        0x72, 0x10, 0x26, 0x38, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x0d, 0x3d,
        0x2c, 0x32, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x07,
    }

    fd, err := syscall.Socket(syscall.AF_PACKET, syscall.SOCK_RAW, syscall.ETH_P_ALL)
    if err != nil {
        fmt.Println("=============================================================================")
        fmt.Println("= Error 1                                                                   =")
        fmt.Println("=============================================================================")
        fmt.Println(err)
    }

    addr := syscall.SockaddrInet4{
        Port: 0,
        Addr: [4]byte{127, 0, 0, 1},
    }

    err = syscall.Bind(fd, &addr)
    if err != nil {
        fmt.Println("=============================================================================")
        fmt.Println("= Error 2                                                                   =")
        fmt.Println("=============================================================================")
        fmt.Println(err)
    }

    err = syscall.SetLsfPromisc("eth0", true)
    if err != nil {
        fmt.Println("=============================================================================")
        fmt.Println("= Error 3                                                                   =")
        fmt.Println("=============================================================================")
        fmt.Println(err)
    }

    n, err := syscall.Write(fd, pkt)
    if err != nil {
        fmt.Println("=============================================================================")
        fmt.Println("= Error 4                                                                   =")
        fmt.Println("=============================================================================")
        fmt.Println(err)
        fmt.Println(n)
    } else {
        fmt.Println("=============================================================================")
        fmt.Println("= Packet is sent                                                            =")
        fmt.Println("=============================================================================")
        fmt.Println(n)
    }
}

However I am getting following error:

=============================================================================
= Start sending                                                             =
=============================================================================
=============================================================================
= Error 2                                                                   =
=============================================================================
invalid argument
=============================================================================
= Error 4                                                                   =
=============================================================================
no such device or address
-1

Please guide me if you have any knowledge.

Khamidulla
  • 2,927
  • 6
  • 35
  • 59
  • Have you tried using the standard library for making connections? Like the [net](https://golang.org/pkg/net/) package or the [crypto/tls](https://golang.org/pkg/crypto/tls/) package? They both have a `Dial` method that does raw TCP. – sargas Mar 08 '16 at 00:01
  • @sargas Thank you for replay. Yes I did use Dial method. However I need to change Ethernet part as well. Not only IP layer. – Khamidulla Mar 08 '16 at 00:12

2 Answers2

0

What you want to accomplish is more complicated.

  1. You cannot use the kernels bind syscall to bind to a raw socket: err = syscall.Bind(fd, &addr)
  2. You want to write ethernet frames to the raw socket. In order to do so you need to assemble the ethernet frame and TCP header yourself. The whole point of using a raw socket on that level is not having the kernel do this for you.

Some working examples in C can be found here. They are probably easy to port to Go

jupp0r
  • 4,502
  • 1
  • 27
  • 34
-4

Here is working code of my problem. I will add explanation later.

package main

import (
    "fmt"
    "net"
    "syscall"
)

func main() {

    fmt.Println("=============================================================================")
    fmt.Println("= Start sending                                                             =")
    fmt.Println("=============================================================================")

    pkt := []byte{
        0x6c, 0x62, 0x6d, 0x50, 0xe6, 0xe4, 0x94, 0xde, 0x80, 0xa5, 0xec, 0x79, 0x08, 0x00, 0x45, 0x00,
        0x00, 0x3c, 0x4b, 0x72, 0x40, 0x00, 0x40, 0x06, 0x44, 0x7d, 0xc0, 0xa8, 0x34, 0x7b, 0xd8, 0x3a,
        0xdd, 0x6e, 0xa6, 0x37, 0x01, 0xbb, 0x32, 0xf3, 0x21, 0xa9, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02,
        0x72, 0x10, 0xae, 0xa5, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x15, 0x13,
        0x6a, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x07,
    }

    fd, err := syscall.Socket(syscall.AF_PACKET, syscall.SOCK_RAW, syscall.ETH_P_ALL)
    if err != nil {
        fmt.Println("=============================================================================")
        fmt.Println("= Error 1                                                                   =")
        fmt.Println("=============================================================================")
        fmt.Println(err)
    }

    if_info, err := net.InterfaceByName("eth0")
    if err != nil {
        fmt.Println("=============================================================================")
        fmt.Println("= Error 2                                                                   =")
        fmt.Println("=============================================================================")
        fmt.Println(err)
    }

    var haddr [8]byte
    copy(haddr[0:7], if_info.HardwareAddr[0:7])
    addr := syscall.SockaddrLinklayer{
        Protocol: syscall.ETH_P_IP,
        Ifindex:  if_info.Index,
        Halen:    uint8(len(if_info.HardwareAddr)),
        Addr:     haddr,
    }

    err = syscall.Bind(fd, &addr)
    if err != nil {
        fmt.Println("=============================================================================")
        fmt.Println("= Error 3                                                                   =")
        fmt.Println("=============================================================================")
        fmt.Println(err)
    }

    err = syscall.SetLsfPromisc("eth0", true)
    if err != nil {
        fmt.Println("=============================================================================")
        fmt.Println("= Error 4                                                                   =")
        fmt.Println("=============================================================================")
        fmt.Println(err)
    }

    n, err := syscall.Write(fd, pkt)
    if err != nil {
        fmt.Println("=============================================================================")
        fmt.Println("= Error 5                                                                   =")
        fmt.Println("=============================================================================")
        fmt.Println(err)
        fmt.Println(n)
    } else {
        fmt.Println("=============================================================================")
        fmt.Println("= Packet is sent                                                            =")
        fmt.Println("=============================================================================")
        fmt.Println(n)
    }

    err = syscall.SetLsfPromisc("eth0", false)
    if err != nil {
        fmt.Println("=============================================================================")
        fmt.Println("= Error 6                                                                   =")
        fmt.Println("=============================================================================")
        fmt.Println(err)
    }
}
Khamidulla
  • 2,927
  • 6
  • 35
  • 59