/* zebra server UNIX domain socket. */ static void zebra_serv_un (const char *path) { int ret; int sock, len; struct sockaddr_un serv; mode_t old_mask; /* First of all, unlink existing socket */ unlink (path); /* Set umask */ old_mask = umask (0077); /* Make UNIX domain socket. */ sock = socket (AF_UNIX, SOCK_STREAM, 0); if (sock < 0) { zlog_warn ("Can't create zserv unix socket: %s", safe_strerror (errno)); zlog_warn ("zebra can't provide full functionality due to above error"); return; } memset (&route_type_oaths, 0, sizeof (route_type_oaths)); /* Make server socket. */ memset (&serv, 0, sizeof (struct sockaddr_un)); serv.sun_family = AF_UNIX; strncpy (serv.sun_path, path, strlen (path)); #ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN len = serv.sun_len = SUN_LEN(&serv); #else len = sizeof (serv.sun_family) + strlen (serv.sun_path); #endif /* HAVE_STRUCT_SOCKADDR_UN_SUN_LEN */ ret = bind (sock, (struct sockaddr *) &serv, len); if (ret < 0) { zlog_warn ("Can't bind to unix socket %s: %s", path, safe_strerror (errno)); zlog_warn ("zebra can't provide full functionality due to above error"); close (sock); return; } ret = listen (sock, 5); if (ret < 0) { zlog_warn ("Can't listen to unix socket %s: %s", path, safe_strerror (errno)); zlog_warn ("zebra can't provide full functionality due to above error"); close (sock); return; } umask (old_mask); zebra_event (ZEBRA_SERV, sock, NULL); }
/* Accept code of zebra server socket. */ static int zebra_accept (struct thread *thread) { int accept_sock; int client_sock; struct sockaddr_in client; socklen_t len; accept_sock = THREAD_FD (thread); /* Reregister myself. */ zebra_event (ZEBRA_SERV, accept_sock, NULL); len = sizeof (struct sockaddr_in); client_sock = accept (accept_sock, (struct sockaddr *) &client, &len); if (client_sock < 0) { zlog_warn ("Can't accept zebra socket: %s", safe_strerror (errno)); return -1; } /* Make client socket non-blocking. */ set_nonblocking(client_sock); /* Create new zebra client. */ zebra_client_create (client_sock); return 0; }
/* Make zebra's server socket. */ static void zebra_serv () { int ret; int accept_sock; struct sockaddr_in addr; accept_sock = socket (AF_INET, SOCK_STREAM, 0); if (accept_sock < 0) { zlog_warn ("Can't create zserv stream socket: %s", safe_strerror (errno)); zlog_warn ("zebra can't provice full functionality due to above error"); return; } memset (&route_type_oaths, 0, sizeof (route_type_oaths)); memset (&addr, 0, sizeof (struct sockaddr_in)); addr.sin_family = AF_INET; addr.sin_port = htons (ZEBRA_PORT); #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN addr.sin_len = sizeof (struct sockaddr_in); #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); sockopt_reuseaddr (accept_sock); sockopt_reuseport (accept_sock); if ( zserv_privs.change(ZPRIVS_RAISE) ) zlog (NULL, LOG_ERR, "Can't raise privileges"); ret = bind (accept_sock, (struct sockaddr *)&addr, sizeof (struct sockaddr_in)); if (ret < 0) { zlog_warn ("Can't bind to stream socket: %s", safe_strerror (errno)); zlog_warn ("zebra can't provice full functionality due to above error"); close (accept_sock); /* Avoid sd leak. */ return; } if ( zserv_privs.change(ZPRIVS_LOWER) ) zlog (NULL, LOG_ERR, "Can't lower privileges"); ret = listen (accept_sock, 1); if (ret < 0) { zlog_warn ("Can't listen to stream socket: %s", safe_strerror (errno)); zlog_warn ("zebra can't provice full functionality due to above error"); close (accept_sock); /* Avoid sd leak. */ return; } zebra_event (ZEBRA_SERV, accept_sock, NULL); }
/* zebra server UNIX domain socket. */ static void zebra_serv_un (const char *path) { int ret; int sock, len; struct sockaddr_un serv; mode_t old_mask; /* First of all, unlink existing socket */ unlink (path); /* Set umask */ old_mask = umask (0077); /* Make UNIX domain socket. */ sock = socket (AF_UNIX, SOCK_STREAM, 0); if (sock < 0) { perror ("sock"); return; } /* Make server socket. */ memset (&serv, 0, sizeof (struct sockaddr_un)); serv.sun_family = AF_UNIX; strncpy (serv.sun_path, path, strlen (path)); #ifdef HAVE_SUN_LEN len = serv.sun_len = SUN_LEN(&serv); #else len = sizeof (serv.sun_family) + strlen (serv.sun_path); #endif /* HAVE_SUN_LEN */ ret = bind (sock, (struct sockaddr *) &serv, len); if (ret < 0) { perror ("bind"); close (sock); return; } ret = listen (sock, 5); if (ret < 0) { perror ("listen"); close (sock); return; } umask (old_mask); zebra_event (ZEBRA_SERV, sock, NULL); }
/* Make new client. */ static void zebra_client_create (int sock) { struct zserv *client; client = XCALLOC (0, sizeof (struct zserv)); /* Make client input/output buffer. */ client->sock = sock; client->ibuf = stream_new (ZEBRA_MAX_PACKET_SIZ); client->obuf = stream_new (ZEBRA_MAX_PACKET_SIZ); /* Set table number. */ client->rtm_table = zebrad.rtm_table_default; /* Add this client to linked list. */ listnode_add (zebrad.client_list, client); /* Make new read thread. */ zebra_event (ZEBRA_READ, sock, client); }
/* Accept code of zebra server socket. */ static int zebra_accept (struct thread *thread) { int val; int accept_sock; int client_sock; struct sockaddr_in client; socklen_t len; accept_sock = THREAD_FD (thread); len = sizeof (struct sockaddr_in); client_sock = accept (accept_sock, (struct sockaddr *) &client, &len); if (client_sock < 0) { zlog_warn ("Can't accept zebra socket: %s", safe_strerror (errno)); return -1; } /* Make client socket non-blocking. */ /* XXX: We dont requeue failed writes, so this leads to inconsistencies. * for now socket must remain blocking, regardless of risk of deadlocks. */ /* val = fcntl (client_sock, F_GETFL, 0); fcntl (client_sock, F_SETFL, (val | O_NONBLOCK)); */ /* Create new zebra client. */ zebra_client_create (client_sock); /* Register myself. */ zebra_event (ZEBRA_SERV, accept_sock, NULL); return 0; }
/* Handler of zebra service request. */ static int zebra_client_read (struct thread *thread) { int sock; struct zserv *client; int nbyte; u_short length; u_char command; /* Get thread data. Reset reading thread because I'm running. */ sock = THREAD_FD (thread); client = THREAD_ARG (thread); client->t_read = NULL; /* Read length and command. */ nbyte = stream_read (client->ibuf, sock, 3); if (nbyte <= 0) { if (IS_ZEBRA_DEBUG_EVENT) zlog_debug ("connection closed socket [%d]", sock); zebra_client_close (client); return -1; } length = stream_getw (client->ibuf); command = stream_getc (client->ibuf); if (length < 3) { if (IS_ZEBRA_DEBUG_EVENT) zlog_debug ("length %d is less than 3 ", length); zebra_client_close (client); return -1; } length -= 3; /* Read rest of data. */ if (length) { nbyte = stream_read (client->ibuf, sock, length); if (nbyte <= 0) { if (IS_ZEBRA_DEBUG_EVENT) zlog_debug ("connection closed [%d] when reading zebra data", sock); zebra_client_close (client); return -1; } } /* Debug packet information. */ if (IS_ZEBRA_DEBUG_EVENT) zlog_debug ("zebra message comes from socket [%d]", sock); if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) zlog_debug ("zebra message received [%s] %d", zebra_command_str[command], length); switch (command) { case ZEBRA_ROUTER_ID_ADD: zread_router_id_add (client, length); break; case ZEBRA_ROUTER_ID_DELETE: zread_router_id_delete (client, length); break; case ZEBRA_INTERFACE_ADD: zread_interface_add (client, length); break; case ZEBRA_INTERFACE_DELETE: zread_interface_delete (client, length); break; case ZEBRA_IPV4_ROUTE_ADD: zread_ipv4_add (client, length); break; case ZEBRA_IPV4_ROUTE_DELETE: zread_ipv4_delete (client, length); break; #ifdef HAVE_IPV6 case ZEBRA_IPV6_ROUTE_ADD: zread_ipv6_add (client, length); break; case ZEBRA_IPV6_ROUTE_DELETE: zread_ipv6_delete (client, length); break; #endif /* HAVE_IPV6 */ case ZEBRA_REDISTRIBUTE_ADD: zebra_redistribute_add (command, client, length); break; case ZEBRA_REDISTRIBUTE_DELETE: zebra_redistribute_delete (command, client, length); break; case ZEBRA_REDISTRIBUTE_DEFAULT_ADD: zebra_redistribute_default_add (command, client, length); break; case ZEBRA_REDISTRIBUTE_DEFAULT_DELETE: zebra_redistribute_default_delete (command, client, length); break; case ZEBRA_IPV4_NEXTHOP_LOOKUP: zread_ipv4_nexthop_lookup (client, length); break; #ifdef HAVE_IPV6 case ZEBRA_IPV6_NEXTHOP_LOOKUP: zread_ipv6_nexthop_lookup (client, length); break; #endif /* HAVE_IPV6 */ case ZEBRA_IPV4_IMPORT_LOOKUP: zread_ipv4_import_lookup (client, length); break; default: zlog_info ("Zebra received unknown command %d", command); break; } stream_reset (client->ibuf); zebra_event (ZEBRA_READ, sock, client); return 0; }
/* Handler of zebra service request. */ static int zebra_client_read (struct thread *thread) { int sock; struct zserv *client; size_t already; uint16_t length, command; uint8_t marker, version; /* Get thread data. Reset reading thread because I'm running. */ sock = THREAD_FD (thread); client = THREAD_ARG (thread); client->t_read = NULL; if (client->t_suicide) { zebra_client_close(client); return -1; } /* Read length and command (if we don't have it already). */ if ((already = stream_get_endp(client->ibuf)) < ZEBRA_HEADER_SIZE) { ssize_t nbyte; if (((nbyte = stream_read_try (client->ibuf, sock, ZEBRA_HEADER_SIZE-already)) == 0) || (nbyte == -1)) { if (IS_ZEBRA_DEBUG_EVENT) zlog_debug ("connection closed socket [%d]", sock); zebra_client_close (client); return -1; } if (nbyte != (ssize_t)(ZEBRA_HEADER_SIZE-already)) { /* Try again later. */ zebra_event (ZEBRA_READ, sock, client); return 0; } already = ZEBRA_HEADER_SIZE; } /* Reset to read from the beginning of the incoming packet. */ stream_set_getp(client->ibuf, 0); /* Fetch header values */ length = stream_getw (client->ibuf); marker = stream_getc (client->ibuf); version = stream_getc (client->ibuf); command = stream_getw (client->ibuf); if (marker != ZEBRA_HEADER_MARKER || version != ZSERV_VERSION) { zlog_err("%s: socket %d version mismatch, marker %d, version %d", __func__, sock, marker, version); zebra_client_close (client); return -1; } if (length < ZEBRA_HEADER_SIZE) { zlog_warn("%s: socket %d message length %u is less than header size %d", __func__, sock, length, ZEBRA_HEADER_SIZE); zebra_client_close (client); return -1; } if (length > STREAM_SIZE(client->ibuf)) { zlog_warn("%s: socket %d message length %u exceeds buffer size %lu", __func__, sock, length, (u_long)STREAM_SIZE(client->ibuf)); zebra_client_close (client); return -1; } /* Read rest of data. */ if (already < length) { ssize_t nbyte; if (((nbyte = stream_read_try (client->ibuf, sock, length-already)) == 0) || (nbyte == -1)) { if (IS_ZEBRA_DEBUG_EVENT) zlog_debug ("connection closed [%d] when reading zebra data", sock); zebra_client_close (client); return -1; } if (nbyte != (ssize_t)(length-already)) { /* Try again later. */ zebra_event (ZEBRA_READ, sock, client); return 0; } } length -= ZEBRA_HEADER_SIZE; /* Debug packet information. */ if (IS_ZEBRA_DEBUG_EVENT) zlog_debug ("zebra message comes from socket [%d]", sock); if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) zlog_debug ("zebra message received [%s] %d", zserv_command_string (command), length); switch (command) { case ZEBRA_ROUTER_ID_ADD: zread_router_id_add (client, length); break; case ZEBRA_ROUTER_ID_DELETE: zread_router_id_delete (client, length); break; case ZEBRA_INTERFACE_ADD: zread_interface_add (client, length); break; case ZEBRA_INTERFACE_DELETE: zread_interface_delete (client, length); break; case ZEBRA_IPV4_ROUTE_ADD: zread_ipv4_add (client, length); break; case ZEBRA_IPV4_ROUTE_DELETE: zread_ipv4_delete (client, length); break; #ifdef HAVE_IPV6 case ZEBRA_IPV6_ROUTE_ADD: zread_ipv6_add (client, length); break; case ZEBRA_IPV6_ROUTE_DELETE: zread_ipv6_delete (client, length); break; #endif /* HAVE_IPV6 */ case ZEBRA_REDISTRIBUTE_ADD: zebra_redistribute_add (command, client, length); break; case ZEBRA_REDISTRIBUTE_DELETE: zebra_redistribute_delete (command, client, length); break; case ZEBRA_REDISTRIBUTE_DEFAULT_ADD: zebra_redistribute_default_add (command, client, length); break; case ZEBRA_REDISTRIBUTE_DEFAULT_DELETE: zebra_redistribute_default_delete (command, client, length); break; case ZEBRA_IPV4_NEXTHOP_LOOKUP: zread_ipv4_nexthop_lookup (client, length); break; #ifdef HAVE_IPV6 case ZEBRA_IPV6_NEXTHOP_LOOKUP: zread_ipv6_nexthop_lookup (client, length); break; #endif /* HAVE_IPV6 */ case ZEBRA_IPV4_IMPORT_LOOKUP: zread_ipv4_import_lookup (client, length); break; case ZEBRA_HELLO: zread_hello (client); break; default: zlog_info ("Zebra received unknown command %d", command); break; } if (client->t_suicide) { /* No need to wait for thread callback, just kill immediately. */ zebra_client_close(client); return -1; } stream_reset (client->ibuf); zebra_event (ZEBRA_READ, sock, client); return 0; }