20200106_jeffrey - silenceuncrio/diary GitHub Wiki

0850

review


結合以下這兩支來併成一支 gre_keepalive_06.c

  • 每五秒發一次 gre tunnel keepalive request

gre_keepalive_05.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;

unsigned short csum(unsigned short *ptr,int nbytes) {
    long sum;
    unsigned short oddbyte;
    short answer;

    //Debug info
    //hexdump((unsigned char *) ptr, nbytes);
    //printf("csum nbytes: %d\n", nbytes);
    //printf("csum ptr address: %p\n", ptr);

    sum=0;
    while(nbytes>1) {
        sum+=*ptr++;
        nbytes-=2;
    }
    if(nbytes==1) {
        oddbyte=0;
        *((u_char*)&oddbyte)=*(u_char*)ptr;
        sum+=oddbyte;
    }

    sum = (sum>>16)+(sum & 0xffff);
    sum = sum + (sum>>16);
    answer=(short)~sum;

    return(answer);
}

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");

#if 0
    // 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");
#endif

#if 0
    // 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");
#endif

    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[128];

    // let kernel decide the outer IP header

    // fabricate the outer GRE header
    struct grehdr *outer_greh = (struct grehdr *) buffer;
    memset(outer_greh, 0, sizeof(struct grehdr));
    outer_greh->protocol = 0x0800; // IP

    // fabricate the inner IP header
    struct iphdr *inner_ip = (struct iphdr *) (buffer + sizeof(struct grehdr));
    memset(inner_ip, 0, sizeof(struct iphdr));
    inner_ip->ihl       = 5; // the number of 32-bit words in the header
    inner_ip->version   = 4; // IPv4
    inner_ip->tos       = 16; // low delay
    inner_ip->tot_len   = sizeof(struct iphdr) + sizeof(struct grehdr);
    inner_ip->id        = htons(0);
    inner_ip->frag_off  = 0x00;
    inner_ip->ttl       = 64;
    inner_ip->protocol  = 47; // GRE
    inner_ip->check     = 0; //16 bit checksum of IP header. Can't calculate at this point
    inet_pton(AF_INET, "192.168.1.13", &(inner_ip->saddr));
    inet_pton(AF_INET, "192.168.1.11", &(inner_ip->daddr));

    // fabricate the inner GRE header
    struct grehdr *inner_greh = (struct grehdr *) (buffer + sizeof(struct grehdr) + sizeof(struct iphdr));
    memset(inner_greh, 0, sizeof(struct grehdr));
    inner_greh->protocol = htons(0); // defined at cisco tunnel keepalive

    // calculate the checksum for integrity
    inner_ip->check = csum((unsigned short *) (buffer + sizeof(struct grehdr)), sizeof(struct iphdr) + sizeof(struct grehdr));
    printf("checksum: 0x%04x\n", inner_ip->check);

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

    return(0);
}

tlpi_timers_ptmr_sigev_signal.c

/*************************************************************************\
*                  Copyright (C) Michael Kerrisk, 2019.                   *
*                                                                         *
* This program is free software. You may use, modify, and redistribute it *
* under the terms of the GNU General Public License as published by the   *
* Free Software Foundation, either version 3 or (at your option) any      *
* later version. This program is distributed without any warranty.  See   *
* the file COPYING.gpl-v3 for details.                                    *
\*************************************************************************/

#define _POSIX_C_SOURCE 199309
#include <signal.h>
#include <time.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

#define TIMER_SIG SIGRTMAX              /* Our timer notification signal */

#define BUF_SIZE 1000
/* Return a string containing the current time formatted according to
   the specification in 'format' (see strftime(3) for specifiers).
   If 'format' is NULL, we use "%c" as a specifier (which gives the'
   date and time as for ctime(3), but without the trailing newline).
   Returns NULL on error. */

/* Convert a string of the following form to an itimerspec structure:
   "value.sec[/value.nanosec][:interval.sec[/interval.nanosec]]".
   Optional components that are omitted cause 0 to be assigned to the
   corresponding structure fields. */

void
itimerspecFromStr(char *str, struct itimerspec *tsp)
{
    char *dupstr ,*cptr, *sptr;

    dupstr = strdup(str);

    cptr = strchr(dupstr, ':');
    if (cptr != NULL)
        *cptr = '\0';

    sptr = strchr(dupstr, '/');
    if (sptr != NULL)
        *sptr = '\0';

    tsp->it_value.tv_sec = atoi(dupstr);
    tsp->it_value.tv_nsec = (sptr != NULL) ? atoi(sptr + 1) : 0;

    if (cptr == NULL) {
        tsp->it_interval.tv_sec = 0;
        tsp->it_interval.tv_nsec = 0;
    } else {
        sptr = strchr(cptr + 1, '/');
        if (sptr != NULL)
            *sptr = '\0';
        tsp->it_interval.tv_sec = atoi(cptr + 1);
        tsp->it_interval.tv_nsec = (sptr != NULL) ? atoi(sptr + 1) : 0;
    }
    free(dupstr);
}

char *
currTime(const char *format)
{
    static char buf[BUF_SIZE];  /* Nonreentrant */
    time_t t;
    size_t s;
    struct tm *tm;

    t = time(NULL);
    tm = localtime(&t);
    if (tm == NULL)
        return NULL;

    s = strftime(buf, BUF_SIZE, (format != NULL) ? format : "%c", tm);

    return (s == 0) ? NULL : buf;
}

static void
handler(int sig, siginfo_t *si, void *uc)
{
    timer_t *tidptr;

    tidptr = si->si_value.sival_ptr;

    /* UNSAFE: This handler uses non-async-signal-safe functions
       (printf(); see Section 21.1.2) */

    printf("[%s] Got signal %d\n", currTime("%T"), sig);
    printf("    *sival_ptr         = %ld\n", (long) *tidptr);
    printf("    timer_getoverrun() = %d\n", timer_getoverrun(*tidptr));
}

int
main(int argc, char *argv[])
{
    struct itimerspec ts;
    struct sigaction  sa;
    struct sigevent   sev;
    timer_t *tidlist;
    int j;

    if (argc < 2)
    {
        printf("%s secs[/nsecs][:int-secs[/int-nsecs]]...\n", argv[0]);
        printf("usageErr: %s [secs [usecs [int-secs [int-usecs]]]]\n", argv[0]);
        exit(EXIT_SUCCESS);
    }

    tidlist = calloc(argc - 1, sizeof(timer_t));
    if (tidlist == NULL)
    {
        printf("errExit: malloc\n");
        exit(EXIT_FAILURE);
    }

    /* Establish handler for notification signal */

    sa.sa_flags = SA_SIGINFO;
    sa.sa_sigaction = handler;
    sigemptyset(&sa.sa_mask);
    if (sigaction(TIMER_SIG, &sa, NULL) == -1)
    {
        printf("errExit: sigaction\n");
        exit(EXIT_FAILURE);
    }

    /* Create and start one timer for each command-line argument */

    sev.sigev_notify = SIGEV_SIGNAL;    /* Notify via signal */
    sev.sigev_signo = TIMER_SIG;        /* Notify using this signal */

    for (j = 0; j < argc - 1; j++) {
        itimerspecFromStr(argv[j + 1], &ts);

        sev.sigev_value.sival_ptr = &tidlist[j];
                /* Allows handler to get ID of this timer */

        if (timer_create(CLOCK_REALTIME, &sev, &tidlist[j]) == -1)
        {
            printf("errExit: timer_create\n");
            exit(EXIT_FAILURE);
        }
        printf("Timer ID: %ld (%s)\n", (long) tidlist[j], argv[j + 1]);

        if (timer_settime(tidlist[j], 0, &ts, NULL) == -1)
        {
            printf("errExit: timer_settime\n");
            exit(EXIT_FAILURE);
        }
    }

    for (;;)                            /* Wait for incoming timer signals */
        pause();
}

0940

搞定 - gre_keepalive_06.c

再來需要 pcap 來收取特定的 keepalive response

應該就是利用 src ip 以及 gre protocol type 這兩個欄位來收特定的 gre tunnel keepalive response


google libpcap tutorial

1030

花點時間看一下 google 到的這幾篇

先大致 view 一下並為了這幾篇下幾個摘要再決定要花時間深入哪幾篇


簡單作個排序順邊把不要讀的刪掉

要開始花時間 study 了

1155

為了更容易使用 pcap

gre 的 config 欄位要多一個 device 的欄位

1315

再幫忙修改 WAN > WiFi STA web page

假使四周沒有任何 AP 的話

m330 會一直 scan 個不停


m330[release/v0.08] - at 'WAN > WiFi STA' web page, do not get the status until vm.status.scan_count != 0

commit c6ea949b90bf53ade1c859d9cd60beb0f31eea2b
Refs: [release/v0.08], {origin/release/v0.08}
Author: jeffrey <[email protected]>
Date:   Mon Jan 6 13:28:49 2020 +0800

    at 'WAN > WiFi STA' web page, do not get the status until vm.status.scan_count != 0

 proscend/prosrc/www/app/feature/wifi_sta.js | 23 +++++++++--------------
 1 file changed, 9 insertions(+), 14 deletions(-)

1420

在 study 官方教學文件 Programming with pcap 的過程

  • 已經對 libpcap 不陌生了
  • 應該不用看其他文件就可以開始 coding 了

1445

時間還夠我再看一下 Using libpcap in C

1615

參考 pcap-filter(7) - Linux man page

想辦法怎麼 filter 出 gre tunnel keepalive response

1700

應該可以開始 coding 了

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