golang tun设备创建并监听

golang tun设备创建并监听

linux tun设备文件地址为/dev/net/tun.直接打开即可(关闭文件描述符创建的tun虚拟接口自动注销)

fd,err:=syscall.Open("/dev/net/tun",syscall.O_RDWR,0640)

//关闭
syscall.Close(fd)

初始化

  1. 配置ip地址
  2. 启动虚拟网卡
ip addr add xxx.xxx.xxx.xxx/24 dev tuname
ip link set dev tuname up

读取ip包

tun 是位于l3网络层,拿到手就是热乎的ip包,直接读文件描述符就ok

var(
    buff []byte=make([]byte,1024)
    lang int
    err error
)
lang,err=syscall.Read(fd,buff)

开始

查看本机网络接口
请添加图片描述

正常情况下,有2个接口,一个lo 本地,一个enxxxx的物理接口,当然在这里有几个不重要,大概了解下就可以了

创建一个名称为tun01的设备过后(不做初始化)

请添加图片描述

初始化后,这设备接口已经可以正常通了(你甚至可以直接使用这个接口的地址进行tcp/udp通信)

请添加图片描述

这个时候呢,这个go程序这边直接读文件描述符是没数据(最开始有几个大小为48的数据包,那是初始化产生的),也不可能会有数据。经过tun01 接口才能读出数据,但是都这步都没配路由表策略,怎么会有数据走这个接口过.这个时候肯定少不了ip4伴侣ip4 报头(这部分不了解的可以查看我[golang 监听ip包]这边文章,golang ip4头结构体里面都有)

这时候你想接受到数据,你得把你有流量来往的数据的网络设备接口导到你这个网络设备接口。查看路由策略(默认策略在main表中)。这个表看数据流入的看法是先不看default,如果ip4 dst 地址前3个对上了,那么就经过那一行对应的网络设备,一个都没对上,走default via 的那个地址,dev xxxx是用于发送这个ip包的网络设备(也就是说你default那一行乱搞,顶多是没网,你同局域网或者在非default网段的网络还是能上的),这里使用ip route改路由策略不要怕改路由表改错了带来什么影响导致重装系统,直接重启一下,一切都恢复如初

请添加图片描述

更改default 数据走向至tun01

请添加图片描述

请添加图片描述
请添加图片描述

演示代码

package main

/*
#include <net/if.h>
#include <linux/if_tun.h>
#include <sys/socket.h>
#include <sys/types.h>
*/
import "C"
import (
	"encoding/binary"
	"fmt"
	"os"
	"os/exec"
	"os/signal"
	"strconv"
	"syscall"
	"unsafe"
)

func Raw2String(src uint32) string {
	raw := make([]byte, 4)
	binary.LittleEndian.PutUint32(raw, src)
	return strconv.FormatUint(uint64(raw[0]), 10) + "." + strconv.FormatUint(uint64(raw[1]), 10) + "." + strconv.FormatUint(uint64(raw[2]), 10) + "." + strconv.FormatUint(uint64(raw[3]), 10)
}

// ip包必选,ip6自行根据wireshark进行编写,此处ip4为例
type IPHeader struct {
	Version_And_Len        uint8 //前4个bit为version(4 ip4,6 ip6),后bit个字节为首部length xxxx xxxx
	DiffernetialtedService uint8
	Tot_Len                uint16
	Id                     uint16
	Flag_And_Seek          uint16 //前3bit 为flag后面13bit为seek
	TTL                    uint8
	Protocol               uint8
	CheckSum               uint16
	Source                 uint32
	Dest                   uint32
}
type Pointer[T any] struct {
	T    *T
	buff []byte
}

func NewPointer[T any]() *Pointer[T] {
	var t T
	var ans = &Pointer[T]{buff: make([]byte, unsafe.Sizeof(t))} //获取类型占用内存字节数
	ans.T = (*T)(unsafe.Pointer(&ans.buff[0]))                  //将指针关联过去
	return ans
}
func (s *Pointer[T]) Bytes() []byte {
	return s.buff
}
func Open_Tun(tuname string, ipadd string) int {
	fd, err := syscall.Open("/dev/net/tun", syscall.O_RDWR, 0640)
	if fd < 0 {
		fmt.Fprintln(os.Stderr, "open fd failed "+err.Error())
		return -1
	}
	var (
		ifr C.struct_ifreq
	)
	//网络设备接口注册
	copy(ifr.ifr_ifrn[:len(tuname)], []byte(tuname))
	flags := NewPointer[uint16]()
	*flags.T = syscall.IFF_TUN | syscall.IFF_UP | syscall.IFF_MULTICAST
	copy(ifr.ifr_ifru[:2], flags.Bytes())
	ans, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), syscall.TUNSETIFF, uintptr(unsafe.Pointer(&ifr)))
	if int32(ans) < 0 {
		fmt.Fprintln(os.Stderr, err.Error())
		syscall.Close(fd)
		return -1
	}
	//设备接口初始化
	cmd := exec.Command("ip", "addr", "add", "192.168.99.99/24", "dev", tuname)
	cmd.Run()
	cmd = exec.Command("ip", "link", "set", "dev", tuname, "up")
	cmd.Run()
	return fd
}

func main() {
	fd := Open_Tun("tun01", "10.0.0.2")
	if fd > 0 {
		ch := make(chan os.Signal, 1)
		signal.Notify(ch, syscall.SIGINT)
		go func() {
			var (
				ipheader *IPHeader
				// size     int
				err  error
				buff []byte = make([]byte, 1024)
			)
			for {
				_, err = syscall.Read(fd, buff)
				if err == nil {
					if buff[0] == 0x45 { //只看ip4
						ipheader = (*IPHeader)(unsafe.Pointer(&buff[0]))
						fmt.Printf("protocol %d src %s dst %s\n", ipheader.Protocol, Raw2String(ipheader.Source), Raw2String(ipheader.Dest))
					}
				}
			}
		}()
		<-ch
		syscall.Close(fd)
	}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/405686.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2024-02-21 作业

作业要求&#xff1a; 复习课上内容 //已完成结构体字节对齐&#xff0c;64位没做完的做完&#xff0c;32位重新都做一遍&#xff0c;课上指定2字节对齐的做一遍&#xff0c;自己验证 //已完成两种验证大小端对齐的代码写一遍复习指针内容 //已完成完善顺序表已写出的…

使用HiveMQ实现Android MQTT

MQTT官网&#xff1a;https://mqtt.org/ 百度Android MQTT&#xff0c;或者B站上搜索&#xff0c;发现大多使用https://github.com/eclipse/paho.mqtt.android&#xff0c;这是Eclipse的一个Android MQTT客户端实现库&#xff0c;但是我发现这个库在运行到高版本的手机上时报错…

Oracle迁移到mysql-表结构的坑

1.mysql中id自增字段必须是整数类型 id BIGINT AUTO_INCREMENT not null, 2.VARCHAR2改为VARCHAR 3.NUMBER(16)改为decimal(16,0) 4.date改为datetime 5.mysql范围分区必须int格式&#xff0c;不能list类型 ERROR 1697 (HY000): VALUES value for partition …

【leetcode热题】填充每个节点的下一个右侧节点指针

给定一个 完美二叉树 &#xff0c;其所有叶子节点都在同一层&#xff0c;每个父节点都有两个子节点。二叉树定义如下&#xff1a; struct Node {int val;Node *left;Node *right;Node *next; } 填充它的每个 next 指针&#xff0c;让这个指针指向其下一个右侧节点。如果找不到…

Linux线程同步(2)死锁与互斥锁

死锁&#xff08;Deadlock&#xff09;是指两个或两个以上的进程&#xff08;或线程&#xff09;在执行过程中&#xff0c;由于竞争资源或者由于彼此通信而造成的一种阻塞的现象&#xff0c;若无外力作用&#xff0c;它们都将无法推进下去。此时称系统处于死锁状态或系统产生了…

【Linux进阶之路】Socket —— “UDP“ “TCP“

文章目录 一、再识网络1. 端口号2. 网络字节序列3.TCP 与 UDP 二、套接字1.sockaddr结构2.UDP1.server端1.1 构造函数1.2 Init1.3 Run 2.客户端1.Linux2.Windows 3.TCP1. 基本接口2. 客户端3. 服务端1.版本12.版本23.版本34.版本4 三、守护进程尾序 一、再识网络 1. 端口号 在…

RT-Thread 时钟 timer delay 相关

前言 此处,介绍对delay 时钟 timer 这几部分之间的关联和相关的知识点;本来只是想介绍一下 delay的,但是发现说到delay 不先 提到 先验知识 晶振\时钟\时钟节拍\定时器 好像没法解释透彻,所以就变成了 晶振\时钟\时钟节拍\定时器\delay 的很简单的概括一遍;并附带上能直接运行的…

【数据结构】链式队列

链式队列实现&#xff1a; 1.创建一个空队列 2.尾插法入队 3.头删法出队 4.遍历队列 一、main函数 #include <stdio.h> #include "./3.linkqueue.h" int main(int…

备考2025年AMC8数学竞赛:2000-2024年AMC8真题练一练

我们今天来随机看五道AMC8的真题和解析&#xff0c;对于想了解或者加AMC8美国数学竞赛的孩子来说&#xff0c;吃透AMC8历年真题是备考最科学、最有效的方法之一。 为帮助孩子们更高效地备考&#xff0c;我整理了2000-2004年的全部AMC8真题&#xff0c;并且独家制作了多种在线练…

Rust通用代码生成器莲花发布红莲尝鲜版二十一发布介绍视频,前端代码生成物大翻新

Rust通用代码生成器莲花发布红莲尝鲜版二十一发布介绍视频&#xff0c;前端代码生成物大翻新 Rust通用代码生成器发布了红莲尝鲜版二十一的最新介绍视频&#xff0c;前端代码生成物大翻新。视频请见&#xff1a; Rust通用代码生成器&#xff1a;莲花&#xff0c;红莲尝鲜版二…

构建生物医学知识图谱from zero to hero (3):生物医学命名实体识别和链接

生物医学实体链接 🤓现在是激动人心的部分。对于NLP和命名实体识别和链接的新手,让我们从一些基础知识开始。命名实体识别技术用于检测文本中的相关实体或概念。例如,在生物医学领域,我们希望在文本中识别各种基因、药物、疾病和其他概念。 生物医学概念提取 在这个例子中…

爬虫知识--03

数据存mysql import requests from bs4 import BeautifulSoup import pymysql# 链接数据库pymysql conn pymysql.connect(userroot,password"JIAJIA",host127.0.0.1,databasecnblogs,port3306, ) cursor conn.cursor() cursor conn.cursor()# 爬数据 res request…

Linux之ACL访问控制列表

一、ACL权限的介绍 1.1 什么是ACL 访问控制列表&#xff08;ACL&#xff09;是一种网络安全技术&#xff0c;它通过在网络设备&#xff08;如路由器、交换机和防火墙&#xff09;上定义一系列规则&#xff0c;对进出接口的数据包进行控制。这些规则可以包含“允许”&…

计算机网络面经_体系结构一文说清

编辑&#xff1a;平平无奇的羊 目录 基础 1. 计算机网络结构体系 三种模型之间的区别&#xff1a; 如何背诵&#xff1a; 进阶 OSI七层模型&#xff1a; TCP/IP四层模型&#xff1a; TCP/IP五层模型 总结 字节实习生为大家带来的是计算机网络面经系列博文&#xff0c;由浅…

线性代数:向量、张量、矩阵和标量

线性代数&#xff1a;向量、张量、矩阵和标量 背景 在线性代数中&#xff0c;向量、张量、矩阵和标量都属于基础概念&#xff0c;特别是最近AI的爆火&#xff0c;向量和张量的概念也越来越普及&#xff0c;本文将介绍下这些基本概念。 1. 标量&#xff08;Scalar&#xff0…

【Java网络编程06】HTTPS原理

1. HTTPS基本概念 HTTPS&#xff1a;HTTPS也是一个应用层协议&#xff0c;它在HTTP协议的基础上引入了一个加密层——SSL协议&#xff0c;区别就在于HTTP协议是基于明文传输的&#xff08;不安全&#xff09;&#xff0c;使用HTTPS加密就能在一定程度上防止数据在传输过程中被…

c# 类的介绍及延伸

类介绍 类的定义是以关键字 class 开始&#xff0c;后跟类的名称。 类属于引用类型&#xff0c;只能通过new方式创建。 如果类定义中没有指定基类&#xff0c;那其基类为system.object // <访问修饰符> class class类名 <access specifier> class class_name { //…

华为配置WDS手拉手业务示例

配置WDS手拉手业务示例 组网图形 图1 配置WDS手拉手业务示例组网图 业务需求组网需求数据规划配置思路配置注意事项操作步骤配置文件 业务需求 企业用户通过WLAN接入网络&#xff0c;以满足移动办公的最基本需求。但企业考虑到AP通过有线部署的成本较高&#xff0c;所以通过建立…

golang 监听ip数据包(golang纯享版)

golang 监听ip数据包(golang纯享版) 【注】本机编译运行平台为linux&#xff0c;如需测试代码请移至linux平台进行代码测试 本文以ip4 作为案例进行包抓取示范&#xff0c;ip6抓取与ip4方式异曲同工&#xff0c;可自行举一反三得出 第一步&#xff0c;通过wireshark抓包拿到…

第四十二回 假李逵翦径劫单身 黑旋风沂岭杀四虎-python读写csv和json数据

李逵答应了宋江三件事&#xff1a;不可吃酒&#xff0c;独自前行&#xff0c;不带板斧。李逵痛快答应了&#xff0c;挎一口腰刀&#xff0c;提着朴刀&#xff0c;带了一锭大银子&#xff0c;三五个小银子就下山去了。 宋江放心不下&#xff0c;于是请同乡朱贵也回家一趟&#…