Line data Source code
1 : /*
2 : * Copyright (C) 2021 Abhinay Ramesh
3 : *
4 : * This file is part of GNU Zebra.
5 : *
6 : * GNU Zebra is free software; you can redistribute it and/or modify it
7 : * under the terms of the GNU General Public License as published by the
8 : * Free Software Foundation; either version 2, or (at your option) any
9 : * later version.
10 : *
11 : * GNU Zebra is distributed in the hope that it will be useful, but
12 : * WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : * General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU General Public License along
17 : * with this program; see the file COPYING; if not, write to the Free Software
18 : * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 : */
20 :
21 : #include "zebra.h"
22 : #include "config.h"
23 : #include "memory.h"
24 : #include "ospf6d.h"
25 : #include "vty.h"
26 : #include "command.h"
27 : #include "md5.h"
28 : #include "sha256.h"
29 : #include "lib/zlog.h"
30 : #include "ospf6_message.h"
31 : #include "ospf6_interface.h"
32 : #include "ospf6_neighbor.h"
33 : #include "ospf6_proto.h"
34 : #include "ospf6_top.h"
35 : #include "ospf6_area.h"
36 : #include "ospf6_auth_trailer.h"
37 : #include "ospf6_route.h"
38 : #include "ospf6_zebra.h"
39 : #include "lib/keychain.h"
40 :
41 : unsigned char conf_debug_ospf6_auth[2];
42 24 : DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_AUTH_HASH_XOR, "OSPF6 auth hash xor");
43 :
44 : /*Apad is the hexadecimal value 0x878FE1F3. */
45 : const uint8_t ospf6_hash_apad_max[KEYCHAIN_MAX_HASH_SIZE] = {
46 : 0x87, 0x8f, 0xe1, 0xf3, 0x87, 0x8f, 0xe1, 0xf3, 0x87, 0x8f, 0xe1,
47 : 0xf3, 0x87, 0x8f, 0xe1, 0xf3, 0x87, 0x8f, 0xe1, 0xf3, 0x87, 0x8f,
48 : 0xe1, 0xf3, 0x87, 0x8f, 0xe1, 0xf3, 0x87, 0x8f, 0xe1, 0xf3, 0x87,
49 : 0x8f, 0xe1, 0xf3, 0x87, 0x8f, 0xe1, 0xf3, 0x87, 0x8f, 0xe1, 0xf3,
50 : 0x87, 0x8f, 0xe1, 0xf3, 0x87, 0x8f, 0xe1, 0xf3, 0x87, 0x8f, 0xe1,
51 : 0xf3, 0x87, 0x8f, 0xe1, 0xf3, 0x87, 0x8f, 0xe1, 0xf3,
52 : };
53 :
54 : const uint8_t ospf6_hash_ipad_max[KEYCHAIN_ALGO_MAX_INTERNAL_BLK_SIZE] = {
55 : 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
56 : 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
57 : 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
58 : 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
59 : 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
60 : 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
61 : 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
62 : 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
63 : 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
64 : 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
65 : 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
66 : };
67 :
68 : const uint8_t ospf6_hash_opad_max[KEYCHAIN_ALGO_MAX_INTERNAL_BLK_SIZE] = {
69 : 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
70 : 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
71 : 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
72 : 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
73 : 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
74 : 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
75 : 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
76 : 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
77 : 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
78 : 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
79 : 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
80 : };
81 :
82 0 : void ospf6_auth_hdr_dump_send(struct ospf6_header *ospfh, uint16_t length)
83 : {
84 0 : struct ospf6_auth_hdr *ospf6_at_hdr;
85 0 : uint16_t at_len, oh_len, at_hdr_len, hash_len;
86 0 : unsigned char temp[KEYCHAIN_MAX_HASH_SIZE + 1];
87 :
88 0 : oh_len = htons(ospfh->length);
89 0 : at_len = length - oh_len;
90 0 : if (at_len > 0) {
91 0 : ospf6_at_hdr = (struct ospf6_auth_hdr *)
92 : ((uint8_t *)ospfh + oh_len);
93 0 : at_hdr_len = htons(ospf6_at_hdr->length);
94 0 : hash_len = at_hdr_len - OSPF6_AUTH_HDR_MIN_SIZE;
95 0 : memcpy(temp, ospf6_at_hdr->data, hash_len);
96 0 : temp[hash_len] = '\0';
97 0 : zlog_debug("OSPF6 Authentication Trailer");
98 0 : zlog_debug(" Type %d", htons(ospf6_at_hdr->type));
99 0 : zlog_debug(" Length %d", at_hdr_len);
100 0 : zlog_debug(" Reserved %d", ospf6_at_hdr->reserved);
101 0 : zlog_debug(" SA ID %d", htons(ospf6_at_hdr->id));
102 0 : zlog_debug(" seqnum high 0x%08x",
103 : htonl(ospf6_at_hdr->seqnum_h));
104 0 : zlog_debug(" seqnum high 0x%08x",
105 : htonl(ospf6_at_hdr->seqnum_l));
106 0 : zlog_debug(" Data %s", temp);
107 : }
108 0 : }
109 :
110 0 : void ospf6_auth_hdr_dump_recv(struct ospf6_header *ospfh, uint16_t length,
111 : unsigned int lls_len)
112 : {
113 0 : struct ospf6_auth_hdr *ospf6_at_hdr;
114 0 : uint16_t at_len, oh_len, at_hdr_len, hash_len;
115 0 : unsigned char temp[KEYCHAIN_MAX_HASH_SIZE + 1];
116 :
117 0 : oh_len = ntohs(ospfh->length);
118 0 : at_len = length - (oh_len + lls_len);
119 0 : if (at_len > 0) {
120 0 : ospf6_at_hdr =
121 0 : (struct ospf6_auth_hdr *)((uint8_t *)ospfh + oh_len);
122 0 : at_hdr_len = ntohs(ospf6_at_hdr->length);
123 0 : hash_len = at_hdr_len - (uint16_t)OSPF6_AUTH_HDR_MIN_SIZE;
124 0 : if (hash_len > KEYCHAIN_MAX_HASH_SIZE) {
125 0 : zlog_debug(
126 : "Specified value for hash_len %u is greater than expected %u",
127 : hash_len, KEYCHAIN_MAX_HASH_SIZE);
128 0 : return;
129 : }
130 0 : memcpy(temp, ospf6_at_hdr->data, hash_len);
131 0 : temp[hash_len] = '\0';
132 0 : zlog_debug("OSPF6 Authentication Trailer");
133 0 : zlog_debug(" Type %d", ntohs(ospf6_at_hdr->type));
134 0 : zlog_debug(" Length %d", at_hdr_len);
135 0 : zlog_debug(" Reserved %d", ospf6_at_hdr->reserved);
136 0 : zlog_debug(" SA ID %d", ntohs(ospf6_at_hdr->id));
137 0 : zlog_debug(" seqnum high 0x%08x",
138 : ntohl(ospf6_at_hdr->seqnum_h));
139 0 : zlog_debug(" seqnum high 0x%08x",
140 : ntohl(ospf6_at_hdr->seqnum_l));
141 0 : zlog_debug(" Data %s", temp);
142 : }
143 : }
144 :
145 0 : unsigned char *ospf6_hash_message_xor(unsigned char *mes1,
146 : unsigned char *mes2,
147 : uint32_t len)
148 : {
149 0 : unsigned char *result;
150 0 : uint32_t i;
151 :
152 0 : result = XCALLOC(MTYPE_OSPF6_AUTH_HASH_XOR, len);
153 :
154 0 : for (i = 0; i < len; i++)
155 0 : result[i] = mes1[i] ^ mes2[i];
156 :
157 0 : return result;
158 : }
159 :
160 0 : static void md5_digest(unsigned char *mes, uint32_t len,
161 : unsigned char *digest)
162 : {
163 : #ifdef CRYPTO_OPENSSL
164 : unsigned int size = KEYCHAIN_MD5_HASH_SIZE;
165 : EVP_MD_CTX *ctx;
166 : #elif CRYPTO_INTERNAL
167 0 : MD5_CTX ctx;
168 : #endif
169 :
170 : #ifdef CRYPTO_OPENSSL
171 : ctx = EVP_MD_CTX_new();
172 : EVP_DigestInit(ctx, EVP_md5());
173 : EVP_DigestUpdate(ctx, mes, len);
174 : EVP_DigestFinal(ctx, digest, &size);
175 : EVP_MD_CTX_free(ctx);
176 : #elif CRYPTO_INTERNAL
177 0 : memset(&ctx, 0, sizeof(ctx));
178 0 : MD5Init(&ctx);
179 0 : MD5Update(&ctx, mes, len);
180 0 : MD5Final(digest, &ctx);
181 : #endif
182 0 : }
183 :
184 0 : static void sha256_digest(unsigned char *mes, uint32_t len,
185 : unsigned char *digest)
186 : {
187 : #ifdef CRYPTO_OPENSSL
188 : unsigned int size = KEYCHAIN_HMAC_SHA256_HASH_SIZE;
189 : EVP_MD_CTX *ctx;
190 : #elif CRYPTO_INTERNAL
191 0 : SHA256_CTX ctx;
192 : #endif
193 :
194 : #ifdef CRYPTO_OPENSSL
195 : ctx = EVP_MD_CTX_new();
196 : EVP_DigestInit(ctx, EVP_sha256());
197 : EVP_DigestUpdate(ctx, mes, len);
198 : EVP_DigestFinal(ctx, digest, &size);
199 : EVP_MD_CTX_free(ctx);
200 : #elif CRYPTO_INTERNAL
201 0 : memset(&ctx, 0, sizeof(ctx));
202 0 : SHA256_Init(&ctx);
203 0 : SHA256_Update(&ctx, mes, len);
204 0 : SHA256_Final(digest, &ctx);
205 : #endif
206 0 : }
207 :
208 : #ifdef CRYPTO_OPENSSL
209 : static void sha1_digest(unsigned char *mes, uint32_t len,
210 : unsigned char *digest)
211 : {
212 : EVP_MD_CTX *ctx;
213 : unsigned int size = KEYCHAIN_HMAC_SHA1_HASH_SIZE;
214 :
215 : ctx = EVP_MD_CTX_new();
216 : EVP_DigestInit(ctx, EVP_sha1());
217 : EVP_DigestUpdate(ctx, mes, len);
218 : EVP_DigestFinal(ctx, digest, &size);
219 : EVP_MD_CTX_free(ctx);
220 : }
221 :
222 : static void sha384_digest(unsigned char *mes, uint32_t len,
223 : unsigned char *digest)
224 : {
225 : EVP_MD_CTX *ctx;
226 : unsigned int size = KEYCHAIN_HMAC_SHA384_HASH_SIZE;
227 :
228 : ctx = EVP_MD_CTX_new();
229 : EVP_DigestInit(ctx, EVP_sha384());
230 : EVP_DigestUpdate(ctx, mes, len);
231 : EVP_DigestFinal(ctx, digest, &size);
232 : EVP_MD_CTX_free(ctx);
233 : }
234 :
235 : static void sha512_digest(unsigned char *mes, uint32_t len,
236 : unsigned char *digest)
237 : {
238 : EVP_MD_CTX *ctx;
239 : unsigned int size = KEYCHAIN_HMAC_SHA512_HASH_SIZE;
240 :
241 : ctx = EVP_MD_CTX_new();
242 : EVP_DigestInit(ctx, EVP_sha512());
243 : EVP_DigestUpdate(ctx, mes, len);
244 : EVP_DigestFinal(ctx, digest, &size);
245 : EVP_MD_CTX_free(ctx);
246 : }
247 : #endif /* CRYPTO_OPENSSL */
248 :
249 0 : static void ospf6_hash_hmac_sha_digest(enum keychain_hash_algo key,
250 : unsigned char *mes, uint32_t len,
251 : unsigned char *digest)
252 : {
253 0 : if ((key < KEYCHAIN_ALGO_NULL) || (key > KEYCHAIN_ALGO_MAX))
254 : return;
255 :
256 0 : switch (key) {
257 0 : case KEYCHAIN_ALGO_MD5:
258 0 : md5_digest(mes, len, digest);
259 0 : break;
260 : case KEYCHAIN_ALGO_HMAC_SHA1:
261 : #ifdef CRYPTO_OPENSSL
262 : sha1_digest(mes, len, digest);
263 : #endif
264 : break;
265 0 : case KEYCHAIN_ALGO_HMAC_SHA256:
266 0 : sha256_digest(mes, len, digest);
267 0 : break;
268 : case KEYCHAIN_ALGO_HMAC_SHA384:
269 : #ifdef CRYPTO_OPENSSL
270 : sha384_digest(mes, len, digest);
271 : #endif
272 : break;
273 : case KEYCHAIN_ALGO_HMAC_SHA512:
274 : #ifdef CRYPTO_OPENSSL
275 : sha512_digest(mes, len, digest);
276 : #endif
277 : break;
278 : case KEYCHAIN_ALGO_NULL:
279 : case KEYCHAIN_ALGO_MAX:
280 : default:
281 : /* no action */
282 : break;
283 : }
284 : }
285 :
286 0 : uint16_t ospf6_auth_len_get(struct ospf6_interface *oi)
287 : {
288 0 : uint16_t at_len = 0;
289 0 : char *keychain_name = NULL;
290 0 : struct keychain *keychain = NULL;
291 0 : struct key *key = NULL;
292 :
293 0 : if (CHECK_FLAG(oi->at_data.flags, OSPF6_AUTH_TRAILER_KEYCHAIN)) {
294 0 : if (CHECK_FLAG(oi->at_data.flags,
295 : OSPF6_AUTH_TRAILER_KEYCHAIN_VALID)) {
296 0 : at_len = OSPF6_AUTH_HDR_MIN_SIZE
297 0 : + keychain_get_hash_len(oi->at_data.hash_algo);
298 : } else {
299 0 : keychain_name = oi->at_data.keychain;
300 0 : keychain = keychain_lookup(keychain_name);
301 0 : if (keychain) {
302 0 : key = key_lookup_for_send(keychain);
303 0 : if (key && key->string
304 0 : && key->hash_algo != KEYCHAIN_ALGO_NULL) {
305 0 : at_len = OSPF6_AUTH_HDR_MIN_SIZE
306 0 : + keychain_get_hash_len(
307 : key->hash_algo);
308 : }
309 : }
310 : }
311 0 : } else if (CHECK_FLAG(oi->at_data.flags,
312 : OSPF6_AUTH_TRAILER_MANUAL_KEY)) {
313 0 : at_len = OSPF6_AUTH_HDR_MIN_SIZE
314 0 : + keychain_get_hash_len(oi->at_data.hash_algo);
315 : }
316 :
317 0 : return at_len;
318 : }
319 :
320 429 : int ospf6_auth_validate_pkt(struct ospf6_interface *oi, unsigned int *pkt_len,
321 : struct ospf6_header *oh, unsigned int *at_len,
322 : unsigned int *lls_block_len)
323 : {
324 429 : struct ospf6_hello *hello = NULL;
325 429 : struct ospf6_dbdesc *dbdesc = NULL;
326 429 : struct ospf6_neighbor *on = NULL;
327 429 : struct ospf6_auth_hdr ospf6_auth_info;
328 429 : uint16_t hdr_len = 0;
329 429 : uint32_t oh_seqnum_h = 0;
330 429 : uint32_t oh_seqnum_l = 0;
331 429 : bool auth_present = false;
332 429 : bool lls_present = false;
333 429 : struct ospf6_lls_hdr *lls_hdr = NULL;
334 :
335 429 : on = ospf6_neighbor_lookup(oh->router_id, oi);
336 429 : hdr_len = ntohs(oh->length);
337 429 : if (*pkt_len < hdr_len) {
338 0 : if (IS_OSPF6_DEBUG_AUTH_RX)
339 0 : zlog_err("RECV[%pOI] Received incomplete %s packet",
340 : oi, ospf6_message_type(oh->type));
341 0 : return OSPF6_AUTH_VALIDATE_FAILURE;
342 429 : } else if (*pkt_len == hdr_len) {
343 429 : if (oi->at_data.flags != 0)
344 : return OSPF6_AUTH_VALIDATE_FAILURE;
345 : /* No auth info to be considered.
346 : */
347 : return OSPF6_AUTH_PROCESS_NORMAL;
348 : }
349 :
350 0 : switch (oh->type) {
351 0 : case OSPF6_MESSAGE_TYPE_HELLO:
352 0 : hello = (struct ospf6_hello *)((uint8_t *)oh
353 : + sizeof(struct ospf6_header));
354 0 : if (OSPF6_OPT_ISSET_EXT(hello->options, OSPF6_OPT_L))
355 0 : lls_present = true;
356 :
357 0 : if (OSPF6_OPT_ISSET_EXT(hello->options, OSPF6_OPT_AT))
358 0 : auth_present = true;
359 : break;
360 0 : case OSPF6_MESSAGE_TYPE_DBDESC:
361 0 : dbdesc = (struct ospf6_dbdesc *)((uint8_t *)oh
362 : + sizeof(struct ospf6_header));
363 0 : if (OSPF6_OPT_ISSET_EXT(dbdesc->options, OSPF6_OPT_L))
364 0 : lls_present = true;
365 :
366 0 : if (OSPF6_OPT_ISSET_EXT(dbdesc->options, OSPF6_OPT_AT))
367 0 : auth_present = true;
368 : break;
369 0 : case OSPF6_MESSAGE_TYPE_LSREQ:
370 : case OSPF6_MESSAGE_TYPE_LSUPDATE:
371 : case OSPF6_MESSAGE_TYPE_LSACK:
372 0 : if (on) {
373 0 : lls_present = on->lls_present;
374 0 : auth_present = on->auth_present;
375 : }
376 : break;
377 0 : default:
378 0 : if (IS_OSPF6_DEBUG_AUTH_RX)
379 0 : zlog_err("RECV[%pOI] : Wrong packet type %d",
380 : oi, oh->type);
381 : return OSPF6_AUTH_VALIDATE_FAILURE;
382 : }
383 :
384 0 : if ((oh->type == OSPF6_MESSAGE_TYPE_HELLO)
385 0 : || (oh->type == OSPF6_MESSAGE_TYPE_DBDESC)) {
386 0 : if (on) {
387 0 : on->auth_present = auth_present;
388 0 : on->lls_present = lls_present;
389 : }
390 : }
391 :
392 0 : if ((!auth_present && (oi->at_data.flags != 0))
393 0 : || (auth_present && (oi->at_data.flags == 0))) {
394 0 : if (IS_OSPF6_DEBUG_AUTH_RX)
395 0 : zlog_err("RECV[%pOI] : Auth option miss-match in %s pkt",
396 : oi, ospf6_message_type(oh->type));
397 0 : return OSPF6_AUTH_VALIDATE_FAILURE;
398 : }
399 :
400 0 : if (lls_present) {
401 0 : lls_hdr = (struct ospf6_lls_hdr *)(oh + hdr_len);
402 0 : *lls_block_len = ntohs(lls_hdr->length) * 4;
403 : }
404 :
405 0 : if (*lls_block_len > (*pkt_len - hdr_len)) {
406 0 : if (IS_OSPF6_DEBUG_AUTH_RX)
407 0 : zlog_err("RECV[%pOI] : Wrong lls data in %s packet",
408 : oi, ospf6_message_type(oh->type));
409 0 : return OSPF6_AUTH_VALIDATE_FAILURE;
410 : }
411 :
412 0 : memset(&ospf6_auth_info, 0, sizeof(ospf6_auth_info));
413 0 : if ((*pkt_len - hdr_len - (*lls_block_len)) > sizeof(ospf6_auth_info)) {
414 0 : if (IS_OSPF6_DEBUG_AUTH_RX)
415 0 : zlog_err("RECV[%pOI] : Wrong auth data in %s packet",
416 : oi, ospf6_message_type(oh->type));
417 0 : return OSPF6_AUTH_VALIDATE_FAILURE;
418 : }
419 :
420 0 : memcpy(&ospf6_auth_info, ((uint8_t *)oh + hdr_len + (*lls_block_len)),
421 : (*pkt_len - hdr_len - (*lls_block_len)));
422 0 : if (ntohs(ospf6_auth_info.length) > OSPF6_AUTH_HDR_FULL) {
423 0 : if (IS_OSPF6_DEBUG_AUTH_RX)
424 0 : zlog_err("RECV[%pOI] : Wrong auth header length in %s",
425 : oi, ospf6_message_type(oh->type));
426 0 : return OSPF6_AUTH_VALIDATE_FAILURE;
427 : }
428 :
429 : /* after authentication header validation is done
430 : * reduce the auth hdr size from the packet length
431 : */
432 0 : *at_len = ntohs(ospf6_auth_info.length);
433 0 : *pkt_len = (*pkt_len) - (*at_len) - (*lls_block_len);
434 :
435 0 : if (on) {
436 0 : oh_seqnum_h = ntohl(ospf6_auth_info.seqnum_h);
437 0 : oh_seqnum_l = ntohl(ospf6_auth_info.seqnum_l);
438 0 : if ((oh_seqnum_h >= on->seqnum_h[oh->type])
439 0 : && (oh_seqnum_l > on->seqnum_l[oh->type])) {
440 : /* valid sequence number received */
441 0 : on->seqnum_h[oh->type] = oh_seqnum_h;
442 0 : on->seqnum_l[oh->type] = oh_seqnum_l;
443 : } else {
444 0 : if (IS_OSPF6_DEBUG_AUTH_RX) {
445 0 : zlog_err(
446 : "RECV[%pOI] : Nbr(%s) Auth Sequence number mismatch in %s ",
447 : oi, on->name,
448 : ospf6_message_type(oh->type));
449 0 : zlog_err(
450 : "nbr_seq_l %u, nbr_seq_h %u, hdr_seq_l %u, hdr_seq_h %u",
451 : on->seqnum_l[oh->type],
452 : on->seqnum_h[oh->type], oh_seqnum_l,
453 : oh_seqnum_h);
454 : }
455 :
456 0 : return OSPF6_AUTH_VALIDATE_FAILURE;
457 : }
458 : }
459 :
460 : return OSPF6_AUTH_VALIDATE_SUCCESS;
461 : }
462 :
463 : /* Starting point of packet process function. */
464 0 : int ospf6_auth_check_digest(struct ospf6_header *oh, struct ospf6_interface *oi,
465 : struct in6_addr *src, unsigned int lls_block_len)
466 0 : {
467 0 : uint32_t hash_len = KEYCHAIN_MAX_HASH_SIZE;
468 0 : unsigned char apad[hash_len];
469 0 : unsigned char temp_hash[hash_len];
470 0 : struct ospf6_auth_hdr *ospf6_auth;
471 0 : uint32_t ipv6_addr_size = sizeof(struct in6_addr);
472 0 : struct keychain *keychain = NULL;
473 0 : struct key *key = NULL;
474 0 : char *auth_str = NULL;
475 0 : uint16_t auth_len = 0;
476 0 : uint8_t hash_algo = 0;
477 0 : uint16_t oh_len = ntohs(oh->length);
478 0 : int ret = 0;
479 :
480 0 : if (oi->at_data.flags == 0)
481 : return OSPF6_AUTH_PROCESS_NORMAL;
482 :
483 0 : ospf6_auth = (struct ospf6_auth_hdr *)((uint8_t *)oh +
484 0 : (oh_len + lls_block_len));
485 0 : if (CHECK_FLAG(oi->at_data.flags, OSPF6_AUTH_TRAILER_KEYCHAIN)) {
486 0 : keychain = keychain_lookup(oi->at_data.keychain);
487 0 : if (!keychain) {
488 0 : if (IS_OSPF6_DEBUG_AUTH_RX)
489 0 : zlog_err(
490 : "RECV[%pOI]: Keychain doesn't exist for %s",
491 : oi, ospf6_message_type(oh->type));
492 0 : return OSPF6_AUTH_VALIDATE_FAILURE;
493 : }
494 :
495 0 : key = key_lookup_for_accept(keychain, ntohs(ospf6_auth->id));
496 0 : if (!key) {
497 0 : if (IS_OSPF6_DEBUG_AUTH_RX)
498 0 : zlog_err("RECV[%pOI]: Auth, Invalid SA for %s",
499 : oi, ospf6_message_type(oh->type));
500 0 : return OSPF6_AUTH_VALIDATE_FAILURE;
501 : }
502 :
503 0 : if (key && key->string
504 0 : && key->hash_algo != KEYCHAIN_ALGO_NULL) {
505 0 : auth_str = key->string;
506 0 : hash_algo = key->hash_algo;
507 : } else {
508 0 : if (IS_OSPF6_DEBUG_AUTH_RX)
509 0 : zlog_err(
510 : "RECV[%pOI]: Incomplete keychain config for %s",
511 : oi, ospf6_message_type(oh->type));
512 0 : return OSPF6_AUTH_VALIDATE_FAILURE;
513 : }
514 0 : } else if (CHECK_FLAG(oi->at_data.flags,
515 : OSPF6_AUTH_TRAILER_MANUAL_KEY)) {
516 0 : auth_str = oi->at_data.auth_key;
517 0 : hash_algo = oi->at_data.hash_algo;
518 : }
519 :
520 0 : if (!auth_str)
521 0 : return OSPF6_AUTH_VALIDATE_FAILURE;
522 :
523 0 : hash_len = keychain_get_hash_len(hash_algo);
524 0 : memset(apad, 0, sizeof(apad));
525 0 : memset(temp_hash, 0, sizeof(temp_hash));
526 :
527 : /* start digest verification */
528 0 : memcpy(apad, src, ipv6_addr_size);
529 0 : memcpy(apad + ipv6_addr_size, ospf6_hash_apad_max,
530 0 : (hash_len - ipv6_addr_size));
531 :
532 0 : auth_len = ntohs(ospf6_auth->length);
533 :
534 0 : memcpy(temp_hash, ospf6_auth->data, hash_len);
535 0 : memcpy(ospf6_auth->data, apad, hash_len);
536 :
537 0 : ospf6_auth_update_digest(oi, oh, ospf6_auth, auth_str,
538 0 : (oh_len + auth_len + lls_block_len),
539 : hash_algo);
540 :
541 : #ifdef CRYPTO_OPENSSL
542 : ret = CRYPTO_memcmp(temp_hash, ospf6_auth->data, hash_len);
543 : #else
544 0 : ret = memcmp(temp_hash, ospf6_auth->data, hash_len);
545 : #endif
546 0 : if (ret == 0)
547 : return OSPF6_AUTH_VALIDATE_SUCCESS;
548 :
549 : return OSPF6_AUTH_VALIDATE_FAILURE;
550 : }
551 :
552 0 : void ospf6_auth_digest_send(struct in6_addr *src, struct ospf6_interface *oi,
553 : struct ospf6_header *oh, uint16_t auth_len,
554 : uint32_t pkt_len)
555 0 : {
556 0 : struct ospf6_auth_hdr *ospf6_auth;
557 0 : char *keychain_name = NULL;
558 0 : struct keychain *keychain = NULL;
559 0 : struct key *key = NULL;
560 0 : char *auth_str = NULL;
561 0 : uint16_t key_id = 0;
562 0 : enum keychain_hash_algo hash_algo = KEYCHAIN_ALGO_NULL;
563 0 : uint32_t hash_len = KEYCHAIN_MAX_HASH_SIZE;
564 0 : unsigned char apad[hash_len];
565 0 : int ipv6_addr_size = sizeof(struct in6_addr);
566 0 : struct ospf6 *ospf6 = NULL;
567 :
568 0 : if (CHECK_FLAG(oi->at_data.flags, OSPF6_AUTH_TRAILER_KEYCHAIN)) {
569 0 : if (CHECK_FLAG(oi->at_data.flags,
570 : OSPF6_AUTH_TRAILER_KEYCHAIN_VALID)) {
571 0 : auth_str = oi->at_data.auth_key;
572 0 : hash_algo = oi->at_data.hash_algo;
573 0 : key_id = oi->at_data.key_id;
574 : } else {
575 0 : keychain_name = oi->at_data.keychain;
576 0 : keychain = keychain_lookup(keychain_name);
577 0 : if (keychain) {
578 0 : key = key_lookup_for_send(keychain);
579 0 : if (key && key->string
580 0 : && key->hash_algo != KEYCHAIN_ALGO_NULL) {
581 0 : auth_str = key->string;
582 0 : hash_algo = key->hash_algo;
583 0 : key_id = key->index;
584 : }
585 : }
586 : }
587 0 : } else if (CHECK_FLAG(oi->at_data.flags,
588 : OSPF6_AUTH_TRAILER_MANUAL_KEY)) {
589 0 : auth_str = oi->at_data.auth_key;
590 0 : hash_algo = oi->at_data.hash_algo;
591 0 : key_id = oi->at_data.key_id;
592 : } else {
593 0 : if (IS_OSPF6_DEBUG_AUTH_TX)
594 0 : zlog_warn("SEND[%pOI]: Authentication not configured for %s",
595 : oi, ospf6_message_type(oh->type));
596 0 : return;
597 : }
598 :
599 0 : if (!auth_str) {
600 0 : if (IS_OSPF6_DEBUG_AUTH_TX)
601 0 : zlog_warn("SEND[%pOI]: Authentication key is not configured for %s",
602 : oi, ospf6_message_type(oh->type));
603 0 : return;
604 : }
605 :
606 0 : hash_len = keychain_get_hash_len(hash_algo);
607 0 : if (oi->area && oi->area->ospf6)
608 0 : ospf6 = oi->area->ospf6;
609 : else
610 : return;
611 :
612 0 : ospf6->seqnum_l++;
613 0 : if (ospf6->seqnum_l == 0xFFFFFFFF) {
614 0 : ospf6->seqnum_h++;
615 0 : ospf6->seqnum_l = 0;
616 0 : ospf6_auth_seqno_nvm_update(ospf6);
617 : }
618 :
619 : /* Key must be reset. which is not handled as of now. */
620 0 : if ((ospf6->seqnum_l == 0xFFFFFFFF)
621 0 : && (ospf6->seqnum_h == 0xFFFFFFFF)) {
622 0 : ospf6->seqnum_l = 0;
623 0 : ospf6->seqnum_h = 0;
624 0 : zlog_err(
625 : "Both Higher and Lower sequence number has wrapped. Need to reset the key");
626 : }
627 :
628 0 : memset(apad, 0, sizeof(apad));
629 :
630 0 : if (src)
631 0 : memcpy(apad, src, ipv6_addr_size);
632 :
633 0 : memcpy(apad + ipv6_addr_size, ospf6_hash_apad_max,
634 0 : (hash_len - ipv6_addr_size));
635 :
636 0 : ospf6_auth =
637 0 : (struct ospf6_auth_hdr *)((uint8_t *)oh + ntohs(oh->length));
638 0 : ospf6_auth->type = htons(OSPF6_AUTHENTICATION_CRYPTOGRAPHIC);
639 0 : ospf6_auth->length = htons(auth_len);
640 0 : ospf6_auth->reserved = 0;
641 0 : ospf6_auth->id = htons(key_id);
642 0 : ospf6_auth->seqnum_h = htonl(ospf6->seqnum_h);
643 0 : ospf6_auth->seqnum_l = htonl(ospf6->seqnum_l);
644 0 : memcpy(ospf6_auth->data, apad, hash_len);
645 :
646 0 : ospf6_auth_update_digest(oi, oh, ospf6_auth, auth_str, pkt_len,
647 : hash_algo);
648 :
649 : /* There is a optimisation that is done to ensure that
650 : * for every packet flow keychain lib API are called
651 : * only once and the result are stored in oi->at_data.
652 : * So, After processing the flow it is reset back here.
653 : */
654 0 : if (CHECK_FLAG(oi->at_data.flags, OSPF6_AUTH_TRAILER_KEYCHAIN_VALID)) {
655 0 : oi->at_data.hash_algo = KEYCHAIN_ALGO_NULL;
656 0 : if (oi->at_data.auth_key) {
657 0 : XFREE(MTYPE_OSPF6_AUTH_MANUAL_KEY,
658 : oi->at_data.auth_key);
659 0 : oi->at_data.auth_key = NULL;
660 : }
661 :
662 0 : oi->at_data.key_id = 0;
663 0 : UNSET_FLAG(oi->at_data.flags,
664 : OSPF6_AUTH_TRAILER_KEYCHAIN_VALID);
665 : }
666 : }
667 :
668 0 : void ospf6_auth_update_digest(struct ospf6_interface *oi,
669 : struct ospf6_header *oh,
670 : struct ospf6_auth_hdr *ospf6_auth, char *auth_str,
671 : uint32_t pkt_len, enum keychain_hash_algo algo)
672 0 : {
673 0 : static const uint16_t cpid = 1;
674 0 : uint32_t hash_len = keychain_get_hash_len(algo);
675 0 : uint32_t block_s = keychain_get_block_size(algo);
676 0 : uint32_t k_len = strlen(auth_str);
677 0 : uint32_t ks_len = strlen(auth_str) + sizeof(cpid);
678 0 : unsigned char ipad[block_s];
679 0 : unsigned char opad[block_s];
680 0 : unsigned char ko[block_s], ks[ks_len], tmp[hash_len];
681 0 : unsigned char *first = NULL;
682 0 : unsigned char *second = NULL;
683 0 : unsigned char first_mes[block_s + pkt_len];
684 0 : unsigned char second_mes[block_s + pkt_len];
685 0 : unsigned char first_hash[hash_len];
686 0 : unsigned char second_hash[hash_len];
687 :
688 0 : memset(ko, 0, sizeof(ko));
689 0 : memcpy(ks, auth_str, k_len);
690 0 : memcpy(ks + k_len, &cpid, sizeof(cpid));
691 0 : if (ks_len > hash_len) {
692 0 : ospf6_hash_hmac_sha_digest(algo, ks, ks_len, tmp);
693 0 : memcpy(ko, tmp, hash_len);
694 : } else
695 0 : memcpy(ko, ks, ks_len);
696 :
697 0 : memcpy(ipad, ospf6_hash_ipad_max, block_s);
698 0 : memcpy(opad, ospf6_hash_opad_max, block_s);
699 :
700 0 : first = ospf6_hash_message_xor((unsigned char *)&ipad, ko, block_s);
701 0 : second = ospf6_hash_message_xor((unsigned char *)&opad, ko, block_s);
702 :
703 0 : memcpy(first_mes, first, block_s);
704 0 : memcpy(first_mes + block_s, oh, pkt_len);
705 :
706 0 : ospf6_hash_hmac_sha_digest(algo, first_mes, (block_s + pkt_len),
707 : first_hash);
708 :
709 0 : memcpy(second_mes, second, block_s);
710 0 : memcpy(second_mes + block_s, first_hash, hash_len);
711 :
712 0 : ospf6_hash_hmac_sha_digest(algo, second_mes, (block_s + hash_len),
713 : second_hash);
714 :
715 0 : memcpy(ospf6_auth->data, second_hash, hash_len);
716 0 : XFREE(MTYPE_OSPF6_AUTH_HASH_XOR, first);
717 0 : XFREE(MTYPE_OSPF6_AUTH_HASH_XOR, second);
718 0 : }
719 :
720 0 : DEFUN (debug_ospf6_auth,
721 : debug_ospf6_auth_cmd,
722 : "debug ospf6 authentication [<tx|rx>]",
723 : DEBUG_STR
724 : OSPF6_STR
725 : "debug OSPF6 authentication\n"
726 : "debug authentication tx\n"
727 : "debug authentication rx\n")
728 : {
729 0 : int auth_opt_idx = 3;
730 :
731 0 : if (argc == 4) {
732 0 : if (!strncmp(argv[auth_opt_idx]->arg, "t", 1))
733 0 : OSPF6_DEBUG_AUTH_TX_ON();
734 0 : else if (!strncmp(argv[auth_opt_idx]->arg, "r", 1))
735 0 : OSPF6_DEBUG_AUTH_RX_ON();
736 : } else {
737 0 : OSPF6_DEBUG_AUTH_TX_ON();
738 0 : OSPF6_DEBUG_AUTH_RX_ON();
739 : }
740 :
741 0 : return CMD_SUCCESS;
742 : }
743 :
744 0 : DEFUN (no_debug_ospf6_auth,
745 : no_debug_ospf6_auth_cmd,
746 : "no debug ospf6 authentication [<tx|rx>]",
747 : NO_STR
748 : DEBUG_STR
749 : OSPF6_STR
750 : "debug OSPF6 authentication\n"
751 : "debug authentication tx\n"
752 : "debug authentication rx\n")
753 : {
754 0 : int auth_opt_idx = 3;
755 :
756 0 : if (argc == 5) {
757 0 : if (!strncmp(argv[auth_opt_idx]->arg, "t", 1))
758 0 : OSPF6_DEBUG_AUTH_TX_OFF();
759 0 : else if (!strncmp(argv[auth_opt_idx]->arg, "r", 1))
760 0 : OSPF6_DEBUG_AUTH_RX_OFF();
761 : } else {
762 0 : OSPF6_DEBUG_AUTH_TX_OFF();
763 0 : OSPF6_DEBUG_AUTH_RX_OFF();
764 : }
765 :
766 0 : return CMD_SUCCESS;
767 : }
768 :
769 0 : int config_write_ospf6_debug_auth(struct vty *vty)
770 : {
771 0 : if (IS_OSPF6_DEBUG_AUTH_TX)
772 0 : vty_out(vty, "debug ospf6 authentication tx\n");
773 0 : if (IS_OSPF6_DEBUG_AUTH_RX)
774 0 : vty_out(vty, "debug ospf6 authentication rx\n");
775 0 : return 0;
776 : }
777 :
778 8 : void install_element_ospf6_debug_auth(void)
779 : {
780 8 : install_element(ENABLE_NODE, &debug_ospf6_auth_cmd);
781 8 : install_element(ENABLE_NODE, &no_debug_ospf6_auth_cmd);
782 8 : install_element(CONFIG_NODE, &debug_ospf6_auth_cmd);
783 8 : install_element(CONFIG_NODE, &no_debug_ospf6_auth_cmd);
784 8 : }
785 :
786 : /* Clear the specified interface structure */
787 0 : static void ospf6_intf_auth_clear(struct vty *vty, struct interface *ifp)
788 : {
789 0 : struct ospf6_interface *oi;
790 :
791 0 : if (!if_is_operative(ifp))
792 : return;
793 :
794 0 : if (ifp->info == NULL)
795 : return;
796 :
797 0 : oi = (struct ospf6_interface *)ifp->info;
798 :
799 0 : if (IS_OSPF6_DEBUG_INTERFACE)
800 0 : zlog_debug(
801 : "Interface %s: clear authentication rx/tx drop counters",
802 : ifp->name);
803 :
804 : /* Reset the interface rx/tx drop counters */
805 0 : oi->at_data.tx_drop = 0;
806 0 : oi->at_data.rx_drop = 0;
807 : }
808 :
809 : /* Clear interface */
810 0 : DEFUN(clear_ipv6_ospf6_intf_auth, clear_ipv6_ospf6_intf_auth_cmd,
811 : "clear ipv6 ospf6 [vrf VRF] auth-counters interface [IFNAME]",
812 : CLEAR_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR
813 : "authentication rx/tx drop counters\n" INTERFACE_STR IFNAME_STR)
814 : {
815 0 : int idx_ifname = 0;
816 0 : int idx_vrf = 0;
817 0 : struct interface *ifp;
818 0 : struct listnode *node;
819 0 : struct ospf6 *ospf6 = NULL;
820 0 : char *vrf_name = NULL;
821 0 : vrf_id_t vrf_id = VRF_DEFAULT;
822 0 : struct vrf *vrf = NULL;
823 :
824 0 : if (argv_find(argv, argc, "vrf", &idx_vrf))
825 0 : vrf_name = argv[idx_vrf + 1]->arg;
826 :
827 0 : if (vrf_name && strmatch(vrf_name, VRF_DEFAULT_NAME))
828 : vrf_name = NULL;
829 :
830 0 : if (vrf_name) {
831 0 : vrf = vrf_lookup_by_name(vrf_name);
832 0 : if (vrf)
833 0 : vrf_id = vrf->vrf_id;
834 : }
835 :
836 0 : if (!argv_find(argv, argc, "IFNAME", &idx_ifname)) {
837 : /* Clear all the ospfv3 interfaces auth data. */
838 0 : for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
839 0 : if (vrf_id != ospf6->vrf_id)
840 0 : continue;
841 :
842 0 : if (!vrf)
843 0 : vrf = vrf_lookup_by_id(ospf6->vrf_id);
844 0 : FOR_ALL_INTERFACES (vrf, ifp)
845 0 : ospf6_intf_auth_clear(vty, ifp);
846 : }
847 : } else {
848 : /* Interface name is specified. */
849 0 : ifp = if_lookup_by_name(argv[idx_ifname]->arg, vrf_id);
850 0 : if (ifp == NULL)
851 0 : vty_out(vty, "No such interface name\n");
852 : else
853 0 : ospf6_intf_auth_clear(vty, ifp);
854 : }
855 :
856 0 : return CMD_SUCCESS;
857 : }
858 :
859 8 : void install_element_ospf6_clear_intf_auth(void)
860 : {
861 8 : install_element(ENABLE_NODE, &clear_ipv6_ospf6_intf_auth_cmd);
862 8 : }
863 :
864 8 : enum ospf6_auth_err ospf6_auth_nvm_file_exist(void)
865 : {
866 8 : struct stat buffer;
867 8 : int exist;
868 :
869 8 : exist = stat(OSPF6_AUTH_SEQ_NUM_FILE, &buffer);
870 8 : if (exist == 0)
871 : return OSPF6_AUTH_FILE_EXIST;
872 : else
873 8 : return OSPF6_AUTH_FILE_DO_NOT_EXIST;
874 : }
875 :
876 : /*
877 : * Record in non-volatile memory the given ospf6 process,
878 : * authentication trailer higher order sequence number.
879 : */
880 8 : void ospf6_auth_seqno_nvm_update(struct ospf6 *ospf6)
881 : {
882 8 : const char *inst_name;
883 8 : json_object *json;
884 8 : json_object *json_instances;
885 8 : json_object *json_instance;
886 :
887 8 : zlog_err("Higher order sequence number %d update for %s process",
888 : ospf6->seqnum_h, ospf6->name);
889 :
890 8 : inst_name = ospf6->name ? ospf6->name : VRF_DEFAULT_NAME;
891 :
892 8 : json = json_object_from_file((char *)OSPF6_AUTH_SEQ_NUM_FILE);
893 8 : if (json == NULL)
894 8 : json = json_object_new_object();
895 :
896 8 : json_object_object_get_ex(json, "instances", &json_instances);
897 8 : if (!json_instances) {
898 8 : json_instances = json_object_new_object();
899 8 : json_object_object_add(json, "instances", json_instances);
900 : }
901 :
902 8 : json_object_object_get_ex(json_instances, inst_name, &json_instance);
903 8 : if (!json_instance) {
904 8 : json_instance = json_object_new_object();
905 8 : json_object_object_add(json_instances, inst_name,
906 : json_instance);
907 : }
908 :
909 : /*
910 : * Record higher order sequence number in non volatile memory.
911 : */
912 8 : json_object_int_add(json_instance, "sequence_number", ospf6->seqnum_h);
913 :
914 8 : json_object_to_file_ext((char *)OSPF6_AUTH_SEQ_NUM_FILE, json,
915 : JSON_C_TO_STRING_PRETTY);
916 8 : json_object_free(json);
917 8 : }
918 :
919 : /*
920 : * Delete authentication sequence number for a given OSPF6 process
921 : * from non-volatile memory.
922 : */
923 0 : void ospf6_auth_seqno_nvm_delete(struct ospf6 *ospf6)
924 : {
925 0 : const char *inst_name;
926 0 : json_object *json;
927 0 : json_object *json_instances;
928 :
929 0 : zlog_err("Higher order sequence number delete for %s process",
930 : ospf6->name);
931 :
932 0 : inst_name = ospf6->name ? ospf6->name : VRF_DEFAULT_NAME;
933 :
934 0 : json = json_object_from_file((char *)OSPF6_AUTH_SEQ_NUM_FILE);
935 0 : if (json == NULL)
936 0 : json = json_object_new_object();
937 :
938 0 : json_object_object_get_ex(json, "instances", &json_instances);
939 0 : if (!json_instances) {
940 0 : json_instances = json_object_new_object();
941 0 : json_object_object_add(json, "instances", json_instances);
942 : }
943 :
944 0 : json_object_object_del(json_instances, inst_name);
945 :
946 0 : json_object_to_file_ext((char *)OSPF6_AUTH_SEQ_NUM_FILE, json,
947 : JSON_C_TO_STRING_PRETTY);
948 0 : json_object_free(json);
949 0 : }
950 :
951 :
952 : /*
953 : * Fetch from non-volatile memory the stored ospf6 process
954 : * authentication sequence number.
955 : */
956 0 : void ospf6_auth_seqno_nvm_read(struct ospf6 *ospf6)
957 : {
958 0 : const char *inst_name;
959 0 : json_object *json;
960 0 : json_object *json_instances;
961 0 : json_object *json_instance;
962 0 : json_object *json_seqnum;
963 :
964 0 : inst_name = ospf6->name ? ospf6->name : VRF_DEFAULT_NAME;
965 :
966 0 : json = json_object_from_file((char *)OSPF6_AUTH_SEQ_NUM_FILE);
967 0 : if (json == NULL)
968 0 : json = json_object_new_object();
969 :
970 0 : json_object_object_get_ex(json, "instances", &json_instances);
971 0 : if (!json_instances) {
972 0 : json_instances = json_object_new_object();
973 0 : json_object_object_add(json, "instances", json_instances);
974 : }
975 :
976 0 : json_object_object_get_ex(json_instances, inst_name, &json_instance);
977 0 : if (!json_instance) {
978 0 : json_instance = json_object_new_object();
979 0 : json_object_object_add(json_instances, inst_name,
980 : json_instance);
981 : }
982 :
983 0 : json_object_object_get_ex(json_instance, "sequence_number",
984 : &json_seqnum);
985 0 : ospf6->seqnum_h = json_object_get_int(json_seqnum);
986 :
987 0 : zlog_err("Higher order sequence number %d read for %s process %s",
988 : ospf6->seqnum_h, ospf6->name, strerror(errno));
989 :
990 0 : json_object_object_del(json_instances, inst_name);
991 0 : json_object_to_file_ext((char *)OSPF6_AUTH_SEQ_NUM_FILE, json,
992 : JSON_C_TO_STRING_PRETTY);
993 0 : json_object_free(json);
994 0 : }
|