blob: e03831d0de179e8ac4201cac4019ee156abea667 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* BGP network related fucntions
2 Copyright (C) 1999 Kunihiro Ishiguro
3
4This file is part of GNU Zebra.
5
6GNU Zebra is free software; you can redistribute it and/or modify it
7under the terms of the GNU General Public License as published by the
8Free Software Foundation; either version 2, or (at your option) any
9later version.
10
11GNU Zebra is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Zebra; see the file COPYING. If not, write to the Free
18Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
1902111-1307, USA. */
20
21#include <zebra.h>
22
23#include "thread.h"
24#include "sockunion.h"
25#include "memory.h"
26#include "log.h"
27#include "if.h"
28#include "prefix.h"
29#include "command.h"
pauledd7c242003-06-04 13:59:38 +000030#include "privs.h"
paul718e3742002-12-13 20:15:29 +000031
32#include "bgpd/bgpd.h"
33#include "bgpd/bgp_fsm.h"
34#include "bgpd/bgp_attr.h"
35#include "bgpd/bgp_debug.h"
36#include "bgpd/bgp_network.h"
pauledd7c242003-06-04 13:59:38 +000037
38extern struct zebra_privs_t bgpd_privs;
39
paul718e3742002-12-13 20:15:29 +000040
41/* Accept bgp connection. */
42static int
43bgp_accept (struct thread *thread)
44{
45 int bgp_sock;
46 int accept_sock;
47 union sockunion su;
48 struct peer *peer;
paul718e3742002-12-13 20:15:29 +000049 struct bgp *bgp;
50 char buf[SU_ADDRSTRLEN];
51
52 /* Regiser accept thread. */
53 accept_sock = THREAD_FD (thread);
54 bgp = THREAD_ARG (thread);
55
56 if (accept_sock < 0)
57 {
58 zlog_err ("accept_sock is nevative value %d", accept_sock);
59 return -1;
60 }
61 thread_add_read (master, bgp_accept, bgp, accept_sock);
62
63 /* Accept client connection. */
64 bgp_sock = sockunion_accept (accept_sock, &su);
65 if (bgp_sock < 0)
66 {
67 zlog_err ("[Error] BGP socket accept failed (%s)", strerror (errno));
68 return -1;
69 }
70
71 if (BGP_DEBUG (events, EVENTS))
72 zlog_info ("[Event] BGP connection from host %s", inet_sutop (&su, buf));
73
74 /* Check remote IP address */
paul6ad23f02004-02-17 19:45:10 +000075 peer = peer_lookup (bgp, &su);
76 if (! peer || peer->status == Idle)
paul718e3742002-12-13 20:15:29 +000077 {
78 if (BGP_DEBUG (events, EVENTS))
79 {
paul6ad23f02004-02-17 19:45:10 +000080 if (! peer)
paul718e3742002-12-13 20:15:29 +000081 zlog_info ("[Event] BGP connection IP address %s is not configured",
82 inet_sutop (&su, buf));
83 else
84 zlog_info ("[Event] BGP connection IP address %s is Idle state",
85 inet_sutop (&su, buf));
86 }
87 close (bgp_sock);
88 return -1;
89 }
90
91 /* In case of peer is EBGP, we should set TTL for this connection. */
paul6ad23f02004-02-17 19:45:10 +000092 if (peer_sort (peer) == BGP_PEER_EBGP)
93 sockopt_ttl (peer->su.sa.sa_family, bgp_sock, peer->ttl);
paul718e3742002-12-13 20:15:29 +000094
95 if (! bgp)
paul6ad23f02004-02-17 19:45:10 +000096 bgp = peer->bgp;
paul718e3742002-12-13 20:15:29 +000097
paul6ad23f02004-02-17 19:45:10 +000098 peer->fd_accept = bgp_sock;
paul718e3742002-12-13 20:15:29 +000099
100 BGP_EVENT_ADD (peer, TCP_connection_open);
101
102 return 0;
103}
104
105/* BGP socket bind. */
106int
107bgp_bind (struct peer *peer)
108{
109#ifdef SO_BINDTODEVICE
110 int ret;
111 struct ifreq ifreq;
112
113 if (! peer->ifname)
114 return 0;
115
116 strncpy ((char *)&ifreq.ifr_name, peer->ifname, sizeof (ifreq.ifr_name));
117
paul6ad23f02004-02-17 19:45:10 +0000118 ret = setsockopt (*peer->fd, SOL_SOCKET, SO_BINDTODEVICE,
paul718e3742002-12-13 20:15:29 +0000119 &ifreq, sizeof (ifreq));
120 if (ret < 0)
121 {
122 zlog (peer->log, LOG_INFO, "bind to interface %s failed", peer->ifname);
123 return ret;
124 }
125#endif /* SO_BINDTODEVICE */
126 return 0;
127}
128
129int
130bgp_bind_address (int sock, struct in_addr *addr)
131{
132 int ret;
133 struct sockaddr_in local;
134
135 memset (&local, 0, sizeof (struct sockaddr_in));
136 local.sin_family = AF_INET;
137#ifdef HAVE_SIN_LEN
138 local.sin_len = sizeof(struct sockaddr_in);
139#endif /* HAVE_SIN_LEN */
140 memcpy (&local.sin_addr, addr, sizeof (struct in_addr));
141
pauledd7c242003-06-04 13:59:38 +0000142 if ( bgpd_privs.change (ZPRIVS_RAISE) )
143 zlog_err ("bgp_bind_address: could not raise privs");
144
paul718e3742002-12-13 20:15:29 +0000145 ret = bind (sock, (struct sockaddr *)&local, sizeof (struct sockaddr_in));
146 if (ret < 0)
147 ;
pauledd7c242003-06-04 13:59:38 +0000148
149 if (bgpd_privs.change (ZPRIVS_LOWER) )
150 zlog_err ("bgp_bind_address: could not lower privs");
151
paul718e3742002-12-13 20:15:29 +0000152 return 0;
153}
154
155struct in_addr *
156bgp_update_address (struct interface *ifp)
157{
158 struct prefix_ipv4 *p;
159 struct connected *connected;
160 listnode node;
161
162 for (node = listhead (ifp->connected); node; nextnode (node))
163 {
164 connected = getdata (node);
165
166 p = (struct prefix_ipv4 *) connected->address;
167
168 if (p->family == AF_INET)
169 return &p->prefix;
170 }
171 return NULL;
172}
173
174/* Update source selection. */
175void
176bgp_update_source (struct peer *peer)
177{
178 struct interface *ifp;
179 struct in_addr *addr;
180
181 /* Source is specified with interface name. */
182 if (peer->update_if)
183 {
184 ifp = if_lookup_by_name (peer->update_if);
185 if (! ifp)
186 return;
187
188 addr = bgp_update_address (ifp);
189 if (! addr)
190 return;
191
paul6ad23f02004-02-17 19:45:10 +0000192 bgp_bind_address (*peer->fd, addr);
paul718e3742002-12-13 20:15:29 +0000193 }
194
195 /* Source is specified with IP address. */
196 if (peer->update_source)
paul6ad23f02004-02-17 19:45:10 +0000197 sockunion_bind (*peer->fd, peer->update_source, 0, peer->update_source);
paul718e3742002-12-13 20:15:29 +0000198}
199
200/* BGP try to connect to the peer. */
201int
202bgp_connect (struct peer *peer)
203{
204 unsigned int ifindex = 0;
205
206 /* Make socket for the peer. */
paul6ad23f02004-02-17 19:45:10 +0000207 *peer->fd = sockunion_socket (&peer->su);
208 if (*peer->fd < 0)
paul718e3742002-12-13 20:15:29 +0000209 return -1;
210
211 /* If we can get socket for the peer, adjest TTL and make connection. */
212 if (peer_sort (peer) == BGP_PEER_EBGP)
paul6ad23f02004-02-17 19:45:10 +0000213 sockopt_ttl (peer->su.sa.sa_family, *peer->fd, peer->ttl);
paul718e3742002-12-13 20:15:29 +0000214
paul6ad23f02004-02-17 19:45:10 +0000215 sockopt_reuseaddr (*peer->fd);
216 sockopt_reuseport (*peer->fd);
paul718e3742002-12-13 20:15:29 +0000217
218 /* Bind socket. */
219 bgp_bind (peer);
220
221 /* Update source bind. */
222 bgp_update_source (peer);
223
224#ifdef HAVE_IPV6
225 if (peer->ifname)
226 ifindex = if_nametoindex (peer->ifname);
227#endif /* HAVE_IPV6 */
228
229 if (BGP_DEBUG (events, EVENTS))
230 plog_info (peer->log, "%s [Event] Connect start to %s fd %d",
paul6ad23f02004-02-17 19:45:10 +0000231 peer->host, peer->host, *peer->fd);
paul718e3742002-12-13 20:15:29 +0000232
233 /* Connect to the remote peer. */
paul6ad23f02004-02-17 19:45:10 +0000234 return sockunion_connect (*peer->fd, &peer->su, htons (peer->port), ifindex);
paul718e3742002-12-13 20:15:29 +0000235}
236
237/* After TCP connection is established. Get local address and port. */
238void
239bgp_getsockname (struct peer *peer)
240{
241 if (peer->su_local)
242 {
243 XFREE (MTYPE_TMP, peer->su_local);
244 peer->su_local = NULL;
245 }
246
247 if (peer->su_remote)
248 {
249 XFREE (MTYPE_TMP, peer->su_remote);
250 peer->su_remote = NULL;
251 }
252
paul6ad23f02004-02-17 19:45:10 +0000253 peer->su_local = sockunion_getsockname (*peer->fd);
254 peer->su_remote = sockunion_getpeername (*peer->fd);
paul718e3742002-12-13 20:15:29 +0000255
256 bgp_nexthop_set (peer->su_local, peer->su_remote, &peer->nexthop, peer);
257}
258
259/* IPv6 supported version of BGP server socket setup. */
260#if defined (HAVE_IPV6) && ! defined (NRL)
261int
262bgp_socket (struct bgp *bgp, unsigned short port)
263{
gdt10d60ad2003-12-23 17:34:39 +0000264 int ret, en;
paul718e3742002-12-13 20:15:29 +0000265 struct addrinfo req;
266 struct addrinfo *ainfo;
267 struct addrinfo *ainfo_save;
268 int sock = 0;
269 char port_str[BUFSIZ];
270
271 memset (&req, 0, sizeof (struct addrinfo));
272
273 req.ai_flags = AI_PASSIVE;
274 req.ai_family = AF_UNSPEC;
275 req.ai_socktype = SOCK_STREAM;
276 sprintf (port_str, "%d", port);
277 port_str[sizeof (port_str) - 1] = '\0';
278
279 ret = getaddrinfo (NULL, port_str, &req, &ainfo);
280 if (ret != 0)
281 {
282 zlog_err ("getaddrinfo: %s", gai_strerror (ret));
283 return -1;
284 }
285
286 ainfo_save = ainfo;
287
288 do
289 {
290 if (ainfo->ai_family != AF_INET && ainfo->ai_family != AF_INET6)
291 continue;
292
293 sock = socket (ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
294 if (sock < 0)
295 {
296 zlog_err ("socket: %s", strerror (errno));
297 continue;
298 }
299
300 sockopt_reuseaddr (sock);
301 sockopt_reuseport (sock);
pauledd7c242003-06-04 13:59:38 +0000302
303 if (bgpd_privs.change (ZPRIVS_RAISE) )
304 zlog_err ("bgp_socket: could not raise privs");
paul718e3742002-12-13 20:15:29 +0000305
306 ret = bind (sock, ainfo->ai_addr, ainfo->ai_addrlen);
gdt10d60ad2003-12-23 17:34:39 +0000307 en = errno;
308 if (bgpd_privs.change (ZPRIVS_LOWER) )
309 zlog_err ("bgp_bind_address: could not lower privs");
310
paul718e3742002-12-13 20:15:29 +0000311 if (ret < 0)
312 {
gdt10d60ad2003-12-23 17:34:39 +0000313 zlog_err ("bind: %s", strerror (en));
314 close(sock);
paul718e3742002-12-13 20:15:29 +0000315 continue;
316 }
pauledd7c242003-06-04 13:59:38 +0000317
paul718e3742002-12-13 20:15:29 +0000318 ret = listen (sock, 3);
319 if (ret < 0)
320 {
321 zlog_err ("listen: %s", strerror (errno));
322 close (sock);
323 continue;
324 }
325
326 thread_add_read (master, bgp_accept, bgp, sock);
327 }
328 while ((ainfo = ainfo->ai_next) != NULL);
329
330 freeaddrinfo (ainfo_save);
331
332 return sock;
333}
334#else
335/* Traditional IPv4 only version. */
336int
337bgp_socket (struct bgp *bgp, unsigned short port)
338{
339 int sock;
340 int socklen;
341 struct sockaddr_in sin;
hasso4a1a2712004-02-12 15:41:38 +0000342 int ret, en;
paul718e3742002-12-13 20:15:29 +0000343
344 sock = socket (AF_INET, SOCK_STREAM, 0);
345 if (sock < 0)
346 {
347 zlog_err ("socket: %s", strerror (errno));
348 return sock;
349 }
350
351 sockopt_reuseaddr (sock);
352 sockopt_reuseport (sock);
353
354 memset (&sin, 0, sizeof (struct sockaddr_in));
355
356 sin.sin_family = AF_INET;
357 sin.sin_port = htons (port);
358 socklen = sizeof (struct sockaddr_in);
359#ifdef HAVE_SIN_LEN
360 sin.sin_len = socklen;
361#endif /* HAVE_SIN_LEN */
362
pauledd7c242003-06-04 13:59:38 +0000363 if ( bgpd_privs.change (ZPRIVS_RAISE) )
364 zlog_err ("bgp_socket: could not raise privs");
365
paul718e3742002-12-13 20:15:29 +0000366 ret = bind (sock, (struct sockaddr *) &sin, socklen);
gdt10d60ad2003-12-23 17:34:39 +0000367 en = errno;
368
369 if (bgpd_privs.change (ZPRIVS_LOWER) )
370 zlog_err ("bgp_socket: could not lower privs");
371
paul718e3742002-12-13 20:15:29 +0000372 if (ret < 0)
373 {
gdt10d60ad2003-12-23 17:34:39 +0000374 zlog_err ("bind: %s", strerror (en));
paul718e3742002-12-13 20:15:29 +0000375 close (sock);
376 return ret;
377 }
pauledd7c242003-06-04 13:59:38 +0000378
paul718e3742002-12-13 20:15:29 +0000379 ret = listen (sock, 3);
380 if (ret < 0)
381 {
382 zlog_err ("listen: %s", strerror (errno));
383 close (sock);
384 return ret;
385 }
386
387 thread_add_read (bm->master, bgp_accept, bgp, sock);
388
389 return sock;
390}
391#endif /* HAVE_IPV6 && !NRL */