Coverage Report

Created: 2025-07-14 06:48

/src/frr/ospfd/ospf_network.c
Line
Count
Source (jump to first uncovered line)
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
 * OSPF network related functions
4
 *   Copyright (C) 1999 Toshiaki Takada
5
 */
6
7
#include <zebra.h>
8
9
#include "frrevent.h"
10
#include "linklist.h"
11
#include "prefix.h"
12
#include "if.h"
13
#include "sockunion.h"
14
#include "log.h"
15
#include "sockopt.h"
16
#include "privs.h"
17
#include "lib_errors.h"
18
#include "lib/table.h"
19
20
#include "ospfd/ospfd.h"
21
#include "ospfd/ospf_network.h"
22
#include "ospfd/ospf_interface.h"
23
#include "ospfd/ospf_asbr.h"
24
#include "ospfd/ospf_lsa.h"
25
#include "ospfd/ospf_lsdb.h"
26
#include "ospfd/ospf_neighbor.h"
27
#include "ospfd/ospf_packet.h"
28
#include "ospfd/ospf_dump.h"
29
30
/* Join to the OSPF ALL SPF ROUTERS multicast group. */
31
int ospf_if_add_allspfrouters(struct ospf *top, struct prefix *p,
32
            ifindex_t ifindex)
33
0
{
34
0
  int ret;
35
36
0
  ret = setsockopt_ipv4_multicast(top->fd, IP_ADD_MEMBERSHIP,
37
0
          p->u.prefix4, htonl(OSPF_ALLSPFROUTERS),
38
0
          ifindex);
39
0
  if (ret < 0)
40
0
    flog_err(
41
0
      EC_LIB_SOCKET,
42
0
      "can't setsockopt IP_ADD_MEMBERSHIP (fd %d, addr %pI4, ifindex %u, AllSPFRouters): %s; perhaps a kernel limit on # of multicast group memberships has been exceeded?",
43
0
      top->fd, &p->u.prefix4, ifindex,
44
0
      safe_strerror(errno));
45
0
  else {
46
0
    if (IS_DEBUG_OSPF_EVENT)
47
0
      zlog_debug(
48
0
        "interface %pI4 [%u] join AllSPFRouters Multicast group.",
49
0
        &p->u.prefix4, ifindex);
50
0
  }
51
52
0
  return ret;
53
0
}
54
55
int ospf_if_drop_allspfrouters(struct ospf *top, struct prefix *p,
56
             ifindex_t ifindex)
57
0
{
58
0
  int ret;
59
60
0
  ret = setsockopt_ipv4_multicast(top->fd, IP_DROP_MEMBERSHIP,
61
0
          p->u.prefix4, htonl(OSPF_ALLSPFROUTERS),
62
0
          ifindex);
63
0
  if (ret < 0)
64
0
    flog_err(EC_LIB_SOCKET,
65
0
       "can't setsockopt IP_DROP_MEMBERSHIP (fd %d, addr %pI4, ifindex %u, AllSPFRouters): %s",
66
0
       top->fd, &p->u.prefix4, ifindex,
67
0
       safe_strerror(errno));
68
0
  else {
69
0
    if (IS_DEBUG_OSPF_EVENT)
70
0
      zlog_debug(
71
0
        "interface %pI4 [%u] leave AllSPFRouters Multicast group.",
72
0
        &p->u.prefix4, ifindex);
73
0
  }
74
75
0
  return ret;
76
0
}
77
78
/* Join to the OSPF ALL Designated ROUTERS multicast group. */
79
int ospf_if_add_alldrouters(struct ospf *top, struct prefix *p,
80
          ifindex_t ifindex)
81
0
{
82
0
  int ret;
83
84
0
  ret = setsockopt_ipv4_multicast(top->fd, IP_ADD_MEMBERSHIP,
85
0
          p->u.prefix4, htonl(OSPF_ALLDROUTERS),
86
0
          ifindex);
87
0
  if (ret < 0)
88
0
    flog_err(
89
0
      EC_LIB_SOCKET,
90
0
      "can't setsockopt IP_ADD_MEMBERSHIP (fd %d, addr %pI4, ifindex %u, AllDRouters): %s; perhaps a kernel limit on # of multicast group memberships has been exceeded?",
91
0
      top->fd, &p->u.prefix4, ifindex,
92
0
      safe_strerror(errno));
93
0
  else {
94
0
    if (IS_DEBUG_OSPF_EVENT)
95
0
      zlog_debug(
96
0
        "interface %pI4 [%u] join AllDRouters Multicast group.",
97
0
        &p->u.prefix4, ifindex);
98
0
  }
99
0
  return ret;
100
0
}
101
102
int ospf_if_drop_alldrouters(struct ospf *top, struct prefix *p,
103
           ifindex_t ifindex)
104
0
{
105
0
  int ret;
106
107
0
  ret = setsockopt_ipv4_multicast(top->fd, IP_DROP_MEMBERSHIP,
108
0
          p->u.prefix4, htonl(OSPF_ALLDROUTERS),
109
0
          ifindex);
110
0
  if (ret < 0)
111
0
    flog_err(EC_LIB_SOCKET,
112
0
       "can't setsockopt IP_DROP_MEMBERSHIP (fd %d, addr %pI4, ifindex %u, AllDRouters): %s",
113
0
       top->fd, &p->u.prefix4, ifindex,
114
0
       safe_strerror(errno));
115
0
  else if (IS_DEBUG_OSPF_EVENT)
116
0
    zlog_debug(
117
0
      "interface %pI4 [%u] leave AllDRouters Multicast group.",
118
0
      &p->u.prefix4, ifindex);
119
120
0
  return ret;
121
0
}
122
123
int ospf_if_ipmulticast(int fd, struct prefix *p, ifindex_t ifindex)
124
0
{
125
0
  uint8_t val;
126
0
  int ret, len;
127
128
  /* Prevent receiving self-origined multicast packets. */
129
0
  ret = setsockopt_ipv4_multicast_loop(fd, 0);
130
0
  if (ret < 0)
131
0
    flog_err(EC_LIB_SOCKET,
132
0
       "can't setsockopt IP_MULTICAST_LOOP(0) for fd %d: %s",
133
0
       fd, safe_strerror(errno));
134
135
  /* Explicitly set multicast ttl to 1 -- endo. */
136
0
  val = 1;
137
0
  len = sizeof(val);
138
0
  ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&val, len);
139
0
  if (ret < 0)
140
0
    flog_err(EC_LIB_SOCKET,
141
0
       "can't setsockopt IP_MULTICAST_TTL(1) for fd %d: %s",
142
0
       fd, safe_strerror(errno));
143
#ifndef GNU_LINUX
144
  /* For GNU LINUX ospf_write uses IP_PKTINFO, in_pktinfo to send
145
   * packet out of ifindex. Below would be used Non Linux system.
146
   */
147
  ret = setsockopt_ipv4_multicast_if(fd, p->u.prefix4, ifindex);
148
  if (ret < 0)
149
    flog_err(EC_LIB_SOCKET,
150
       "can't setsockopt IP_MULTICAST_IF(fd %d, addr %pI4, ifindex %u): %s",
151
       fd, &p->u.prefix4, ifindex,
152
       safe_strerror(errno));
153
#endif
154
155
0
  return ret;
156
0
}
157
158
/*
159
 * Helper to open and set up a socket; returns the new fd on success,
160
 * -1 on error.
161
 */
162
static int sock_init_common(vrf_id_t vrf_id, const char *name, int *pfd)
163
0
{
164
0
  int ospf_sock;
165
0
  int ret, hincl = 1;
166
167
0
  if (vrf_id == VRF_UNKNOWN) {
168
    /* silently return since VRF is not ready */
169
0
    return -1;
170
0
  }
171
172
0
  frr_with_privs(&ospfd_privs) {
173
0
    ospf_sock = vrf_socket(AF_INET, SOCK_RAW, IPPROTO_OSPFIGP,
174
0
               vrf_id, name);
175
0
    if (ospf_sock < 0) {
176
0
      flog_err(EC_LIB_SOCKET, "%s: socket: %s", __func__,
177
0
         safe_strerror(errno));
178
0
      return -1;
179
0
    }
180
181
0
#ifdef IP_HDRINCL
182
    /* we will include IP header with packet */
183
0
    ret = setsockopt(ospf_sock, IPPROTO_IP, IP_HDRINCL, &hincl,
184
0
         sizeof(hincl));
185
0
    if (ret < 0) {
186
0
      flog_err(EC_LIB_SOCKET,
187
0
         "Can't set IP_HDRINCL option for fd %d: %s",
188
0
         ospf_sock, safe_strerror(errno));
189
0
      break;
190
0
    }
191
#elif defined(IPTOS_PREC_INTERNETCONTROL)
192
#warning "IP_HDRINCL not available on this system"
193
#warning "using IPTOS_PREC_INTERNETCONTROL"
194
    ret = setsockopt_ipv4_tos(ospf_sock,
195
            IPTOS_PREC_INTERNETCONTROL);
196
    if (ret < 0) {
197
      flog_err(EC_LIB_SOCKET,
198
         "can't set sockopt IP_TOS %d to socket %d: %s",
199
         tos, ospf_sock, safe_strerror(errno));
200
      break;
201
    }
202
#else /* !IPTOS_PREC_INTERNETCONTROL */
203
#warning "IP_HDRINCL not available, nor is IPTOS_PREC_INTERNETCONTROL"
204
    flog_err(EC_LIB_UNAVAILABLE, "IP_HDRINCL option not available");
205
#endif /* IP_HDRINCL */
206
207
0
    ret = setsockopt_ifindex(AF_INET, ospf_sock, 1);
208
209
0
    if (ret < 0)
210
0
      flog_err(EC_LIB_SOCKET,
211
0
         "Can't set pktinfo option for fd %d",
212
0
         ospf_sock);
213
0
  }
214
215
0
  *pfd = ospf_sock;
216
217
0
  return ret;
218
0
}
219
220
/*
221
 * Update a socket bufsize(s), based on its ospf instance
222
 */
223
void ospf_sock_bufsize_update(const struct ospf *ospf, int sock,
224
            enum ospf_sock_type_e type)
225
0
{
226
0
  int bufsize;
227
228
0
  if (type == OSPF_SOCK_BOTH || type == OSPF_SOCK_RECV) {
229
0
    bufsize = ospf->recv_sock_bufsize;
230
0
    setsockopt_so_recvbuf(sock, bufsize);
231
0
  }
232
233
0
  if (type == OSPF_SOCK_BOTH || type == OSPF_SOCK_SEND) {
234
0
    bufsize = ospf->send_sock_bufsize;
235
0
    setsockopt_so_sendbuf(sock, bufsize);
236
0
  }
237
0
}
238
239
int ospf_sock_init(struct ospf *ospf)
240
1
{
241
1
#ifdef FUZZING
242
1
  return 0;
243
0
#endif
244
0
  int ret;
245
246
  /* silently ignore. already done */
247
0
  if (ospf->fd > 0)
248
0
    return -1;
249
250
0
  ret = sock_init_common(ospf->vrf_id, ospf->name, &(ospf->fd));
251
252
0
  if (ret >= 0) /* Update socket buffer sizes */
253
0
    ospf_sock_bufsize_update(ospf, ospf->fd, OSPF_SOCK_BOTH);
254
255
0
  return ret;
256
0
}
257
258
/*
259
 * Open per-interface write socket
260
 */
261
int ospf_ifp_sock_init(struct interface *ifp)
262
0
{
263
0
  struct ospf_if_info *oii;
264
0
  struct ospf_interface *oi;
265
0
  struct ospf *ospf;
266
0
  struct route_node *rn;
267
0
  int ret;
268
269
0
  oii = IF_OSPF_IF_INFO(ifp);
270
0
  if (oii == NULL)
271
0
    return -1;
272
273
0
  if (oii->oii_fd > 0)
274
0
    return 0;
275
276
0
  rn = route_top(IF_OIFS(ifp));
277
0
  if (rn && rn->info) {
278
0
    oi = rn->info;
279
0
    ospf = oi->ospf;
280
0
  } else
281
0
    return -1;
282
283
0
  ret = sock_init_common(ifp->vrf->vrf_id, ifp->name, &oii->oii_fd);
284
285
0
  if (ret >= 0) /* Update socket buffer sizes */
286
0
    ospf_sock_bufsize_update(ospf, oii->oii_fd, OSPF_SOCK_BOTH);
287
288
0
  if (IS_DEBUG_OSPF_EVENT)
289
0
    zlog_debug("%s: ifp %s, oii %p, fd %d", __func__, ifp->name,
290
0
         oii, oii->oii_fd);
291
292
0
  return ret;
293
0
}
294
295
/*
296
 * Close per-interface write socket
297
 */
298
int ospf_ifp_sock_close(struct interface *ifp)
299
0
{
300
0
  struct ospf_if_info *oii;
301
302
0
  oii = IF_OSPF_IF_INFO(ifp);
303
0
  if (oii == NULL)
304
0
    return 0;
305
306
0
  if (oii->oii_fd > 0) {
307
0
    if (IS_DEBUG_OSPF_EVENT)
308
0
      zlog_debug("%s: ifp %s, oii %p, fd %d", __func__,
309
0
           ifp->name, oii, oii->oii_fd);
310
311
0
    close(oii->oii_fd);
312
0
    oii->oii_fd = -1;
313
0
  }
314
315
0
  return 0;
316
0
}