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

来源:互联网 发布:有淘宝账号就能贷款 编辑:程序博客网 时间:2024/05/16 04:02

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

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

socket编程基本没什么区别。


代码如下:

package mainimport (    "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    uint32length int = len(data)index  int)for length > 1 {sum += uint32(data[index])<<8 + uint32(data[index+1])index += 2length -= 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

0 0
原创粉丝点击