I use the following Go code to get some info about the network interfaces. Any suggestions on how I would be able to get the status of promiscuous mode for each interface?
type Iface struct {
Name string `json:"name"`
Status string `json:"status"`
Multicast bool `json:"multicast"`
Broadcast bool `json:"broadcast"`
}
func (c *InterfacesController) GetInterfaces() {
interfaces, err := net.Interfaces()
if err != nil {
fmt.Println(err)
return
}
var ifaceset []Iface
var ifc Iface
for _, i := range interfaces {
ifc.Name = i.Name
if strings.Contains(i.Flags.String(), "up") {
ifc.Status = "UP"
} else {
ifc.Status = "DOWN"
}
if strings.Contains(i.Flags.String(), "multicast") {
ifc.Multicast = true
} else {
ifc.Multicast = false
}
if strings.Contains(i.Flags.String(), "broadcast") {
ifc.Broadcast = true
} else {
ifc.Broadcast = false
}
ifaceset = append(ifaceset, ifc)
}
}
It doesn't appear Go has a cross-platform way of checking the PROMISC flag (I can't even find out for sure if such a flag exists for windows.) Here is a way to get it on linux, which I'm guessing you're on:
package main
import (
"fmt"
"net"
"os"
"syscall"
"unsafe"
)
func GetPromiscuous(i net.Interface) (bool, error) {
tab, err := syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC)
if err != nil {
return false, os.NewSyscallError("netlinkrib", err)
}
msgs, err := syscall.ParseNetlinkMessage(tab)
if err != nil {
return false, os.NewSyscallError("parsenetlinkmessage", err)
}
loop:
for _, m := range msgs {
switch m.Header.Type {
case syscall.NLMSG_DONE:
break loop
case syscall.RTM_NEWLINK:
ifim := (*syscall.IfInfomsg)(unsafe.Pointer(&m.Data[0]))
if ifim.Index == int32(i.Index) {
return (ifim.Flags & syscall.IFF_PROMISC) != 0, nil
}
}
}
return false, os.ErrNotExist
}
func main() {
ints, err := net.Interfaces()
if err != nil {
panic(err)
}
for _, i := range ints {
p, err := GetPromiscuous(i)
if err != nil {
panic(err)
}
fmt.Println(i.Name, p)
}
}
This is based of the interfaceTable function in the standard library. It uses rtnetlink to get the flags of the interface. Unless you want to roll your own syscall.NetlinkRIB function, this code will always pull the information for every network device and filter out the requested one.
A bit less magical way to get the flag you want is to use cgo and ioctl:
package main
/*
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
bool is_promisc(char *name) {
int s = socket(AF_INET, SOCK_STREAM, 0);
struct ifreq *i = malloc(sizeof *i);
strncpy((char *)&(i->ifr_name), name, IFNAMSIZ);
ioctl(s, SIOCGIFFLAGS, i);
bool p = (i->ifr_flags & IFF_PROMISC) != 0;
free(i);
return p;
}
*/
import "C"
import (
"fmt"
"net"
)
func GetPromiscuous(i net.Interface) (bool, error) {
set, err := C.is_promisc(C.CString(i.Name))
return bool(set), err
}
func main() {
ints, err := net.Interfaces()
if err != nil {
panic(err)
}
for _, i := range ints {
p, err := GetPromiscuous(i)
if err != nil {
panic(err)
}
fmt.Println(i.Name, p)
}
}
A final note is that either way may not always tell you correctly whether an interface is actually in promiscuous mode or not. See this thread for more details.
From what I'm reading using the netlink route should work correctly, but another post says we should be checking the promiscuous count. Please let me know if someone knows how to do that, because I can't find how to. The only stackoverflow question on the matter has gone unanswered.
I think either of these methods will work as long as you're not doing any crazy networking stuff (bridge, vlan interfaces, macvtap, etc.) The code definitely works if you use iproute2 tools to turn promisc on and off on an interface.
The working environment is Ubuntu, I used the ifconfig command and checked each interface details to see if it contains the word PROMISC. Something like this:
//
// get the interfaces
//
interfaces, err := net.Interfaces()
//
// run the ifconfig command
//
out, err := exec.Command("/bin/sh", "-c", "ifconfig").Output()
var ifc Iface
var ifaceset []Iface
//
// split the output to handle each interface separately
//
var ifaceDetails = strings.Split(string(out), "\n\n")
//
// iterate interfaces
//
for _, i := range interfaces {
ifc.Name = i.Name
if strings.Contains(i.Flags.String(), "up") {
ifc.Status = "UP"
} else {
ifc.Status = "DOWN"
}
if strings.Contains(i.Flags.String(), "multicast") {
ifc.Multicast = true
} else {
ifc.Multicast = false
}
if strings.Contains(i.Flags.String(), "broadcast") {
ifc.Broadcast = true
} else {
ifc.Broadcast = false
}
//
// try to find the word PROMISC to check if it is UP
//
for _, ifdetails := range ifaceDetails {
if strings.Contains(ifdetails, i.Name) {
if strings.Contains(ifdetails, "PROMISC") {
ifc.Promisc = true
} else {
ifc.Promisc = false
}
}
}
ifaceset = append(ifaceset, ifc)
}
}
Related
I would like to read a pcap file generated by tcpdump that contains large UDP packets that have undergone IPV4 fragmentation. The original packets are of a size of around 22000 bytes.
In C++, I would use libtins with its IPV4Reassembler. Is there a way that I can do something similar in Rust?
Currently in Rust here is what I have written so far: a highly incomplete first-pass attempt (using crate pnet):
use pnet::packet::{
ethernet::{EtherTypes, EthernetPacket},
ip::IpNextHeaderProtocols,
ipv4::Ipv4Packet,
udp::UdpPacket,
Packet,
};
struct Ipv4Reassembler {
cap: pcap::Capture<pcap::Offline>,
}
impl Iterator for Ipv4Reassembler {
type Item = Vec<u8>;
fn next(&mut self) -> Option<Self::Item> {
let mut payload = Vec::<u8>::new();
while let Some(packet) = self.cap.next().ok() {
// todo: handle packets other than Ethernet packets
let ethernet = EthernetPacket::new(packet.data).unwrap();
match ethernet.get_ethertype() {
EtherTypes::Ipv4 => {
let ipv4_packet = Ipv4Packet::new(ethernet.payload()).unwrap();
// dbg!(&ipv4_packet);
// todo: discard incomplete packets
// todo: construct header for reassembled packet
// todo: check id, etc
let off: usize = 8 * ipv4_packet.get_fragment_offset() as usize;
let end = off + ipv4_packet.payload().len();
if payload.len() < end {
payload.resize(end, 0);
}
payload[off..end].clone_from_slice(ipv4_packet.payload());
if ipv4_packet.get_flags() & 1 == 0 {
return Some(payload);
}
}
_ => {}
}
}
None
}
}
fn main() {
let pcap_path = "os-992114000702.pcap";
let reass = Ipv4Reassembler {
cap: pcap::Capture::from_file(&pcap_path).unwrap(),
};
for payload in reass {
let udp_packet = UdpPacket::new(&payload).unwrap();
dbg!(&udp_packet);
dbg!(&udp_packet.payload().len());
}
}
In C++ here is the code I would use (using libtins):
#include <tins/ip_reassembler.h>
#include <tins/packet.h>
#include <tins/rawpdu.h>
#include <tins/sniffer.h>
#include <tins/tins.h>
#include <tins/udp.h>
#include <iostream>
#include <string>
void read_packets(const std::string &pcap_filename) {
Tins::IPv4Reassembler reassembler;
Tins::FileSniffer sniffer(pcap_filename);
while (Tins::Packet packet = sniffer.next_packet()) {
auto &pdu = *packet.pdu();
const Tins::Timestamp ×tamp = packet.timestamp();
if (reassembler.process(pdu) != Tins::IPv4Reassembler::FRAGMENTED) {
const Tins::UDP *udp = pdu.find_pdu<Tins::UDP>();
if (!udp) {
continue;
}
const Tins::RawPDU *raw = pdu.find_pdu<Tins::RawPDU>();
if (!raw) {
continue;
}
const Tins::RawPDU::payload_type &payload = raw->payload();
std::cout << "Packet: " << payload.size() << std::endl;
// do something with the reassembled packet here
}
}
}
int main() {
const std::string pcap_path = "os-992114000702.pcap";
read_packets(pcap_path);
}
g++ -O3 -o pcap pcap.cpp -ltins
It seems that one solution is to implement RFC815 but I am not sure how to do that in Rust. I have found:
this old pull request to smolltcp but it appears to have been abandoned.
Fuschia reassembly.rs but I have no idea how to use this outside of Fuschia.
I am trying to create a C struct point and pass it to Go but I keep getting a nil pointer. I have the following in C and calling from Go.
test.h
#include <stdio.h>
typedef struct TestStruct {
int test_int;
} TestStruct;
TestStruct* newTestStruct();
test.c
TestStruct* newTestStruct() {
printf("[C] Creating TestStruct...\n");
TestStruct test = {0};
test.test_int = 10;
TestStruct* testPtr = &test;
if (testPtr == NULL) {
printf("[C] TestStruct is NULL.\n");
}
fflush(stdout);
return testPtr;
}
test.go
package teststruct
import "log"
// #include "test.h"
import "C"
type TestStruct C.struct_TestStruct
func NewTestStruct() *TestStruct {
t := C.newTestStruct()
if t == nil {
log.Errorf("[Go] TestStruct is nil.")
}
return (*TestStruct)(t)
}
It prints off the following:
[C] Creating TestStruct...
[Go] TestStruct is nil.
Why is this nil on the Go side?
You are returning a pointer to a stack-allocated structure in C, which is very wrong.
The pointer returned from newTestStruct is essentially dangling and trying to access any data through it may lead to crashes or worse.
Make sure to allocate data on the heap if you want to return a pointer to it, something like:
TestStruct* newTestStruct() {
printf("[C] Creating TestStruct...\n");
TestStruct* testPtr = (TestStruct*)malloc(sizeof(TestStruct));
testPtr->test_int = 10;
if (testPtr == NULL) {
printf("[C] TestStruct is NULL.\n");
}
fflush(stdout);
return testPtr;
}
By the way, on any half-modern C compiler you'd get a warning for your C code, something like warning: function returns address of local variable [-Wreturn-local-addr]
I am trying to populate a map based on output from various goroutines. For this I have created a channel of type (map[key][]int)
done := make(chan map[int][]int)
and pass it to workers goroutine, along with the key value, which is int for the example.
for i := 0; i < 10; i++ {
go worker(i, done)
}
I want to populate my map as I read from the key. Currently I am doing as below
for i := 0; i < 10; i++ {
m := <-done
fmt.Println(m)
for k,v := range m {
retmap[k] = v
}
}
fmt.Println(retmap)
I feel I am not doing this correctly. Is there a better way to do this using channels? Any suggestions would be much appreciated?
playground: https://play.golang.org/p/sv4Qk4hEljx
You could use a specific channel per worker instead of encoding that information in the result object of the worker. Something like:
func worker(done chan []int) {
fmt.Print("working...")
rnd := rand.Intn(10)
fmt.Println("Sleeping for ", rnd, "seconds")
for i := 0; i < rnd; i++ {
time.Sleep(time.Second)
}
fmt.Println("done")
// Send a value to notify that we're done.
done <- makeRange(0, rnd)
}
func main() {
channels := make([]chan []int, 10, 10)
for i := 0; i < 10; i++ {
channels[i] = make(chan []int)
go worker(channels[i])
}
retmap := make(map[int][]int)
for i := 0; i < 10; i++ {
retmap[i] = <-channels[i]
}
fmt.Println(retmap)
}
Playground link
There is a function that sets a pointer to a nil value:
func nilSetter(x *int) {
x = nil
}
I have such snippet of code:
i := 42
fmt.Println(&i)
nilSetter(&i)
fmt.Println(&i)
Which prints:
0xc42008a000
0xc42008a000
While I expect:
0xc42008a000
nil
I know that it happens because function nilSetter just copy address and sets to nil that copy.
But how can I do it correctly?
The only way to achieve that is with a pointer to a pointer. And it's pretty clunky so it's probably not what you want:
func nilSetter(x **int) {
*x = nil
}
func main() {
x := 2
xp := &x
fmt.Println(xp)
nilSetter(&xp)
fmt.Println(xp)
}
// Output:
// 0x10414020
// <nil>
The reason of such behaviour is because there is no pass by reference in Go.
Two variables can have contents that point to the same storage location. But, it is not possible to have them share the same storage location.
Example:
package main
import "fmt"
func main() {
var a int
var b, c = &a, &a
fmt.Println(b, c) // 0x1040a124 0x1040a124
fmt.Println(&b, &c) // 0x1040c108 0x1040c110
}
From your code, the argument x of nilSetter is pointing to some location but it have its own address and when you are setting a nil to it, you are changing its address not the address of what it is pointing to.
package main
import "fmt"
func nilSetter(x *int) {
x = nil
fmt.Println(x, &x) // <nil> 0x1040c140
}
func main() {
i := 42
fmt.Println(&i) // 0x10414020
nilSetter(&i)
fmt.Println(&i) // 0x10414020
}
That is why pointers always have an exact address even its value is nil
Referencing to a blog post by Dave Cheney: https://dave.cheney.net/2017/04/29/there-is-no-pass-by-reference-in-go
Just use return value and assign.
func nilSetter(x *int) *int {
x = nil
return x
}
x = nilSetter(x)
guys! I am a beginner in Go. I have some doubts When I learning reflect package ,here's the code:
package main
import (
"encoding/json"
"fmt"
"reflect"
)
func checkError(err error) {
if err != nil {
panic(err)
}
}
type Test struct {
X int
Y string
}
func main() {
fmt.Println("hello world!")
test1()
test2()
}
func test1() {
a := Test{}
fmt.Printf("a: %v %T \n", a, a)
fmt.Println(a)
err := json.Unmarshal([]byte(`{"X":1,"Y":"x"}`), &a)
checkError(err)
fmt.Printf("a: %v %T \n", a, a)
}
func test2() {
fmt.Println("===========================")
m := make(map[string]reflect.Type)
m["test"] = reflect.TypeOf(Test{})
a := reflect.New(m["test"]).Elem().Interface()
fmt.Printf("a: %v %T \n", a, a)
fmt.Println(a)
err := json.Unmarshal([]byte(`{"X":1,"Y":"x"}`), &a)
checkError(err)
fmt.Printf("a: %v %T \n", a, a)
}
and the result :
a: {0 } main.Test
{0 }
a: {1 x} main.Test
===========================
a: {0 } main.Test
{0 }
a: map[X:1 Y:x] map[string]interface {}
Why these two way make different result, Could anyone tell me why, many thanks.
In test2 you're passing in the address of the interface{} containing a Test value. When the value is dereferenced by the json package it only sees an interface{}, and therefor it unmarshals into the default types.
What you need is an interface{} containing a pointer to a Test value.
// reflect.New is creating a *Test{} value.
// You don't want to dereference that with Elem()
a := reflect.New(m["test"]).Interface()
// 'a' contains a *Test value. You already have a pointer, and you
// don't want the address of the interface value.
err := json.Unmarshal([]byte(`{"X":1,"Y":"x"}`), a)