Go语言linux下构造tcp数据包(不使用net包和Cgo)

原创 2014年03月03日 19:54:07

Golang可以通过syscall包中的相关socket函数(Windows和Linux中syscall中网络编程的函数不太一样)来进行网络编

程,可以用我们熟悉的方法使用raw socket,因为最近在搞一些协议的学习,所以特意试了试,和普通的linux+C的

socket编程基本没什么区别。


代码如下:

package main

import (
    "bytes"
    "encoding/binary"
    . "fmt"
    "strconv"
    "strings"
    "syscall"
    "unsafe"
)

type TCPHeader struct {
    SrcPort   uint16
    DstPort   uint16
    SeqNum    uint32
    AckNum    uint32
    Offset    uint8
    Flag      uint8
    Window    uint16
    Checksum  uint16
    UrgentPtr uint16
}

type PsdHeader struct {
    SrcAddr   uint32
    DstAddr   uint32
    Zero      uint8
    ProtoType uint8
    TcpLength uint16
}

func inet_addr(ipaddr string) uint32 {
    var (
        segments []string = strings.Split(ipaddr, ".")
        ip       [4]uint64
        ret      uint64
    )
    for i := 0; i < 4; i++ {
        ip[i], _ = strconv.ParseUint(segments[i], 10, 64)
    }
    ret = ip[3]<<24 + ip[2]<<16 + ip[1]<<8 + ip[0]
    return uint32(ret)
}

func htons(port uint16) uint16 {
    var (
        high uint16 = port >> 8
        ret  uint16 = port<<8 + high
    )
    return ret
}

func CheckSum(data []byte) uint16 {
	var (
		sum    uint32
		length int = len(data)
		index  int
	)
	for length > 1 {
		sum += uint32(data[index])<<8 + uint32(data[index+1])
		index += 2
		length -= 2
	}
	if length > 0 {
		sum += uint32(data[index])
	}
	sum += (sum >> 16)

	return uint16(^sum)
}

func main() {
    var (
        msg       string
        psdheader PsdHeader
        tcpheader TCPHeader
    )

    Printf("Input the content: ")
    Scanf("%s", &msg)

    /*填充TCP伪首部*/
    psdheader.SrcAddr = inet_addr("127.0.0.1")
    psdheader.DstAddr = inet_addr("127.0.0.1")
    psdheader.Zero = 0
    psdheader.ProtoType = syscall.IPPROTO_TCP
    psdheader.TcpLength = uint16(unsafe.Sizeof(TCPHeader{})) + uint16(len(msg))

    /*填充TCP首部*/
    tcpheader.SrcPort = htons(3000)
    tcpheader.DstPort = htons(8080)
    tcpheader.SeqNum = 0
    tcpheader.AckNum = 0
    tcpheader.Offset = uint8(uint16(unsafe.Sizeof(TCPHeader{}))/4) << 4
    tcpheader.Flag = 2 //SYN
    tcpheader.Window = 60000
    tcpheader.Checksum = 0

    /*buffer用来写入两种首部来求得校验和*/
    var (
        buffer bytes.Buffer
    )
    binary.Write(&buffer, binary.BigEndian, psdheader)
    binary.Write(&buffer, binary.BigEndian, tcpheader)
    tcpheader.Checksum = CheckSum(buffer.Bytes())

    /*接下来清空buffer,填充实际要发送的部分*/
    buffer.Reset()
    binary.Write(&buffer, binary.BigEndian, tcpheader)
    binary.Write(&buffer, binary.BigEndian, msg)

    /*下面的操作都是raw socket操作,大家都看得懂*/
    var (
        sockfd int
        addr   syscall.SockaddrInet4
        err    error
    )
    if sockfd, err = syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_TCP); err != nil {
        Println("Socket() error: ", err.Error())
        return
    }
    defer syscall.Shutdown(sockfd, syscall.SHUT_RDWR)
    addr.Addr[0], addr.Addr[1], addr.Addr[2], addr.Addr[3] = 127, 0, 0, 1
    addr.Port = 8080
    if err = syscall.Sendto(sockfd, buffer.Bytes(), 0, &addr); err != nil {
        Println("Sendto() error: ", err.Error())
        return
    }
    Println("Send success!")
}


如果转载请注明文章出处:http://blog.csdn.net/gophers/article/details/20393601

Linux 网络编程—— libpcap 详解

概述libpcap 是一个网络数据包捕获函数库,功能非常强大,Linux 下著名的 tcpdump 就是以它为基础的。libpcap主要的作用1)捕获各种数据包,列如:网络流量统计。2)过滤网络数据包...
  • tennysonsky
  • tennysonsky
  • 2015年04月02日 19:32
  • 48970

Linux.网络抓包库libpcap

TCPDUMP & Libpcap $ uname -a Linux niugenen 4.4.0-66-generic #87-Ubuntu SMP Fri Mar 3 15:29:05 UTC 2...
  • stringNewName
  • stringNewName
  • 2017年03月23日 20:31
  • 751

用Golang自己构造ICMP数据包

ICMP是用来对网络状况进行反馈的协议,可以用来侦测网络状态或检测网路错误。 限于当前Golang在网络编程方面的代码稀缺,资料甚少,所以分享一个用Golang来构造ICMP数据包并发送ping程...
  • u011774512
  • u011774512
  • 2014年03月18日 21:41
  • 4876

利用RawSocket篡改UDP源地址

最近在voip项目开发过程中,碰到一种业务场景,接入层通过两种途径对外提供访问入口: CMLB——外部Server SSO——移动终端 由于我们的接入层存在session的概念,因此...
  • cszhouwei
  • cszhouwei
  • 2014年07月07日 21:56
  • 4107

Golang 系统调用Syscall

Go 系统调用最近在研究go语言,发现go语言系统调用源码只有调用函数的定义,没有指导文档,网上也没有相关文档的说明,自己稍微研究了一下,不对的地方欢迎指教 go源码中关于系统调用的定义如下:fun...
  • u011211976
  • u011211976
  • 2017年12月22日 14:51
  • 232

原始套接字(raw socket)

1.原始套接字(raw socket)   1.1 原始套接字工作原理与规则          原始套接字是一个特殊的套接字类型,它的创建方式跟TCP/UDP创建方法几乎是 一摸一样,例如,...
  • bluehawksky
  • bluehawksky
  • 2014年10月27日 16:52
  • 1875

应用程序使用RAW socket从内核中抓取指定协议的数据包流程分析;

应用程序使用RAW socket从内核中抓取指定协议的数据包流程分析; 应用程序: int init_sockets() {     struct ifreq ifr;   ...
  • zxygww
  • zxygww
  • 2016年08月02日 13:19
  • 952

go语言的cgo简单教程

目前Go语言有2套编译器:GC和gccgo。其中GC提供的cgo支持C语言,gccgo支持C/C++。 此外,SWIG从2.0.1之后也对go语言提供支持,可以支持C++的类和回调。Go官方提供...
  • u010884123
  • u010884123
  • 2017年03月08日 15:19
  • 842

解读TCP/UDP数据包(二):TCP数据包结构

1、图 TCP数据包由首部和数据组成, 每行4个字节(32位) 其中首部最少20个字节(5行),最多60个字节(15行),选项部分是可选的; TCP首部并没有字段表明整个数据包的长度,是因...
  • fzzmouse
  • fzzmouse
  • 2013年06月29日 17:23
  • 2221

python 利用Raw Socket进行以太网帧嗅探

1. Raw Socket基础 提供了一种方法来绕过整个网络堆栈遍历和直接将以太网帧输送到一个应用程序。 有很多种方法来创建raw sockets,例如AF_PACKET,PF_PACKET。这里使用...
  • Jeanphorn
  • Jeanphorn
  • 2015年05月04日 16:34
  • 8196
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Go语言linux下构造tcp数据包(不使用net包和Cgo)
举报原因:
原因补充:

(最多只允许输入30个字)