20191231_jeffrey - silenceuncrio/diary GitHub Wiki
今天把 iTwinkle Light
帶回家讓元旦多點氣氛
review
目前搭配以下的環境
+-------+ +-------+
| | 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
注意到這多出來的部分
參考 RFC 1701 - Generic Routing Encapsulation (GRE)
option 的欄位我可以透過 flag 的指定全部都不送
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 如下
參考 how to bind raw socket to specific interface
試著 自行指定 ip header 並 從指定的 interface 送出去
自行指定 ip header 前再熟悉一下相關的知識
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 如下
理論上
我可以讓 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 設定