1*de1e4e89SAndroid Build Coastguard Worker /*
2*de1e4e89SAndroid Build Coastguard Worker * seg6.c "ip sr/seg6"
3*de1e4e89SAndroid Build Coastguard Worker *
4*de1e4e89SAndroid Build Coastguard Worker * This program is free software; you can redistribute it and/or
5*de1e4e89SAndroid Build Coastguard Worker * modify it under the terms of the GNU General Public License
6*de1e4e89SAndroid Build Coastguard Worker * version 2 as published by the Free Software Foundation;
7*de1e4e89SAndroid Build Coastguard Worker *
8*de1e4e89SAndroid Build Coastguard Worker * Author: David Lebrun <[email protected]>
9*de1e4e89SAndroid Build Coastguard Worker */
10*de1e4e89SAndroid Build Coastguard Worker
11*de1e4e89SAndroid Build Coastguard Worker #include <stdio.h>
12*de1e4e89SAndroid Build Coastguard Worker #include <stdlib.h>
13*de1e4e89SAndroid Build Coastguard Worker #include <string.h>
14*de1e4e89SAndroid Build Coastguard Worker #include <unistd.h>
15*de1e4e89SAndroid Build Coastguard Worker #include <errno.h>
16*de1e4e89SAndroid Build Coastguard Worker #include <sys/types.h>
17*de1e4e89SAndroid Build Coastguard Worker #include <sys/socket.h>
18*de1e4e89SAndroid Build Coastguard Worker #include <arpa/inet.h>
19*de1e4e89SAndroid Build Coastguard Worker #include <sys/ioctl.h>
20*de1e4e89SAndroid Build Coastguard Worker #include <linux/if.h>
21*de1e4e89SAndroid Build Coastguard Worker
22*de1e4e89SAndroid Build Coastguard Worker #include <linux/genetlink.h>
23*de1e4e89SAndroid Build Coastguard Worker #include <linux/seg6_genl.h>
24*de1e4e89SAndroid Build Coastguard Worker #include <linux/seg6_hmac.h>
25*de1e4e89SAndroid Build Coastguard Worker
26*de1e4e89SAndroid Build Coastguard Worker #include "utils.h"
27*de1e4e89SAndroid Build Coastguard Worker #include "ip_common.h"
28*de1e4e89SAndroid Build Coastguard Worker #include "libgenl.h"
29*de1e4e89SAndroid Build Coastguard Worker
30*de1e4e89SAndroid Build Coastguard Worker #define HMAC_KEY_PROMPT "Enter secret for HMAC key ID (blank to delete): "
31*de1e4e89SAndroid Build Coastguard Worker
usage(void)32*de1e4e89SAndroid Build Coastguard Worker static void usage(void)
33*de1e4e89SAndroid Build Coastguard Worker {
34*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Usage: ip sr { COMMAND | help }\n");
35*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, " ip sr hmac show\n");
36*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, " ip sr hmac set KEYID ALGO\n");
37*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, " ip sr tunsrc show\n");
38*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, " ip sr tunsrc set ADDRESS\n");
39*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "where ALGO := { sha1 | sha256 }\n");
40*de1e4e89SAndroid Build Coastguard Worker exit(-1);
41*de1e4e89SAndroid Build Coastguard Worker }
42*de1e4e89SAndroid Build Coastguard Worker
43*de1e4e89SAndroid Build Coastguard Worker static struct rtnl_handle grth = { .fd = -1 };
44*de1e4e89SAndroid Build Coastguard Worker static int genl_family = -1;
45*de1e4e89SAndroid Build Coastguard Worker
46*de1e4e89SAndroid Build Coastguard Worker #define SEG6_REQUEST(_req, _bufsiz, _cmd, _flags) \
47*de1e4e89SAndroid Build Coastguard Worker GENL_REQUEST(_req, _bufsiz, genl_family, 0, \
48*de1e4e89SAndroid Build Coastguard Worker SEG6_GENL_VERSION, _cmd, _flags)
49*de1e4e89SAndroid Build Coastguard Worker
50*de1e4e89SAndroid Build Coastguard Worker static struct {
51*de1e4e89SAndroid Build Coastguard Worker unsigned int cmd;
52*de1e4e89SAndroid Build Coastguard Worker struct in6_addr addr;
53*de1e4e89SAndroid Build Coastguard Worker __u32 keyid;
54*de1e4e89SAndroid Build Coastguard Worker const char *pass;
55*de1e4e89SAndroid Build Coastguard Worker __u8 alg_id;
56*de1e4e89SAndroid Build Coastguard Worker } opts;
57*de1e4e89SAndroid Build Coastguard Worker
process_msg(const struct sockaddr_nl * who,struct nlmsghdr * n,void * arg)58*de1e4e89SAndroid Build Coastguard Worker static int process_msg(const struct sockaddr_nl *who, struct nlmsghdr *n,
59*de1e4e89SAndroid Build Coastguard Worker void *arg)
60*de1e4e89SAndroid Build Coastguard Worker {
61*de1e4e89SAndroid Build Coastguard Worker struct rtattr *attrs[SEG6_ATTR_MAX + 1];
62*de1e4e89SAndroid Build Coastguard Worker struct genlmsghdr *ghdr;
63*de1e4e89SAndroid Build Coastguard Worker FILE *fp = (FILE *)arg;
64*de1e4e89SAndroid Build Coastguard Worker int len = n->nlmsg_len;
65*de1e4e89SAndroid Build Coastguard Worker
66*de1e4e89SAndroid Build Coastguard Worker if (n->nlmsg_type != genl_family)
67*de1e4e89SAndroid Build Coastguard Worker return -1;
68*de1e4e89SAndroid Build Coastguard Worker
69*de1e4e89SAndroid Build Coastguard Worker len -= NLMSG_LENGTH(GENL_HDRLEN);
70*de1e4e89SAndroid Build Coastguard Worker if (len < 0)
71*de1e4e89SAndroid Build Coastguard Worker return -1;
72*de1e4e89SAndroid Build Coastguard Worker
73*de1e4e89SAndroid Build Coastguard Worker ghdr = NLMSG_DATA(n);
74*de1e4e89SAndroid Build Coastguard Worker
75*de1e4e89SAndroid Build Coastguard Worker parse_rtattr(attrs, SEG6_ATTR_MAX, (void *)ghdr + GENL_HDRLEN, len);
76*de1e4e89SAndroid Build Coastguard Worker
77*de1e4e89SAndroid Build Coastguard Worker switch (ghdr->cmd) {
78*de1e4e89SAndroid Build Coastguard Worker case SEG6_CMD_DUMPHMAC:
79*de1e4e89SAndroid Build Coastguard Worker {
80*de1e4e89SAndroid Build Coastguard Worker char secret[64];
81*de1e4e89SAndroid Build Coastguard Worker char *algstr;
82*de1e4e89SAndroid Build Coastguard Worker __u8 slen = rta_getattr_u8(attrs[SEG6_ATTR_SECRETLEN]);
83*de1e4e89SAndroid Build Coastguard Worker __u8 alg_id = rta_getattr_u8(attrs[SEG6_ATTR_ALGID]);
84*de1e4e89SAndroid Build Coastguard Worker
85*de1e4e89SAndroid Build Coastguard Worker memset(secret, 0, 64);
86*de1e4e89SAndroid Build Coastguard Worker
87*de1e4e89SAndroid Build Coastguard Worker if (slen > 63) {
88*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "HMAC secret length %d > 63, "
89*de1e4e89SAndroid Build Coastguard Worker "truncated\n", slen);
90*de1e4e89SAndroid Build Coastguard Worker slen = 63;
91*de1e4e89SAndroid Build Coastguard Worker }
92*de1e4e89SAndroid Build Coastguard Worker memcpy(secret, RTA_DATA(attrs[SEG6_ATTR_SECRET]), slen);
93*de1e4e89SAndroid Build Coastguard Worker
94*de1e4e89SAndroid Build Coastguard Worker switch (alg_id) {
95*de1e4e89SAndroid Build Coastguard Worker case SEG6_HMAC_ALGO_SHA1:
96*de1e4e89SAndroid Build Coastguard Worker algstr = "sha1";
97*de1e4e89SAndroid Build Coastguard Worker break;
98*de1e4e89SAndroid Build Coastguard Worker case SEG6_HMAC_ALGO_SHA256:
99*de1e4e89SAndroid Build Coastguard Worker algstr = "sha256";
100*de1e4e89SAndroid Build Coastguard Worker break;
101*de1e4e89SAndroid Build Coastguard Worker default:
102*de1e4e89SAndroid Build Coastguard Worker algstr = "<unknown>";
103*de1e4e89SAndroid Build Coastguard Worker }
104*de1e4e89SAndroid Build Coastguard Worker
105*de1e4e89SAndroid Build Coastguard Worker fprintf(fp, "hmac %u ",
106*de1e4e89SAndroid Build Coastguard Worker rta_getattr_u32(attrs[SEG6_ATTR_HMACKEYID]));
107*de1e4e89SAndroid Build Coastguard Worker fprintf(fp, "algo %s ", algstr);
108*de1e4e89SAndroid Build Coastguard Worker fprintf(fp, "secret \"%s\" ", secret);
109*de1e4e89SAndroid Build Coastguard Worker
110*de1e4e89SAndroid Build Coastguard Worker fprintf(fp, "\n");
111*de1e4e89SAndroid Build Coastguard Worker break;
112*de1e4e89SAndroid Build Coastguard Worker }
113*de1e4e89SAndroid Build Coastguard Worker case SEG6_CMD_GET_TUNSRC:
114*de1e4e89SAndroid Build Coastguard Worker {
115*de1e4e89SAndroid Build Coastguard Worker fprintf(fp, "tunsrc addr %s\n",
116*de1e4e89SAndroid Build Coastguard Worker rt_addr_n2a(AF_INET6, 16,
117*de1e4e89SAndroid Build Coastguard Worker RTA_DATA(attrs[SEG6_ATTR_DST])));
118*de1e4e89SAndroid Build Coastguard Worker break;
119*de1e4e89SAndroid Build Coastguard Worker }
120*de1e4e89SAndroid Build Coastguard Worker }
121*de1e4e89SAndroid Build Coastguard Worker
122*de1e4e89SAndroid Build Coastguard Worker return 0;
123*de1e4e89SAndroid Build Coastguard Worker }
124*de1e4e89SAndroid Build Coastguard Worker
seg6_do_cmd(void)125*de1e4e89SAndroid Build Coastguard Worker static int seg6_do_cmd(void)
126*de1e4e89SAndroid Build Coastguard Worker {
127*de1e4e89SAndroid Build Coastguard Worker SEG6_REQUEST(req, 1024, opts.cmd, NLM_F_REQUEST);
128*de1e4e89SAndroid Build Coastguard Worker int repl = 0, dump = 0;
129*de1e4e89SAndroid Build Coastguard Worker
130*de1e4e89SAndroid Build Coastguard Worker if (genl_family < 0) {
131*de1e4e89SAndroid Build Coastguard Worker if (rtnl_open_byproto(&grth, 0, NETLINK_GENERIC) < 0) {
132*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Cannot open generic netlink socket\n");
133*de1e4e89SAndroid Build Coastguard Worker exit(1);
134*de1e4e89SAndroid Build Coastguard Worker }
135*de1e4e89SAndroid Build Coastguard Worker genl_family = genl_resolve_family(&grth, SEG6_GENL_NAME);
136*de1e4e89SAndroid Build Coastguard Worker if (genl_family < 0)
137*de1e4e89SAndroid Build Coastguard Worker exit(1);
138*de1e4e89SAndroid Build Coastguard Worker req.n.nlmsg_type = genl_family;
139*de1e4e89SAndroid Build Coastguard Worker }
140*de1e4e89SAndroid Build Coastguard Worker
141*de1e4e89SAndroid Build Coastguard Worker switch (opts.cmd) {
142*de1e4e89SAndroid Build Coastguard Worker case SEG6_CMD_SETHMAC:
143*de1e4e89SAndroid Build Coastguard Worker {
144*de1e4e89SAndroid Build Coastguard Worker addattr32(&req.n, sizeof(req), SEG6_ATTR_HMACKEYID, opts.keyid);
145*de1e4e89SAndroid Build Coastguard Worker addattr8(&req.n, sizeof(req), SEG6_ATTR_SECRETLEN,
146*de1e4e89SAndroid Build Coastguard Worker strlen(opts.pass));
147*de1e4e89SAndroid Build Coastguard Worker addattr8(&req.n, sizeof(req), SEG6_ATTR_ALGID, opts.alg_id);
148*de1e4e89SAndroid Build Coastguard Worker if (strlen(opts.pass))
149*de1e4e89SAndroid Build Coastguard Worker addattr_l(&req.n, sizeof(req), SEG6_ATTR_SECRET,
150*de1e4e89SAndroid Build Coastguard Worker opts.pass, strlen(opts.pass));
151*de1e4e89SAndroid Build Coastguard Worker break;
152*de1e4e89SAndroid Build Coastguard Worker }
153*de1e4e89SAndroid Build Coastguard Worker case SEG6_CMD_SET_TUNSRC:
154*de1e4e89SAndroid Build Coastguard Worker addattr_l(&req.n, sizeof(req), SEG6_ATTR_DST, &opts.addr,
155*de1e4e89SAndroid Build Coastguard Worker sizeof(struct in6_addr));
156*de1e4e89SAndroid Build Coastguard Worker break;
157*de1e4e89SAndroid Build Coastguard Worker case SEG6_CMD_DUMPHMAC:
158*de1e4e89SAndroid Build Coastguard Worker dump = 1;
159*de1e4e89SAndroid Build Coastguard Worker break;
160*de1e4e89SAndroid Build Coastguard Worker case SEG6_CMD_GET_TUNSRC:
161*de1e4e89SAndroid Build Coastguard Worker repl = 1;
162*de1e4e89SAndroid Build Coastguard Worker break;
163*de1e4e89SAndroid Build Coastguard Worker }
164*de1e4e89SAndroid Build Coastguard Worker
165*de1e4e89SAndroid Build Coastguard Worker if (!repl && !dump) {
166*de1e4e89SAndroid Build Coastguard Worker if (rtnl_talk(&grth, &req.n, NULL, 0) < 0)
167*de1e4e89SAndroid Build Coastguard Worker return -1;
168*de1e4e89SAndroid Build Coastguard Worker } else if (repl) {
169*de1e4e89SAndroid Build Coastguard Worker if (rtnl_talk(&grth, &req.n, &req.n, sizeof(req)) < 0)
170*de1e4e89SAndroid Build Coastguard Worker return -2;
171*de1e4e89SAndroid Build Coastguard Worker if (process_msg(NULL, &req.n, stdout) < 0) {
172*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Error parsing reply\n");
173*de1e4e89SAndroid Build Coastguard Worker exit(1);
174*de1e4e89SAndroid Build Coastguard Worker }
175*de1e4e89SAndroid Build Coastguard Worker } else {
176*de1e4e89SAndroid Build Coastguard Worker req.n.nlmsg_flags |= NLM_F_DUMP;
177*de1e4e89SAndroid Build Coastguard Worker req.n.nlmsg_seq = grth.dump = ++grth.seq;
178*de1e4e89SAndroid Build Coastguard Worker if (rtnl_send(&grth, &req, req.n.nlmsg_len) < 0) {
179*de1e4e89SAndroid Build Coastguard Worker perror("Failed to send dump request");
180*de1e4e89SAndroid Build Coastguard Worker exit(1);
181*de1e4e89SAndroid Build Coastguard Worker }
182*de1e4e89SAndroid Build Coastguard Worker
183*de1e4e89SAndroid Build Coastguard Worker if (rtnl_dump_filter(&grth, process_msg, stdout) < 0) {
184*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Dump terminated\n");
185*de1e4e89SAndroid Build Coastguard Worker exit(1);
186*de1e4e89SAndroid Build Coastguard Worker }
187*de1e4e89SAndroid Build Coastguard Worker }
188*de1e4e89SAndroid Build Coastguard Worker
189*de1e4e89SAndroid Build Coastguard Worker return 0;
190*de1e4e89SAndroid Build Coastguard Worker }
191*de1e4e89SAndroid Build Coastguard Worker
do_seg6(int argc,char ** argv)192*de1e4e89SAndroid Build Coastguard Worker int do_seg6(int argc, char **argv)
193*de1e4e89SAndroid Build Coastguard Worker {
194*de1e4e89SAndroid Build Coastguard Worker if (argc < 1 || matches(*argv, "help") == 0)
195*de1e4e89SAndroid Build Coastguard Worker usage();
196*de1e4e89SAndroid Build Coastguard Worker
197*de1e4e89SAndroid Build Coastguard Worker memset(&opts, 0, sizeof(opts));
198*de1e4e89SAndroid Build Coastguard Worker
199*de1e4e89SAndroid Build Coastguard Worker if (matches(*argv, "hmac") == 0) {
200*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
201*de1e4e89SAndroid Build Coastguard Worker if (matches(*argv, "show") == 0) {
202*de1e4e89SAndroid Build Coastguard Worker opts.cmd = SEG6_CMD_DUMPHMAC;
203*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "set") == 0) {
204*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
205*de1e4e89SAndroid Build Coastguard Worker if (get_u32(&opts.keyid, *argv, 0) || opts.keyid == 0)
206*de1e4e89SAndroid Build Coastguard Worker invarg("hmac KEYID value is invalid", *argv);
207*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
208*de1e4e89SAndroid Build Coastguard Worker if (strcmp(*argv, "sha1") == 0) {
209*de1e4e89SAndroid Build Coastguard Worker opts.alg_id = SEG6_HMAC_ALGO_SHA1;
210*de1e4e89SAndroid Build Coastguard Worker } else if (strcmp(*argv, "sha256") == 0) {
211*de1e4e89SAndroid Build Coastguard Worker opts.alg_id = SEG6_HMAC_ALGO_SHA256;
212*de1e4e89SAndroid Build Coastguard Worker } else {
213*de1e4e89SAndroid Build Coastguard Worker invarg("hmac ALGO value is invalid", *argv);
214*de1e4e89SAndroid Build Coastguard Worker }
215*de1e4e89SAndroid Build Coastguard Worker opts.cmd = SEG6_CMD_SETHMAC;
216*de1e4e89SAndroid Build Coastguard Worker #ifndef __BIONIC__
217*de1e4e89SAndroid Build Coastguard Worker opts.pass = getpass(HMAC_KEY_PROMPT);
218*de1e4e89SAndroid Build Coastguard Worker #endif
219*de1e4e89SAndroid Build Coastguard Worker } else {
220*de1e4e89SAndroid Build Coastguard Worker invarg("unknown", *argv);
221*de1e4e89SAndroid Build Coastguard Worker }
222*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "tunsrc") == 0) {
223*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
224*de1e4e89SAndroid Build Coastguard Worker if (matches(*argv, "show") == 0) {
225*de1e4e89SAndroid Build Coastguard Worker opts.cmd = SEG6_CMD_GET_TUNSRC;
226*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "set") == 0) {
227*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
228*de1e4e89SAndroid Build Coastguard Worker opts.cmd = SEG6_CMD_SET_TUNSRC;
229*de1e4e89SAndroid Build Coastguard Worker if (!inet_get_addr(*argv, NULL, &opts.addr))
230*de1e4e89SAndroid Build Coastguard Worker invarg("tunsrc ADDRESS value is invalid",
231*de1e4e89SAndroid Build Coastguard Worker *argv);
232*de1e4e89SAndroid Build Coastguard Worker } else {
233*de1e4e89SAndroid Build Coastguard Worker invarg("unknown", *argv);
234*de1e4e89SAndroid Build Coastguard Worker }
235*de1e4e89SAndroid Build Coastguard Worker } else {
236*de1e4e89SAndroid Build Coastguard Worker invarg("unknown", *argv);
237*de1e4e89SAndroid Build Coastguard Worker }
238*de1e4e89SAndroid Build Coastguard Worker
239*de1e4e89SAndroid Build Coastguard Worker return seg6_do_cmd();
240*de1e4e89SAndroid Build Coastguard Worker }
241