Skip to content

Commit

Permalink
Implement golang bind
Browse files Browse the repository at this point in the history
This commit implements the macgonuts golang bind. Besides
build tasks (--with-gobind, with-gobind=yes) related to it and
some documentation. Building and usage. A little sample, too.
  • Loading branch information
rafael-santiago committed Sep 5, 2023
1 parent ee8392e commit 1616e54
Show file tree
Hide file tree
Showing 12 changed files with 390 additions and 77 deletions.
79 changes: 79 additions & 0 deletions doc/BINDS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Details about how to build is not discussed here, take a look at `doc/BUILD.md`.

- [What is available until now](#what-is-available-until-now)
- [Using `macgonuts_pybind`](#using-macgonuts_pybind)
- [Using `macgonuts` from `Golang`](#using-macgonuts-from-golang)

## What is available until now

Expand Down Expand Up @@ -84,3 +85,81 @@ if macgonuts_undo_spoof('eth1', 'dead::beef:8e', 'dead::beef:1') != 0:
```

[``Back``](#topics)

## Using `macgonuts` from `Golang`

Similar to `Python`'s bind you have the two basic building blocks to promote a spoofing attack:

- `Spoof()` function
- `UndoSpoof()` function

The `Spoof()` function expects the following arguments:

- `loIface` is the name of the interface you are accessing the network.
- `targetAddr` is the network address of the target, it can be a `IPv4` or `IPv6` address.
- `addr2Spoof` is the address that will be spoofed at target, it can be a `IPv4` or `IPv6` address.
- `fakePktsAmount` is the total of spoofed packets sent to target, it defaults to one.
- `timeout` is the timeout in `mss` between a spoofed packet and the next, it defauts to no timeout.

Since `Golang` does not have default arguments, when you pass `fakePktsAmount` as zero it will infer
that you want one single fake packet.

The `UndoSpoof()` function expects the following arguments:

- `loIface` is the name of the interface you are accessing the network.
- `targetAddr` is the network address of the target, it can be a `IPv4` or `IPv6` address.
- `addr2Spoof` is the address that was spoofed at target, it can be a `IPv4` or `IPv6` address.

When those function succeed they return `nil` when not, an error is returned and more details are
provided on `stderr`, too.

The bind also implements a `Version()` function that returns a `string` related to the version of the bind.
In general it follows the main version of the project.

This is the main idea on using `Macgonuts` from a `Go` code:

```go
package main

import (
"fmt"
"os"
// INFO(Rafael): Personally I find this way of importing things in Golang kind of naive
// and bit stupid. Because you are linking your stuff to on-line stuff from other
// people that at some point in the future can remove this, cut access, whatever.
// In other words, you have zero control about it. If you lost your local go
// installation, maybe in a future attempt of recompiling the stuff you can
// be surprised of how external world does not give a sh_t to your dependencies
// and you.... If the package is provided by a person, instead of a company, it is
// even worse. But even companies can easily vanish away as whole or at least with
// some technologies as the years go by. Thus, if you are intending to do good engineering
// by writing code that can be built do not mattering where and when... You must consider
// my unpopular, "profanus", maybe heretic point....
"github.com/rafael-santiago/macgonuts/binds/go/v1"
// Instead, the better would be cloning the Macgonuts sources and embed it into your
// own code, by importing as follows (supposing you are into `binds/go/my-new-blau`:
"../v1"
// Cool off, the stuff is BSD-Licensed! ;)
)

func main() {
fmt.Printf("Spoofing...\n")
err := macgonuts.Spoof("eth0", "192.168.5.142", "192.168.5.1", 100, 100)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Printf("Done!\nNow Undoing the spoof...\n")
err = macgonuts.UndoSpoof("eth0", "192.168.5.142", "192.168.5.1")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Printf("Done!\n")
os.Exit(0)
}
```

You also can check a more complete sample at `src/binds/go/sample`.

[``Back``](#topics)
21 changes: 20 additions & 1 deletion doc/BUILD.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ fresh ``macgonuts`` binary to get your stuff done, you can give ``the low-cost b
- [Building the debian package](#building-the-debian-package)
- [Building the binds](#building-the-binds)
- [pybind](#pybind)
- [gobind](#gobind)

## Getting newest macgonuts source code revision

Expand Down Expand Up @@ -208,6 +209,8 @@ Take a look at **Table 1** to know all build options supported by the ``Hefesto`
|``--genhtml-outpath``| value | Specifies a file path for the ``LCOV`` coverage report |
| ``--toolset`` | value | Specifies the name of wanted compiler, can being ``gcc`` or ``clang`` |
| ``--debian-pkg`` | flag | Runs the debian packaging build task |
| ``--with-pybind`` | flag | Includes ``Python``'s bind compilation in the main build task |
| ``--with-gobind`` | flag | Includes ``Golang``'s bind compilation in the main build task |

[``Back``](#topics)

Expand Down Expand Up @@ -273,9 +276,25 @@ When using the ``low-cost`` build you also need to be into ``src`` sub-directory
build parameter ``with-pybind``:

```
you@somewhere-over-the-rainbow:~/macgonuts/src# make with-pybind
you@somewhere-over-the-rainbow:~/macgonuts/src# make with-pybind=yes
```

The ``python`` bind artifacts will be built into ``src/binds/py``.

[``Back``](#topics)

### gobind

In order to build ``Macgonuts`` ``Golang`` bind by using the ``developer's`` build you need to invoke ``Hefesto`` passing
the option ``--with-gobind`` (supposing you are into ``src`` sub-directory):

```
you@somewhere-over-the-rainbow:~/macgonuts/src# hefesto --with-gobind
```

If you want to use ``low-cost`` build instead, also being into ``src`` sub-directory, call ``make`` defining the build
parameter ``with-gobind``:

```
you@somewhere-over-the-rainbow:~/macgonuts/src# make with-gobind=yes
```
4 changes: 4 additions & 0 deletions src/Forgefile.hsl
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ macgonuts-static-lib.epilogue() {
if ($option.count() > 0) {
$subprojects.add_item("pybind");
}
$option = hefesto.sys.get_option("with-gobind");
if ($option.count() > 0) {
$subprojects.add_item("gobind");
}
if (build_projects($subprojects) == 0) {
$option = hefesto.sys.get_option("coverage");
if ($option.count() > 0) {
Expand Down
5 changes: 5 additions & 0 deletions src/GNUmakefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ ifdef with-pybind
LIBACCACIA_CFLAGS += -fPIC
endif

CURR_GOBIND_VERSION = v1

SOURCES := $(wildcard *.c)
SOURCES += $(wildcard unix/*.c)
SOURCES += $(wildcard $(NATIVE_SRC)/*.c)
Expand All @@ -35,6 +37,9 @@ ifdef with-pybind
ar -r $(LIBDIR)/libmacgonutssock.a
cd binds/py && rm -rf build && rm -f macgonuts.c && python setup.py build_ext --inplace
endif
ifdef with-gobind
cd binds/go/$(CURR_GOBIND_VERSION) && go build
endif

setup:
@mkdir -p .o
Expand Down
60 changes: 60 additions & 0 deletions src/binds/go/sample/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//
// Copyright (c) 2023, Rafael Santiago
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree.
//
// INFO(Rafael): If you want to build this sample just run `go build`
package main

import (
"../v1"
"fmt"
"os"
"strconv"
)

func main() {
if len(os.Args) < 4 {
fmt.Fprintf(os.Stderr, "use: %s <iface> <target-ip> <address-to-spoof> [ <packets-total> <timeout in mss> ]",
os.Args[0])
os.Exit(1)
}
var packetsTotal int = 0
var err error = nil
if len(os.Args) > 4 {
packetsTotal, err = strconv.Atoi(os.Args[4])
if err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
}
if packetsTotal < 0 {
fmt.Fprintf(os.Stderr, "error: packets-total must be a positive integer.\n")
os.Exit(1)
}
}
var timeoutInMss int = 0
if len(os.Args) > 5 {
timeoutInMss, err = strconv.Atoi(os.Args[5])
if err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
}
if timeoutInMss < 0 {
fmt.Fprintf(os.Stderr, "error: timeout must be a positive integer.\n")
os.Exit(1)
}
}
err = macgonuts.Spoof(os.Args[1], os.Args[2], os.Args[3], packetsTotal, timeoutInMss)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
err = macgonuts.UndoSpoof(os.Args[1], os.Args[2], os.Args[3])
if err != nil {
fmt.Println(err)
os.Exit(1)
}
os.Exit(0)
}
3 changes: 3 additions & 0 deletions src/binds/go/v1/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/rafael-santiago/macgonuts/src/binds/go/v1

go 1.15
82 changes: 82 additions & 0 deletions src/binds/go/v1/macgonuts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
//
// Copyright (c) 2023, Rafael Santiago
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree.
//
package macgonuts

/*
#cgo CFLAGS: -I../../..
#cgo LDFLAGS: -L../../../../lib -L../../../libs/accacia/lib -lmacgonuts -lmacgonutssock -laccacia
#include <binds/macgonuts_binds.h>
#include <binds/macgonuts_binds.c>
*/
import "C"
import "unsafe"

import (
"fmt"
)

// Indicates the current version of the bind stuff. Always it is directly
// linked to Macgonuts main release version.
const kMacgonutsGoBindVersion string = "v1"

// The Golang bind for macgonuts_spoof() function from libmacgonuts.
// By using this function you can easily promote a spoofing attack based on IPv4 or IPv6. It receives:
// - the local interface label (loIface)
// - the target IPv4/IPv6 address (targetAddr)
// - the IPv4/IPv6 address which will be spoofed at the target host (addr2Spoof)
// - the amount of fake address resolution packets to be sent (fakePktsAmount, when zero it defaults to one)
// - the timeout amount between the current packet and the next (timeout, its default is no timeout)
// It returns nil on success and an error on failure, besides writing some error description to stderr.
func Spoof(loIface, targetAddr, addr2Spoof string, fakePktsAmount, timeout int) error {
if len(loIface) == 0 || len(targetAddr) == 0 || len(addr2Spoof) == 0 {
return fmt.Errorf("invalid argument(s) passed to MacgonutsSpoof().")
}
lo_iface := C.CString(loIface)
defer C.free(unsafe.Pointer(lo_iface))
target_addr := C.CString(targetAddr)
defer C.free(unsafe.Pointer(target_addr))
addr2spoof := C.CString(addr2Spoof)
defer C.free(unsafe.Pointer(addr2spoof))
var fake_pkts_amount C.int = 1
if fakePktsAmount > 0 {
fake_pkts_amount = C.int(fakePktsAmount)
}
if C.macgonuts_binds_spoof(lo_iface,
target_addr,
addr2spoof, fake_pkts_amount, C.int(timeout)) != 0 {
return fmt.Errorf("error when spoofing.")
}
return nil
}

// The Golang bind for macgonuts_undo_spoof() function from libmacgonuts.
// By using this function you can easily undo a previous promoted spoofing attack based on IPv4 or IPV6. It receives:
// - the local interface used during the spoofing attack (loIface)
// - the target IPv4/IPv6 address of the spoofing attack (targetAddr)
// - the IPv4/IPv6 address which was spoofed at the target host (addr2Spoof)
// It returns zero on success and non-zero value on failure, besides writing some error description to stderr.
func UndoSpoof(loIface, targetAddr, addr2Spoof string) error {
if len(loIface) == 0 || len(targetAddr) == 0 || len(addr2Spoof) == 0 {
return fmt.Errorf("invalid argument(s) passed to MacgonutsSpoof().")
}
lo_iface := C.CString(loIface)
defer C.free(unsafe.Pointer(lo_iface))
target_addr := C.CString(targetAddr)
defer C.free(unsafe.Pointer(target_addr))
addr2spoof := C.CString(addr2Spoof)
defer C.free(unsafe.Pointer(addr2spoof))
if C.macgonuts_binds_undo_spoof(lo_iface, target_addr, addr2spoof) != 0 {
return fmt.Errorf("error when undoing spoof.")
}
return nil
}

// Returns the version of the bind stuff.
func Version() string {
return kMacgonutsGoBindVersion
}
Loading

0 comments on commit 1616e54

Please sign in to comment.