huangcm
2025-07-01 676035278781360996553c427a12bf358249ebf7
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/*
 * ipfou.c    FOU (foo over UDP) support
 *
 *              This program is free software; you can redistribute it and/or
 *              modify it under the terms of the GNU General Public License
 *              as published by the Free Software Foundation; either version
 *              2 of the License, or (at your option) any later version.
 *
 * Authors:    Tom Herbert <therbert@google.com>
 */
 
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <net/if.h>
#include <linux/fou.h>
#include <linux/genetlink.h>
#include <linux/ip.h>
#include <arpa/inet.h>
 
#include "libgenl.h"
#include "utils.h"
#include "ip_common.h"
 
static void usage(void)
{
   fprintf(stderr, "Usage: ip fou add port PORT "
       "{ ipproto PROTO  | gue } [ -6 ]\n");
   fprintf(stderr, "       ip fou del port PORT [ -6 ]\n");
   fprintf(stderr, "\n");
   fprintf(stderr, "Where: PROTO { ipproto-name | 1..255 }\n");
   fprintf(stderr, "       PORT { 1..65535 }\n");
 
   exit(-1);
}
 
/* netlink socket */
static struct rtnl_handle genl_rth = { .fd = -1 };
static int genl_family = -1;
 
#define FOU_REQUEST(_req, _bufsiz, _cmd, _flags)    \
   GENL_REQUEST(_req, _bufsiz, genl_family, 0,    \
            FOU_GENL_VERSION, _cmd, _flags)
 
static int fou_parse_opt(int argc, char **argv, struct nlmsghdr *n,
            bool adding)
{
   __u16 port;
   int port_set = 0;
   __u8 ipproto, type;
   bool gue_set = false;
   int ipproto_set = 0;
   unsigned short family = AF_INET;
 
   while (argc > 0) {
       if (!matches(*argv, "port")) {
           NEXT_ARG();
 
           if (get_be16(&port, *argv, 0) || port == 0)
               invarg("invalid port", *argv);
           port_set = 1;
       } else if (!matches(*argv, "ipproto")) {
           struct protoent *servptr;
 
           NEXT_ARG();
 
           servptr = getprotobyname(*argv);
           if (servptr)
               ipproto = servptr->p_proto;
           else if (get_u8(&ipproto, *argv, 0) || ipproto == 0)
               invarg("invalid ipproto", *argv);
           ipproto_set = 1;
       } else if (!matches(*argv, "gue")) {
           gue_set = true;
       } else if (!matches(*argv, "-6")) {
           family = AF_INET6;
       } else {
           fprintf(stderr, "fou: unknown command \"%s\"?\n", *argv);
           usage();
           return -1;
       }
       argc--, argv++;
   }
 
   if (!port_set) {
       fprintf(stderr, "fou: missing port\n");
       return -1;
   }
 
   if (!ipproto_set && !gue_set && adding) {
       fprintf(stderr, "fou: must set ipproto or gue\n");
       return -1;
   }
 
   if (ipproto_set && gue_set) {
       fprintf(stderr, "fou: cannot set ipproto and gue\n");
       return -1;
   }
 
   type = gue_set ? FOU_ENCAP_GUE : FOU_ENCAP_DIRECT;
 
   addattr16(n, 1024, FOU_ATTR_PORT, port);
   addattr8(n, 1024, FOU_ATTR_TYPE, type);
   addattr16(n, 1024, FOU_ATTR_AF, family);
 
   if (ipproto_set)
       addattr8(n, 1024, FOU_ATTR_IPPROTO, ipproto);
 
   return 0;
}
 
static int do_add(int argc, char **argv)
{
   FOU_REQUEST(req, 1024, FOU_CMD_ADD, NLM_F_REQUEST);
 
   fou_parse_opt(argc, argv, &req.n, true);
 
   if (rtnl_talk(&genl_rth, &req.n, NULL, 0) < 0)
       return -2;
 
   return 0;
}
 
static int do_del(int argc, char **argv)
{
   FOU_REQUEST(req, 1024, FOU_CMD_DEL, NLM_F_REQUEST);
 
   fou_parse_opt(argc, argv, &req.n, false);
 
   if (rtnl_talk(&genl_rth, &req.n, NULL, 0) < 0)
       return -2;
 
   return 0;
}
 
int do_ipfou(int argc, char **argv)
{
   if (argc < 1)
       usage();
 
   if (matches(*argv, "help") == 0)
       usage();
 
   if (genl_init_handle(&genl_rth, FOU_GENL_NAME, &genl_family))
       exit(1);
 
   if (matches(*argv, "add") == 0)
       return do_add(argc-1, argv+1);
   if (matches(*argv, "delete") == 0)
       return do_del(argc-1, argv+1);
   fprintf(stderr, "Command \"%s\" is unknown, try \"ip fou help\".\n", *argv);
   exit(-1);
}