20191231_jeffrey - silenceuncrio/diary GitHub Wiki

0840

今天把 iTwinkle Light 帶回家讓元旦多點氣氛

review

1025

目前搭配以下的環境

+-------+                                           +-------+
|       |                   lan                     |       |
| m330  +-------------------+-----------------------+ m330  |
|       | 192.168.1.11      |          192.168.1.13 |       |
+-------+                   |                       +-------+
                            |
                        +---+-------+               +-------+
                        |           | 192.168.1.113 |       |
                        | switch    +---------------+ PC    |
                        |           |               |       |
                        +-----------+               +-------+

搭配 gre 設定

m330 - 192.168.1.11

ip tunnel add gre1 mode gre local 192.168.1.11 remote 192.168.1.113 ttl 255
ip link set gre1 up
ip addr add 10.0.0.11/24 dev gre1

m330 - 192.168.1.11 - gre_keepalive_02.c

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>

struct gre_hdr {
    u_int16_t flags;
    u_int16_t protocol;
    u_int16_t csum;
    u_int16_t reserved1;
    u_int32_t key;
    u_int32_t seq;
} __packed;

int main(int argc, char *argv[])
{
    int sd;
    struct sockaddr_in dest;
    char buffer[64];
    
    struct gre_hdr *greh = (struct gre_hdr *) buffer;
    greh->protocol = 0;

    dest.sin_family = AF_INET;
    if (inet_pton(AF_INET, "10.0.0.113", &(dest.sin_addr)) != 1) {
        printf("Bad Address!\n");
        return(1);
    }

    if ((sd = socket(AF_INET, SOCK_RAW, IPPROTO_GRE)) < 0) {
        printf("socket() failed!\n");
        return(1);
        }

    if (sendto(sd, &buffer, sizeof(struct gre_hdr), 0, (struct sockaddr*) &dest, sizeof(struct sockaddr)) < 0)  {
        printf("sendto() failed!\n");
        return(1);
    }

    return(0);
}

該程式在 m330 - 192.168.1.11 執行後

我的 PC - 192.168.1.113 會收到以下的 GRE packet

image


注意到這多出來的部分

image

參考 RFC 1701 - Generic Routing Encapsulation (GRE)

option 的欄位我可以透過 flag 的指定全部都不送

1315

base on m330 - 192.168.1.11 - gre_keepalive_02.c 修改如下

m330 - 192.168.1.11 - gre_keepalive_03.c

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>

struct gre_hdr {
    u_int16_t flags;
    u_int16_t protocol;
} __packed;

int main(int argc, char *argv[])
{
    int sd;
    struct sockaddr_in dest;
    char buffer[64];
    
    struct gre_hdr *greh = (struct gre_hdr *) buffer;

    memset(greh, 0, sizeof(struct gre_hdr));

    greh->protocol = 0;

    dest.sin_family = AF_INET;
    if (inet_pton(AF_INET, "10.0.0.113", &(dest.sin_addr)) != 1) {
        printf("Bad Address!\n");
        return(1);
    }

    if ((sd = socket(AF_INET, SOCK_RAW, IPPROTO_GRE)) < 0) {
        printf("socket() failed!\n");
        return(1);
        }

    if (sendto(sd, &buffer, sizeof(struct gre_hdr), 0, (struct sockaddr*) &dest, sizeof(struct sockaddr)) < 0)  {
        printf("sendto() failed!\n");
        return(1);
    }

    return(0);
}

PC 端收到 GRE packet 如下

image


參考 how to bind raw socket to specific interface

試著 自行指定 ip header 並 從指定的 interface 送出去

1430

自行指定 ip header 前再熟悉一下相關的知識

1715

m330 - 192.168.1.11 - gre_keepalive_04.c

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <linux/ip.h>
#include <linux/if.h>

struct grehdr {
    u_int16_t flags;
    u_int16_t protocol;
} __packed;

int main(int argc, char *argv[])
{
    int sd;
    if ((sd = socket(AF_INET, SOCK_RAW, IPPROTO_GRE)) < 0) {
        printf("socket() failed!\n");
        return(1);
    }
    printf("OK: a raw socket with GRE protocol is created.\n");

    // inform the kernel do not fill up the packet structure, we will build our own
    int one = 1;
    const int *val = &one;
    if(setsockopt(sd, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) < 0) {
      perror("setsockopt() error");
      exit(2);
    }
    printf("OK: socket option IP_HDRINCL is set.\n");

    // bind raw socket to specific interface
    const char *opt;
    opt = "gre1";
    const len = strnlen(opt, IFNAMSIZ);
    if (len == IFNAMSIZ) {
        fprintf(stderr, "Too long iface name");
        return 1;
    }
    setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, opt, len);
    printf("OK: socket option SO_BINDTODEVICE is set.\n");

    struct sockaddr_in dest;
    dest.sin_family = AF_INET;
    if (inet_pton(AF_INET, "192.168.1.13", &(dest.sin_addr)) != 1) {
        printf("Bad Address!\n");
        return(1);
    }

    char buffer[64];

    // fabricate the IP header
    struct iphdr *ip = (struct iphdr *) buffer;
    ip->ihl      = 5;
    ip->version  = 4;
    ip->tos      = 16; // low delay
    ip->tot_len  = sizeof(struct iphdr) + sizeof(struct grehdr);
    ip->id       = htons(0);
    ip->ttl      = 64; // hops
    ip->protocol = 47; // GRE
    inet_pton(AF_INET, "192.168.1.13", &(ip->saddr));
    inet_pton(AF_INET, "192.168.1.113", &(ip->daddr));

    // fabricate the GRE header
    struct grehdr *greh = (struct grehdr *) (buffer + sizeof(struct iphdr));
    memset(greh, 0, sizeof(struct grehdr));
    greh->protocol = 0;

    if (sendto(sd, &buffer, ip->tot_len, 0, (struct sockaddr*) &dest, sizeof(struct sockaddr)) < 0)  {
        printf("sendto() failed!\n");
        return(1);
    }

    return(0);
}

PC 端收到 GRE packet 如下

image

理論上

我可以讓 m330 - 192.168.1.11 送 gre tunnel keepalive request 給 m330 - 192.168.1.11

然後 m330 - 192.168.1.11 解開後會把 gre tunnel keepalive responce 送給 PC - 192.168.1.113

這需要先修改 m330 - 192.168.1.11 上的 gre1 設定

⚠️ **GitHub.com Fallback** ⚠️