static void local_notify_route_1(int s, struct babel_route *route, int kind) { char buf[512]; int rc; const char *dst_prefix = format_prefix(route->src->prefix, route->src->plen); const char *src_prefix = format_prefix(route->src->src_prefix, route->src->src_plen); rc = snprintf(buf, 512, "%s route %s-%lx-%s prefix %s from %s installed %s " "id %s metric %d refmetric %d via %s if %s\n", local_kind(kind), dst_prefix, (unsigned long)route->neigh, src_prefix, dst_prefix, src_prefix, route->installed ? "yes" : "no", format_eui64(route->src->id), route_metric(route), route->refmetric, format_address(route->neigh->address), route->neigh->ifp->name); if(rc < 0 || rc >= 512) goto fail; rc = write_timeout(s, buf, rc); if(rc < 0) goto fail; return; fail: shutdown(s, 1); return; }
void local_notify_route(struct route *route, int kind) { char buf[512]; int rc; if(local_socket < 0) return; rc = snprintf(buf, 512, "%s route %s-%lx prefix %s installed %s " "id %s metric %d refmetric %d via %s if %s\n", local_kind(kind), format_prefix(route->src->prefix, route->src->plen), (unsigned long)route->neigh, format_prefix(route->src->prefix, route->src->plen), route->installed ? "yes" : "no", format_eui64(route->src->id), route_metric(route), route->refmetric, format_address(route->neigh->address), route->neigh->network->ifname); if(rc < 0 || rc >= 512) goto fail; rc = write_timeout(local_socket, buf, rc); if(rc < 0) goto fail; return; fail: shutdown(local_socket, 1); return; }
void radio_hdlr(uint8_t evt, void *data) { struct radio_packet *packet = data; if (evt != RADIO_EVT_RX_COMPLETED) { ERROR("Unexpected radio evt: %u", evt); return; } if (!packet->crcstatus) { DBG("ch %u bad crc", channels[idx]); goto recv; } /* Link Layer specification section 2.3, Core 4.1, page 2505 * * The length is the 6 LSB, and the minimum allowed payload is 6 bytes. */ if ((packet->pdu[1] & 0x3F) < 6) { DBG("ch %u bad length", channels[idx]); goto recv; } DBG("ch %u (%s)", channels[idx], format_address(data + 2)); recv: radio_recv(channels[idx], ADV_CHANNEL_AA, ADV_CHANNEL_CRC); }
void local_notify_neighbour(struct neighbour *neigh, int kind) { char buf[512]; int rc; if(local_socket < 0) return; rc = snprintf(buf, 512, "%s neighbour %lx address %s " "if %s reach %04x rxcost %d txcost %d cost %d\n", local_kind(kind), /* Neighbours never move around in memory , so we can use the address as a unique identifier. */ (unsigned long int)neigh, format_address(neigh->address), neigh->network->ifname, neigh->reach, neighbour_rxcost(neigh), neighbour_txcost(neigh), neighbour_cost(neigh)); if(rc < 0 || rc >= 512) goto fail; rc = write_timeout(local_socket, buf, rc); if(rc < 0) goto fail; return; fail: shutdown(local_socket, 1); return; }
void adv_report_cb(struct adv_report *report) { DBG("adv type %02x, addr type %02x", report->type, report->addr.type); DBG("address %s, data %s", format_address(report->addr.addr), format_data(report->data, report->len)); memcpy(&peer_addr, &report->addr, sizeof(bdaddr_t)); ll_scan_stop(); ll_conn_create(SCAN_INTERVAL, SCAN_WINDOW, &peer_addr, 1); }
static void print_kernel_route(int add, struct kernel_route *route) { char ifname[IFNAMSIZ]; if(!if_indextoname(route->ifindex, ifname)) memcpy(ifname,"unk",4); fprintf(stderr, "%s kernel route: dest: %s gw: %s metric: %d if: %s(%d) \n", add == RTM_ADD ? "Add" : add == RTM_DELETE ? "Delete" : "Change", format_prefix(route->prefix, route->plen), format_address(route->gw), route->metric, ifname, route->ifindex ); }
static void local_notify_neighbour_1(struct local_socket *s, struct neighbour *neigh, int kind) { char buf[512], rttbuf[64]; int rc; rttbuf[0] = '\0'; if(valid_rtt(neigh)) { rc = snprintf(rttbuf, 64, " rtt %s rttcost %d", format_thousands(neigh->rtt), neighbour_rttcost(neigh)); if(rc < 0 || rc >= 64) rttbuf[0] = '\0'; } rc = snprintf(buf, 512, "%s neighbour %lx address %s " "if %s reach %04x rxcost %d txcost %d%s cost %d\n", local_kind(kind), /* Neighbours never move around in memory , so we can use the address as a unique identifier. */ (unsigned long int)neigh, format_address(neigh->address), neigh->ifp->name, neigh->reach, neighbour_rxcost(neigh), neighbour_txcost(neigh), rttbuf, neighbour_cost(neigh)); if(rc < 0 || rc >= 512) goto fail; rc = write_timeout(s->fd, buf, rc); if(rc < 0) goto fail; return; fail: shutdown(s->fd, 1); return; }
static void local_notify_interface_1(struct local_socket *s, struct interface *ifp, int kind) { char buf[512], v4[INET_ADDRSTRLEN]; int rc; int up; up = if_up(ifp); if(up && ifp->ipv4) inet_ntop(AF_INET, ifp->ipv4, v4, INET_ADDRSTRLEN); else v4[0] = '\0'; if(up) rc = snprintf(buf, 512, "%s interface %s up true%s%s%s%s\n", local_kind(kind), ifp->name, ifp->ll ? " ipv6 " : "", ifp->ll ? format_address(*ifp->ll) : "", v4[0] ? " ipv4 " : "", v4); else rc = snprintf(buf, 512, "%s interface %s up false\n", local_kind(kind), ifp->name); if(rc < 0 || rc >= 512) goto fail; rc = write_timeout(s->fd, buf, rc); if(rc < 0) goto fail; return; fail: shutdown(s->fd, 1); return; }
Datum connection_limits(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; TupleDesc tupdesc; AttInMetadata *attinmeta; /* init on the first call */ if (SRF_IS_FIRSTCALL()) { MemoryContext oldcontext; funcctx = SRF_FIRSTCALL_INIT(); oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); reset_rules(); check_all_rules(); /* number of rules */ funcctx->max_calls = rules->n_rules; /* Build a tuple descriptor for our result type */ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("function returning record called in context " "that cannot accept type record"))); /* * generate attribute metadata needed later to produce tuples from raw * C strings */ attinmeta = TupleDescGetAttInMetadata(tupdesc); funcctx->attinmeta = attinmeta; funcctx->tuple_desc = tupdesc; /* switch back to the old context */ MemoryContextSwitchTo(oldcontext); } /* init the context */ funcctx = SRF_PERCALL_SETUP(); /* check if we have more data */ if (funcctx->max_calls > funcctx->call_cntr) { HeapTuple tuple; Datum result; Datum values[6]; bool nulls[6]; rule_t * rule = &(rules->rules[funcctx->call_cntr]); memset(nulls, 0, sizeof(nulls)); /* rule line */ values[0] = UInt32GetDatum(rule->line); /* database */ if (rule->fields & CHECK_DBNAME) values[1] = CStringGetTextDatum(rule->database); else nulls[1] = TRUE; /* username */ if (rule->fields & CHECK_USER) values[2] = CStringGetTextDatum(rule->user); else nulls[2] = TRUE; /* hostname or IP address */ if (rule->fields & CHECK_HOST) values[3] = CStringGetTextDatum(rule->hostname); else if (rule->fields & CHECK_IP) { char buffer[256]; memset(buffer, 0, 256); format_address(buffer, 256, (struct sockaddr*)&rule->ip, (struct sockaddr*)&rule->mask); values[3] = CStringGetTextDatum(buffer); } else nulls[3] = TRUE; /* count and limit */ values[4] = UInt32GetDatum(rule->count); values[5] = UInt32GetDatum(rule->limit); /* Build and return the tuple. */ tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); /* make the tuple into a datum */ result = HeapTupleGetDatum(tuple); /* Here we want to return another item: */ SRF_RETURN_NEXT(funcctx, result); } else { /* lock ProcArray (serialize the processes) */ LWLockRelease(ProcArrayLock); /* Here we are done returning items and just need to clean up: */ SRF_RETURN_DONE(funcctx); } }
static void babel_print_v2(const u_char *cp, u_int length) { u_int i; u_short bodylen; u_char v4_prefix[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 }; u_char v6_prefix[16] = {0}; TCHECK2(*cp, 4); if (length < 4) goto corrupt; bodylen = EXTRACT_16BITS(cp + 2); printf(" (%u)", bodylen); /* Process the TLVs in the body */ i = 0; while(i < bodylen) { const u_char *message; u_char type, len; message = cp + 4 + i; TCHECK2(*message, 2); ICHECK(i, 2); type = message[0]; len = message[1]; TCHECK2(*message, 2 + len); ICHECK(i, 2 + len); switch(type) { case MESSAGE_PAD1: { if(!vflag) printf(" pad1"); else printf("\n\tPad 1"); } break; case MESSAGE_PADN: { if(!vflag) printf(" padN"); else printf("\n\tPad %d", len + 2); } break; case MESSAGE_ACK_REQ: { u_short nonce, interval; if(!vflag) printf(" ack-req"); else { printf("\n\tAcknowledgment Request "); if(len < 6) goto corrupt; nonce = EXTRACT_16BITS(message + 4); interval = EXTRACT_16BITS(message + 6); printf("%04x %d", nonce, interval); } } break; case MESSAGE_ACK: { u_short nonce; if(!vflag) printf(" ack"); else { printf("\n\tAcknowledgment "); if(len < 2) goto corrupt; nonce = EXTRACT_16BITS(message + 2); printf("%04x", nonce); } } break; case MESSAGE_HELLO: { u_short seqno, interval; if(!vflag) printf(" hello"); else { printf("\n\tHello "); if(len < 6) goto corrupt; seqno = EXTRACT_16BITS(message + 4); interval = EXTRACT_16BITS(message + 6); printf("seqno %u interval %u", seqno, interval); } } break; case MESSAGE_IHU: { unsigned short txcost, interval; if(!vflag) printf(" ihu"); else { u_char address[16]; int rc; printf("\n\tIHU "); if(len < 6) goto corrupt; txcost = EXTRACT_16BITS(message + 4); interval = EXTRACT_16BITS(message + 6); rc = network_address(message[2], message + 8, len - 6, address); if(rc < 0) { printf("[|babel]"); break; } printf("%s txcost %u interval %d", format_address(address), txcost, interval); } } break; case MESSAGE_ROUTER_ID: { if(!vflag) printf(" router-id"); else { printf("\n\tRouter Id"); if(len < 10) goto corrupt; printf(" %s", format_id(message + 4)); } } break; case MESSAGE_NH: { if(!vflag) printf(" nh"); else { int rc; u_char nh[16]; printf("\n\tNext Hop"); if(len < 2) goto corrupt; rc = network_address(message[2], message + 4, len - 2, nh); if(rc < 0) goto corrupt; printf(" %s", format_address(nh)); } } break; case MESSAGE_UPDATE: { if(!vflag) { printf(" update"); if(len < 1) printf("/truncated"); else printf("%s%s%s", (message[3] & 0x80) ? "/prefix": "", (message[3] & 0x40) ? "/id" : "", (message[3] & 0x3f) ? "/unknown" : ""); } else { u_short interval, seqno, metric; u_char plen; int rc; u_char prefix[16]; printf("\n\tUpdate"); if(len < 10) goto corrupt; plen = message[4] + (message[2] == 1 ? 96 : 0); rc = network_prefix(message[2], message[4], message[5], message + 12, message[2] == 1 ? v4_prefix : v6_prefix, len - 10, prefix); if(rc < 0) goto corrupt; interval = EXTRACT_16BITS(message + 6); seqno = EXTRACT_16BITS(message + 8); metric = EXTRACT_16BITS(message + 10); printf("%s%s%s %s metric %u seqno %u interval %u", (message[3] & 0x80) ? "/prefix": "", (message[3] & 0x40) ? "/id" : "", (message[3] & 0x3f) ? "/unknown" : "", format_prefix(prefix, plen), metric, seqno, interval); if(message[3] & 0x80) { if(message[2] == 1) memcpy(v4_prefix, prefix, 16); else memcpy(v6_prefix, prefix, 16); } } } break; case MESSAGE_REQUEST: { if(!vflag) printf(" request"); else { int rc; u_char prefix[16], plen; printf("\n\tRequest "); if(len < 2) goto corrupt; plen = message[3] + (message[2] == 1 ? 96 : 0); rc = network_prefix(message[2], message[3], 0, message + 4, NULL, len - 2, prefix); if(rc < 0) goto corrupt; plen = message[3] + (message[2] == 1 ? 96 : 0); printf("for %s", message[2] == 0 ? "any" : format_prefix(prefix, plen)); } } break; case MESSAGE_MH_REQUEST : { if(!vflag) printf(" mh-request"); else { int rc; u_short seqno; u_char prefix[16], plen; printf("\n\tMH-Request "); if(len < 14) goto corrupt; seqno = EXTRACT_16BITS(message + 4); rc = network_prefix(message[2], message[3], 0, message + 16, NULL, len - 14, prefix); if(rc < 0) goto corrupt; plen = message[3] + (message[2] == 1 ? 96 : 0); printf("(%u hops) for %s seqno %u id %s", message[6], format_prefix(prefix, plen), seqno, format_id(message + 8)); } } break; default: if(!vflag) printf(" unknown"); else printf("\n\tUnknown message type %d", type); } i += len + 2; } return; trunc: printf(" [|babel]"); return; corrupt: printf(" (corrupt)"); return; }
void rtsp_listen_loop(void) { struct addrinfo hints, *info, *p; char portstr[6]; int *sockfd = NULL; int nsock = 0; int i, ret; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; snprintf(portstr, 6, "%d", config.port); ret = getaddrinfo(NULL, portstr, &hints, &info); if (ret) { die("getaddrinfo failed: %s", gai_strerror(ret)); } for (p=info; p; p=p->ai_next) { int fd = socket(p->ai_family, p->ai_socktype, IPPROTO_TCP); int yes = 1; ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); #ifdef IPV6_V6ONLY // some systems don't support v4 access on v6 sockets, but some do. // since we need to account for two sockets we might as well // always. if (p->ai_family == AF_INET6) ret |= setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes)); #endif if (!ret) ret = bind(fd, p->ai_addr, p->ai_addrlen); // one of the address families will fail on some systems that // report its availability. do not complain. if (ret) { debug(1, "Failed to bind to address %s\n", format_address(p->ai_addr)); continue; } debug(1, "Bound to address %s\n", format_address(p->ai_addr)); listen(fd, 5); nsock++; sockfd = realloc(sockfd, nsock*sizeof(int)); sockfd[nsock-1] = fd; } freeaddrinfo(info); if (!nsock) die("could not bind any listen sockets!"); int maxfd = -1; fd_set fds; FD_ZERO(&fds); for (i=0; i<nsock; i++) { if (sockfd[i] > maxfd) maxfd = sockfd[i]; } mdns_register(); printf("Listening for connections.\n"); shairport_startup_complete(); int acceptfd; struct timeval tv; while (1) { tv.tv_sec = 300; tv.tv_usec = 0; for (i=0; i<nsock; i++) FD_SET(sockfd[i], &fds); ret = select(maxfd+1, &fds, 0, 0, &tv); if (ret<0) { if (errno==EINTR) continue; break; } cleanup_threads(); acceptfd = -1; for (i=0; i<nsock; i++) { if (FD_ISSET(sockfd[i], &fds)) { acceptfd = sockfd[i]; break; } } if (acceptfd < 0) // timeout continue; rtsp_conn_info *conn = malloc(sizeof(rtsp_conn_info)); memset(conn, 0, sizeof(rtsp_conn_info)); socklen_t slen = sizeof(conn->remote); debug(1, "new RTSP connection\n"); conn->fd = accept(acceptfd, (struct sockaddr *)&conn->remote, &slen); if (conn->fd < 0) { perror("failed to accept connection"); free(conn); } else { pthread_t rtsp_conversation_thread; ret = pthread_create(&rtsp_conversation_thread, NULL, rtsp_conversation_thread_func, conn); if (ret) die("Failed to create RTSP receiver thread!"); conn->thread = rtsp_conversation_thread; conn->running = 1; track_thread(conn); } } perror("select"); die("fell out of the RTSP select loop"); }
static const char * format_prefix(const unsigned char *prefix, unsigned char plen) { return wmem_strdup_printf(wmem_packet_scope(), "%s/%u", format_address(prefix), plen); }
static int dissect_babel(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_item *ti; unsigned char v4_prefix[16] = {0}, v6_prefix[16] = {0}; int i = 0; proto_tree *babel_tree = NULL; guint8 version; guint16 bodylen; if(tvb_length(tvb) < 4) return 0; if(tvb_get_guint8(tvb, 0) != 42) return 0; version = tvb_get_guint8(tvb, 1); col_set_str(pinfo->cinfo, COL_PROTOCOL, "Babel"); col_set_str(pinfo->cinfo, COL_INFO, "Babel"); if(version != 2) { col_add_fstr(pinfo->cinfo, COL_INFO, "Version %u", version); return 2; } if(tree) { ti = proto_tree_add_item(tree, proto_babel, tvb, 0, -1, ENC_NA); babel_tree = proto_item_add_subtree(ti, ett_babel); proto_tree_add_item(babel_tree, hf_babel_magic, tvb, 0, 1, ENC_NA); proto_tree_add_item(babel_tree, hf_babel_version, tvb, 1, 1, ENC_NA); proto_tree_add_item(babel_tree, hf_babel_bodylen, tvb, 2, 2, ENC_BIG_ENDIAN); } bodylen = tvb_get_ntohs(tvb, 2); i = 0; while(i < bodylen) { guint8 type, len = 0, total_length; proto_tree *message_tree = NULL; int message = 4 + i; type = tvb_get_guint8(tvb, message); if(type == MESSAGE_PAD1) total_length = 1; else { len = tvb_get_guint8(tvb, message + 1); total_length = len + 2; } col_append_fstr(pinfo->cinfo, COL_INFO, " %s", val_to_str(type, messages, "unknown")); ti = proto_tree_add_uint_format(babel_tree, hf_babel_message, tvb, message, total_length, type, "Message %s (%u)", val_to_str(type, messages, "unknown"), type); if(tree) { message_tree = proto_item_add_subtree(ti, ett_message); proto_tree_add_item(message_tree, hf_babel_message_type, tvb, message, 1, ENC_NA); } if(type == MESSAGE_PAD1) { i++; continue; } if(tree) { proto_tree_add_item(message_tree, hf_babel_message_length, tvb, message + 1, 1, ENC_BIG_ENDIAN); if(type == MESSAGE_PADN) { } else if(type == MESSAGE_ACK_REQ) { proto_tree_add_item(message_tree, hf_babel_message_nonce, tvb, message + 4, 2, ENC_BIG_ENDIAN); proto_tree_add_item(message_tree, hf_babel_message_interval, tvb, message + 6, 2, ENC_BIG_ENDIAN); } else if(type == MESSAGE_ACK) { proto_tree_add_item(message_tree, hf_babel_message_nonce, tvb, message + 2, 2, ENC_BIG_ENDIAN); } else if(type == MESSAGE_HELLO) { proto_tree_add_item(message_tree, hf_babel_message_seqno, tvb, message + 4, 2, ENC_BIG_ENDIAN); proto_tree_add_item(message_tree, hf_babel_message_interval, tvb, message + 6, 2, ENC_BIG_ENDIAN); } else if(type == MESSAGE_IHU) { proto_tree *subtree; unsigned char address[16]; int rc = network_address(tvb_get_guint8(tvb, message + 2), tvb_get_ptr(tvb, message + 8, len - 6), len - 6, address); proto_tree_add_item(message_tree, hf_babel_message_rxcost, tvb, message + 4, 2, ENC_BIG_ENDIAN); proto_tree_add_item(message_tree, hf_babel_message_interval, tvb, message + 6, 2, ENC_BIG_ENDIAN); ti = proto_tree_add_text(message_tree, tvb, message + 4, len - 2, "Address: %s", format_address(rc < 0 ? NULL : address)); subtree = proto_item_add_subtree(ti, ett_subtree); proto_tree_add_item(subtree, hf_babel_message_ae, tvb, message + 2, 1, ENC_NA); proto_tree_add_item(subtree, hf_babel_message_prefix, tvb, message + 4, len - 2, ENC_NA); } else if(type == MESSAGE_ROUTER_ID) { proto_tree_add_item(message_tree, hf_babel_message_routerid, tvb, message + 4, 8, ENC_NA); } else if(type == MESSAGE_NH) { proto_tree *subtree; unsigned char nh[16]; int rc = network_address(tvb_get_guint8(tvb, message + 2), tvb_get_ptr(tvb, message + 4, len - 2), len - 2, nh); ti = proto_tree_add_text(message_tree, tvb, message + 4, len - 2, "NH: %s", format_address(rc < 0 ? NULL : nh)); subtree = proto_item_add_subtree(ti, ett_subtree); proto_tree_add_item(subtree, hf_babel_message_ae, tvb, message + 2, 1, ENC_NA); proto_tree_add_item(subtree, hf_babel_message_prefix, tvb, message + 4, len - 2, ENC_NA); } else if(type == MESSAGE_UPDATE) { proto_tree *subtree; unsigned char p[16]; guint8 ae = tvb_get_guint8(tvb, message + 2); guint8 flags = tvb_get_guint8(tvb, message + 3); guint8 plen = tvb_get_guint8(tvb, message + 4); int rc = network_prefix(ae, plen, tvb_get_guint8(tvb, message + 5), tvb_get_ptr(tvb, message + 12, len - 10), ae == 1 ? v4_prefix : v6_prefix, len - 10, p); if(rc >= 0 && (flags & 0x80)) { if(ae == 1) memcpy(v4_prefix, p, 16); else memcpy(v6_prefix, p, 16); } proto_tree_add_item(message_tree, hf_babel_message_flags, tvb, message + 3, 1, ENC_NA); proto_tree_add_item(message_tree, hf_babel_message_interval, tvb, message + 6, 2, ENC_BIG_ENDIAN); proto_tree_add_item(message_tree, hf_babel_message_seqno, tvb, message + 8, 2, ENC_BIG_ENDIAN); proto_tree_add_item(message_tree, hf_babel_message_metric, tvb, message + 10, 2, ENC_BIG_ENDIAN); ti = proto_tree_add_text(message_tree, tvb, message + 12, len - 10, "Prefix: %s", format_prefix(rc < 0 ? NULL : p, plen)); subtree = proto_item_add_subtree(ti, ett_subtree); proto_tree_add_item(subtree, hf_babel_message_ae, tvb, message + 2, 1, ENC_NA); proto_tree_add_item(subtree, hf_babel_message_plen, tvb, message + 4, 1, ENC_NA); proto_tree_add_item(subtree, hf_babel_message_omitted, tvb, message + 5, 1, ENC_NA); proto_tree_add_item(subtree, hf_babel_message_prefix, tvb, message + 12, len - 10, ENC_NA); } else if(type == MESSAGE_REQUEST) { proto_tree *subtree; unsigned char p[16]; guint8 plen = tvb_get_guint8(tvb, message + 3); int rc = network_prefix(tvb_get_guint8(tvb, message + 2), plen, 0, tvb_get_ptr(tvb, message + 4, len - 2), NULL, len - 2, p); ti = proto_tree_add_text(message_tree, tvb, message + 4, len - 2, "Prefix: %s", format_prefix(rc < 0 ? NULL : p, plen)); subtree = proto_item_add_subtree(ti, ett_subtree); proto_tree_add_item(subtree, hf_babel_message_ae, tvb, message + 2, 1, ENC_NA); proto_tree_add_item(subtree, hf_babel_message_plen, tvb, message + 3, 1, ENC_NA); proto_tree_add_item(subtree, hf_babel_message_prefix, tvb, message + 4, len - 2, ENC_NA); } else if(type == MESSAGE_MH_REQUEST) { proto_tree *subtree; unsigned char p[16]; guint8 plen = tvb_get_guint8(tvb, message + 3); int rc = network_prefix(tvb_get_guint8(tvb, message + 2), plen, 0, tvb_get_ptr(tvb, message + 16, len - 14), NULL, len - 14, p); proto_tree_add_item(message_tree, hf_babel_message_seqno, tvb, message + 4, 2, ENC_BIG_ENDIAN); proto_tree_add_item(message_tree, hf_babel_message_hopcount, tvb, message + 6, 1, ENC_NA); proto_tree_add_item(message_tree, hf_babel_message_routerid, tvb, message + 8, 8, ENC_NA); ti = proto_tree_add_text(message_tree, tvb, message + 16, len - 14, "Prefix: %s", format_prefix(rc < 0 ? NULL : p, plen)); subtree = proto_item_add_subtree(ti, ett_subtree); proto_tree_add_item(subtree, hf_babel_message_ae, tvb, message + 2, 1, ENC_NA); proto_tree_add_item(subtree, hf_babel_message_plen, tvb, message + 3, 1, ENC_NA); proto_tree_add_item(subtree, hf_babel_message_prefix, tvb, message + 16, len - 14, ENC_NA); } } i += len + 2; } return i; }
const char * format_prefix(const unsigned char *prefix, unsigned char plen) { return ep_strdup_printf("%s/%u", format_address(prefix), plen); }
static void babel_print_v2(netdissect_options *ndo, const u_char *cp, u_int length) { u_int i; u_short bodylen; u_char v4_prefix[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 }; u_char v6_prefix[16] = {0}; ND_TCHECK2(*cp, 4); if (length < 4) goto corrupt; bodylen = EXTRACT_16BITS(cp + 2); ND_PRINT((ndo, " (%u)", bodylen)); /* Process the TLVs in the body */ i = 0; while(i < bodylen) { const u_char *message; u_int type, len; message = cp + 4 + i; ND_TCHECK2(*message, 1); if((type = message[0]) == MESSAGE_PAD1) { ND_PRINT((ndo, ndo->ndo_vflag ? "\n\tPad 1" : " pad1")); i += 1; continue; } ND_TCHECK2(*message, 2); ICHECK(i, 2); len = message[1]; ND_TCHECK2(*message, 2 + len); ICHECK(i, 2 + len); switch(type) { case MESSAGE_PADN: { if (!ndo->ndo_vflag) ND_PRINT((ndo, " padN")); else ND_PRINT((ndo, "\n\tPad %d", len + 2)); } break; case MESSAGE_ACK_REQ: { u_short nonce, interval; if (!ndo->ndo_vflag) ND_PRINT((ndo, " ack-req")); else { ND_PRINT((ndo, "\n\tAcknowledgment Request ")); if(len < 6) goto corrupt; nonce = EXTRACT_16BITS(message + 4); interval = EXTRACT_16BITS(message + 6); ND_PRINT((ndo, "%04x %s", nonce, format_interval(interval))); } } break; case MESSAGE_ACK: { u_short nonce; if (!ndo->ndo_vflag) ND_PRINT((ndo, " ack")); else { ND_PRINT((ndo, "\n\tAcknowledgment ")); if(len < 2) goto corrupt; nonce = EXTRACT_16BITS(message + 2); ND_PRINT((ndo, "%04x", nonce)); } } break; case MESSAGE_HELLO: { u_short seqno, interval; if (!ndo->ndo_vflag) ND_PRINT((ndo, " hello")); else { ND_PRINT((ndo, "\n\tHello ")); if(len < 6) goto corrupt; seqno = EXTRACT_16BITS(message + 4); interval = EXTRACT_16BITS(message + 6); ND_PRINT((ndo, "seqno %u interval %s", seqno, format_interval(interval))); /* Extra data. */ if(len > 6) subtlvs_print(ndo, message + 8, message + 2 + len, type); } } break; case MESSAGE_IHU: { unsigned short txcost, interval; if (!ndo->ndo_vflag) ND_PRINT((ndo, " ihu")); else { u_char address[16]; int rc; ND_PRINT((ndo, "\n\tIHU ")); if(len < 6) goto corrupt; txcost = EXTRACT_16BITS(message + 4); interval = EXTRACT_16BITS(message + 6); rc = network_address(message[2], message + 8, len - 6, address); if(rc < 0) { ND_PRINT((ndo, "%s", tstr)); break; } ND_PRINT((ndo, "%s txcost %u interval %s", format_address(ndo, address), txcost, format_interval(interval))); /* Extra data. */ if((u_int)rc < len - 6) subtlvs_print(ndo, message + 8 + rc, message + 2 + len, type); } } break; case MESSAGE_ROUTER_ID: { if (!ndo->ndo_vflag) ND_PRINT((ndo, " router-id")); else { ND_PRINT((ndo, "\n\tRouter Id")); if(len < 10) goto corrupt; ND_PRINT((ndo, " %s", format_id(message + 4))); } } break; case MESSAGE_NH: { if (!ndo->ndo_vflag) ND_PRINT((ndo, " nh")); else { int rc; u_char nh[16]; ND_PRINT((ndo, "\n\tNext Hop")); if(len < 2) goto corrupt; rc = network_address(message[2], message + 4, len - 2, nh); if(rc < 0) goto corrupt; ND_PRINT((ndo, " %s", format_address(ndo, nh))); } } break; case MESSAGE_UPDATE: { if (!ndo->ndo_vflag) { ND_PRINT((ndo, " update")); if(len < 1) ND_PRINT((ndo, "/truncated")); else ND_PRINT((ndo, "%s%s%s", (message[3] & 0x80) ? "/prefix": "", (message[3] & 0x40) ? "/id" : "", (message[3] & 0x3f) ? "/unknown" : "")); } else { u_short interval, seqno, metric; u_char plen; int rc; u_char prefix[16]; ND_PRINT((ndo, "\n\tUpdate")); if(len < 10) goto corrupt; plen = message[4] + (message[2] == 1 ? 96 : 0); rc = network_prefix(message[2], message[4], message[5], message + 12, message[2] == 1 ? v4_prefix : v6_prefix, len - 10, prefix); if(rc < 0) goto corrupt; interval = EXTRACT_16BITS(message + 6); seqno = EXTRACT_16BITS(message + 8); metric = EXTRACT_16BITS(message + 10); ND_PRINT((ndo, "%s%s%s %s metric %u seqno %u interval %s", (message[3] & 0x80) ? "/prefix": "", (message[3] & 0x40) ? "/id" : "", (message[3] & 0x3f) ? "/unknown" : "", format_prefix(ndo, prefix, plen), metric, seqno, format_interval_update(interval))); if(message[3] & 0x80) { if(message[2] == 1) memcpy(v4_prefix, prefix, 16); else memcpy(v6_prefix, prefix, 16); } /* extra data? */ if((u_int)rc < len - 10) subtlvs_print(ndo, message + 12 + rc, message + 2 + len, type); } } break; case MESSAGE_REQUEST: { if (!ndo->ndo_vflag) ND_PRINT((ndo, " request")); else { int rc; u_char prefix[16], plen; ND_PRINT((ndo, "\n\tRequest ")); if(len < 2) goto corrupt; plen = message[3] + (message[2] == 1 ? 96 : 0); rc = network_prefix(message[2], message[3], 0, message + 4, NULL, len - 2, prefix); if(rc < 0) goto corrupt; ND_PRINT((ndo, "for %s", message[2] == 0 ? "any" : format_prefix(ndo, prefix, plen))); } } break; case MESSAGE_MH_REQUEST : { if (!ndo->ndo_vflag) ND_PRINT((ndo, " mh-request")); else { int rc; u_short seqno; u_char prefix[16], plen; ND_PRINT((ndo, "\n\tMH-Request ")); if(len < 14) goto corrupt; seqno = EXTRACT_16BITS(message + 4); rc = network_prefix(message[2], message[3], 0, message + 16, NULL, len - 14, prefix); if(rc < 0) goto corrupt; plen = message[3] + (message[2] == 1 ? 96 : 0); ND_PRINT((ndo, "(%u hops) for %s seqno %u id %s", message[6], format_prefix(ndo, prefix, plen), seqno, format_id(message + 8))); } } break; case MESSAGE_TSPC : if (!ndo->ndo_vflag) ND_PRINT((ndo, " tspc")); else { ND_PRINT((ndo, "\n\tTS/PC ")); if(len < 6) goto corrupt; ND_PRINT((ndo, "timestamp %u packetcounter %u", EXTRACT_32BITS (message + 4), EXTRACT_16BITS(message + 2))); } break; case MESSAGE_HMAC : { if (!ndo->ndo_vflag) ND_PRINT((ndo, " hmac")); else { unsigned j; ND_PRINT((ndo, "\n\tHMAC ")); if(len < 18) goto corrupt; ND_PRINT((ndo, "key-id %u digest-%u ", EXTRACT_16BITS(message + 2), len - 2)); for (j = 0; j < len - 2; j++) ND_PRINT((ndo, "%02X", message[4 + j])); } } break; case MESSAGE_UPDATE_SRC_SPECIFIC : { if(!ndo->ndo_vflag) { ND_PRINT((ndo, " ss-update")); } else { u_char prefix[16], src_prefix[16]; u_short interval, seqno, metric; u_char ae, plen, src_plen, omitted; int rc; int parsed_len = 10; ND_PRINT((ndo, "\n\tSS-Update")); if(len < 10) goto corrupt; ae = message[2]; src_plen = message[3]; plen = message[4]; omitted = message[5]; interval = EXTRACT_16BITS(message + 6); seqno = EXTRACT_16BITS(message + 8); metric = EXTRACT_16BITS(message + 10); rc = network_prefix(ae, plen, omitted, message + 2 + parsed_len, ae == 1 ? v4_prefix : v6_prefix, len - parsed_len, prefix); if(rc < 0) goto corrupt; if(ae == 1) plen += 96; parsed_len += rc; rc = network_prefix(ae, src_plen, 0, message + 2 + parsed_len, NULL, len - parsed_len, src_prefix); if(rc < 0) goto corrupt; if(ae == 1) src_plen += 96; parsed_len += rc; ND_PRINT((ndo, " %s from", format_prefix(ndo, prefix, plen))); ND_PRINT((ndo, " %s metric %u seqno %u interval %s", format_prefix(ndo, src_prefix, src_plen), metric, seqno, format_interval_update(interval))); /* extra data? */ if((u_int)parsed_len < len) subtlvs_print(ndo, message + 2 + parsed_len, message + 2 + len, type); } } break; case MESSAGE_REQUEST_SRC_SPECIFIC : { if(!ndo->ndo_vflag) ND_PRINT((ndo, " ss-request")); else { int rc, parsed_len = 3; u_char ae, plen, src_plen, prefix[16], src_prefix[16]; ND_PRINT((ndo, "\n\tSS-Request ")); if(len < 3) goto corrupt; ae = message[2]; plen = message[3]; src_plen = message[4]; rc = network_prefix(ae, plen, 0, message + 2 + parsed_len, NULL, len - parsed_len, prefix); if(rc < 0) goto corrupt; if(ae == 1) plen += 96; parsed_len += rc; rc = network_prefix(ae, src_plen, 0, message + 2 + parsed_len, NULL, len - parsed_len, src_prefix); if(rc < 0) goto corrupt; if(ae == 1) src_plen += 96; parsed_len += rc; if(ae == 0) { ND_PRINT((ndo, "for any")); } else { ND_PRINT((ndo, "for (%s, ", format_prefix(ndo, prefix, plen))); ND_PRINT((ndo, "%s)", format_prefix(ndo, src_prefix, src_plen))); } } } break; case MESSAGE_MH_REQUEST_SRC_SPECIFIC : { if(!ndo->ndo_vflag) ND_PRINT((ndo, " ss-mh-request")); else { int rc, parsed_len = 14; u_short seqno; u_char ae, plen, src_plen, prefix[16], src_prefix[16], hopc; const u_char *router_id = NULL; ND_PRINT((ndo, "\n\tSS-MH-Request ")); if(len < 14) goto corrupt; ae = message[2]; plen = message[3]; seqno = EXTRACT_16BITS(message + 4); hopc = message[6]; src_plen = message[7]; router_id = message + 8; rc = network_prefix(ae, plen, 0, message + 2 + parsed_len, NULL, len - parsed_len, prefix); if(rc < 0) goto corrupt; if(ae == 1) plen += 96; parsed_len += rc; rc = network_prefix(ae, src_plen, 0, message + 2 + parsed_len, NULL, len - parsed_len, src_prefix); if(rc < 0) goto corrupt; if(ae == 1) src_plen += 96; ND_PRINT((ndo, "(%u hops) for (%s, ", hopc, format_prefix(ndo, prefix, plen))); ND_PRINT((ndo, "%s) seqno %u id %s", format_prefix(ndo, src_prefix, src_plen), seqno, format_id(router_id))); } } break; default: if (!ndo->ndo_vflag) ND_PRINT((ndo, " unknown")); else ND_PRINT((ndo, "\n\tUnknown message type %d", type)); } i += len + 2; } return; trunc: ND_PRINT((ndo, " %s", tstr)); return; corrupt: ND_PRINT((ndo, " (corrupt)")); return; }
int kernel_route(int operation, const unsigned char *dest, unsigned short plen, const unsigned char *gate, int ifindex, unsigned int metric, const unsigned char *newgate, int newifindex, unsigned int newmetric) { unsigned char msg[512]; struct rt_msghdr *rtm; struct sockaddr_in6 *sin6; struct sockaddr_in *sin; int rc, len, ipv4; char local6[1][1][16] = IN6ADDR_LOOPBACK_INIT; char local4[1][1][16] = {{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x01 }}}; /* Check that the protocol family is consistent. */ if(plen >= 96 && v4mapped(dest)) { if(!v4mapped(gate)) { errno = EINVAL; return -1; } ipv4 = 1; } else { if(v4mapped(gate)) { errno = EINVAL; return -1; } ipv4 = 0; } if(operation == ROUTE_MODIFY && newmetric == metric && memcmp(newgate, gate, 16) == 0 && newifindex == ifindex) return 0; if(operation == ROUTE_MODIFY) { metric = newmetric; gate = newgate; ifindex = newifindex; } kdebugf("kernel_route: %s %s/%d metric %d dev %d nexthop %s\n", operation == ROUTE_ADD ? "add" : operation == ROUTE_FLUSH ? "flush" : "change", format_address(dest), plen, metric, ifindex, format_address(gate)); if(kernel_socket < 0) kernel_setup_socket(1); memset(&msg, 0, sizeof(msg)); rtm = (struct rt_msghdr *)msg; rtm->rtm_version = RTM_VERSION; switch(operation) { case ROUTE_FLUSH: rtm->rtm_type = RTM_DELETE; break; case ROUTE_ADD: rtm->rtm_type = RTM_ADD; break; case ROUTE_MODIFY: rtm->rtm_type = RTM_CHANGE; break; default: return -1; }; rtm->rtm_index = ifindex; rtm->rtm_flags = RTF_UP | RTF_PROTO2; if(plen == 128) rtm->rtm_flags |= RTF_HOST; /* if(memcmp(nexthop->id, dest, 16) == 0) { */ /* rtm -> rtm_flags |= RTF_LLINFO; */ /* rtm -> rtm_flags |= RTF_CLONING; */ /* } else { */ rtm->rtm_flags |= RTF_GATEWAY; /* } */ if(metric == KERNEL_INFINITY) { rtm->rtm_flags |= RTF_BLACKHOLE; if(ifindex_lo < 0) { ifindex_lo = if_nametoindex("lo0"); if(ifindex_lo <= 0) return -1; } rtm->rtm_index = ifindex_lo; } rtm->rtm_seq = ++seq; rtm->rtm_addrs = RTA_DST | RTA_GATEWAY; if(!(operation == ROUTE_MODIFY && plen == 128)) { rtm->rtm_addrs |= RTA_NETMASK; } #define push_sockaddr_in(ptr, offset) \ do { (ptr) = (struct sockaddr_in *)((char *)(ptr) + (offset)); \ (ptr)->sin_len = sizeof(struct sockaddr_in); \ (ptr)->sin_family = AF_INET; } while (0) #define get_sin_addr(dst,src) \ do { memcpy((dst), (src) + 12, 4); } while (0) #define push_sockaddr_in6(ptr, offset) \ do { (ptr) = (struct sockaddr_in6 *)((char *)(ptr) + (offset)); \ (ptr)->sin6_len = sizeof(struct sockaddr_in6); \ (ptr)->sin6_family = AF_INET6; } while (0) #define get_sin6_addr(dst,src) \ do { memcpy((dst), (src), 16); } while (0) /* KAME ipv6 stack does not support IPv4 mapped IPv6, so we have to * duplicate the codepath */ if(ipv4) { sin = (struct sockaddr_in *)msg; /* destination */ push_sockaddr_in(sin, sizeof(*rtm)); get_sin_addr(&(sin->sin_addr), dest); /* gateway */ push_sockaddr_in(sin, ROUNDUP(sin->sin_len)); if (metric == KERNEL_INFINITY) get_sin_addr(&(sin->sin_addr),**local4); else get_sin_addr(&(sin->sin_addr),gate); /* netmask */ if((rtm->rtm_addrs | RTA_NETMASK) != 0) { struct in6_addr tmp_sin6_addr; push_sockaddr_in(sin, ROUNDUP(sin->sin_len)); plen2mask(plen, &tmp_sin6_addr); get_sin_addr(&(sin->sin_addr), (char *)&tmp_sin6_addr); } len = (char *)sin + ROUNDUP(sin->sin_len) - (char *)msg; } else { sin6 = (struct sockaddr_in6 *)msg; /* destination */ push_sockaddr_in6(sin6, sizeof(*rtm)); get_sin6_addr(&(sin6->sin6_addr), dest); /* gateway */ push_sockaddr_in6(sin6, ROUNDUP(sin6->sin6_len)); if (metric == KERNEL_INFINITY) get_sin6_addr(&(sin6->sin6_addr),**local6); else get_sin6_addr(&(sin6->sin6_addr),gate); if(IN6_IS_ADDR_LINKLOCAL (&sin6->sin6_addr)) SET_IN6_LINKLOCAL_IFINDEX (sin6->sin6_addr, ifindex); /* netmask */ if((rtm->rtm_addrs | RTA_NETMASK) != 0) { push_sockaddr_in6(sin6, ROUNDUP(sin6->sin6_len)); plen2mask(plen, &sin6->sin6_addr); } len = (char *)sin6 + ROUNDUP(sin6->sin6_len) - (char *)msg; } rtm->rtm_msglen = len; rc = write(kernel_socket, msg, rtm->rtm_msglen); if (rc < rtm->rtm_msglen) return -1; return 1; }
static int filter_addresses(struct nlmsghdr *nh, void *data) { int rc; int maxroutes = 0; struct kernel_route *routes = NULL; struct in6_addr addr; int *found = NULL; int len; struct ifaddrmsg *ifa; char ifname[IFNAMSIZ]; int ifindex = 0; int ll = 0; if (data) { void **args = (void **)data; maxroutes = *(int *)args[0]; routes = (struct kernel_route*)args[1]; found = (int *)args[2]; ifindex = args[3] ? *(int*)args[3] : 0; ll = args[4] ? !!*(int*)args[4] : 0; } len = nh->nlmsg_len; if (data && *found >= maxroutes) return 0; if (nh->nlmsg_type != RTM_NEWADDR && (data || nh->nlmsg_type != RTM_DELADDR)) return 0; ifa = (struct ifaddrmsg *)NLMSG_DATA(nh); len -= NLMSG_LENGTH(0); rc = parse_addr_rta(ifa, len, &addr); if (rc < 0) return 0; if (ll == !IN6_IS_ADDR_LINKLOCAL(&addr)) return 0; if (ifindex && ifa->ifa_index != ifindex) return 0; kdebugf("found address on interface %s(%d): %s\n", if_indextoname(ifa->ifa_index, ifname), ifa->ifa_index, format_address(addr.s6_addr)); if (data) { struct kernel_route *route = &routes[*found]; memcpy(route->prefix, addr.s6_addr, 16); route->plen = 128; route->metric = 0; route->ifindex = ifa->ifa_index; route->proto = RTPROT_BABEL_LOCAL; memset(route->gw, 0, 16); *found = (*found)+1; } return 1; }
int kernel_route(int operation, const unsigned char *dest, unsigned short plen, const unsigned char *gate, int ifindex, unsigned int metric, const unsigned char *newgate, int newifindex, unsigned int newmetric) { union { char raw[1024]; struct nlmsghdr nh; } buf; struct rtmsg *rtm; struct rtattr *rta; int len = sizeof(buf.raw); int rc, ipv4; if(!nl_setup) { fprintf(stderr,"kernel_route: netlink not initialized.\n"); errno = EIO; return -1; } /* if the socket has been closed after an IO error, */ /* we try to re-open it. */ if(nl_command.sock < 0) { rc = netlink_socket(&nl_command, 0); if(rc < 0) { int olderrno = errno; perror("kernel_route: netlink_socket()"); errno = olderrno; return -1; } } /* Check that the protocol family is consistent. */ if(plen >= 96 && v4mapped(dest)) { if(!v4mapped(gate)) { errno = EINVAL; return -1; } } else { if(v4mapped(gate)) { errno = EINVAL; return -1; } } ipv4 = v4mapped(gate); if(operation == ROUTE_MODIFY) { if(newmetric == metric && memcmp(newgate, gate, 16) == 0 && newifindex == ifindex) return 0; /* It would be better to add the new route before removing the old one, to avoid losing packets. However, this causes problems with non-multipath kernels, which sometimes silently fail the request, causing "stuck" routes. Let's stick with the naive approach, and hope that the window is small enough to be negligible. */ kernel_route(ROUTE_FLUSH, dest, plen, gate, ifindex, metric, NULL, 0, 0); rc = kernel_route(ROUTE_ADD, dest, plen, newgate, newifindex, newmetric, NULL, 0, 0); if(rc < 0) { if(errno == EEXIST) rc = 1; /* Should we try to re-install the flushed route on failure? Error handling is hard. */ } return rc; } kdebugf("kernel_route: %s %s/%d metric %d dev %d nexthop %s\n", operation == ROUTE_ADD ? "add" : operation == ROUTE_FLUSH ? "flush" : "???", format_address(dest), plen, metric, ifindex, format_address(gate)); /* Unreachable default routes cause all sort of weird interactions; ignore them. */ if(metric >= KERNEL_INFINITY && (plen == 0 || (ipv4 && plen == 96))) return 0; memset(buf.raw, 0, sizeof(buf.raw)); if(operation == ROUTE_ADD) { buf.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL; buf.nh.nlmsg_type = RTM_NEWROUTE; } else { buf.nh.nlmsg_flags = NLM_F_REQUEST; buf.nh.nlmsg_type = RTM_DELROUTE; } rtm = NLMSG_DATA(&buf.nh); rtm->rtm_family = ipv4 ? AF_INET : AF_INET6; rtm->rtm_dst_len = ipv4 ? plen - 96 : plen; rtm->rtm_table = export_table; rtm->rtm_scope = RT_SCOPE_UNIVERSE; if(metric < KERNEL_INFINITY) rtm->rtm_type = RTN_UNICAST; else rtm->rtm_type = RTN_UNREACHABLE; rtm->rtm_protocol = RTPROT_BABEL; rtm->rtm_flags |= RTNH_F_ONLINK; rta = RTM_RTA(rtm); if(ipv4) { rta = RTA_NEXT(rta, len); rta->rta_len = RTA_LENGTH(sizeof(struct in_addr)); rta->rta_type = RTA_DST; memcpy(RTA_DATA(rta), dest + 12, sizeof(struct in_addr)); } else { rta = RTA_NEXT(rta, len); rta->rta_len = RTA_LENGTH(sizeof(struct in6_addr)); rta->rta_type = RTA_DST; memcpy(RTA_DATA(rta), dest, sizeof(struct in6_addr)); } rta = RTA_NEXT(rta, len); rta->rta_len = RTA_LENGTH(sizeof(int)); rta->rta_type = RTA_PRIORITY; if(metric < KERNEL_INFINITY) { *(int*)RTA_DATA(rta) = metric; rta = RTA_NEXT(rta, len); rta->rta_len = RTA_LENGTH(sizeof(int)); rta->rta_type = RTA_OIF; *(int*)RTA_DATA(rta) = ifindex; if(ipv4) { rta = RTA_NEXT(rta, len); rta->rta_len = RTA_LENGTH(sizeof(struct in_addr)); rta->rta_type = RTA_GATEWAY; memcpy(RTA_DATA(rta), gate + 12, sizeof(struct in_addr)); } else { rta = RTA_NEXT(rta, len); rta->rta_len = RTA_LENGTH(sizeof(struct in6_addr)); rta->rta_type = RTA_GATEWAY; memcpy(RTA_DATA(rta), gate, sizeof(struct in6_addr)); } } else { *(int*)RTA_DATA(rta) = -1; } buf.nh.nlmsg_len = (char*)rta + rta->rta_len - buf.raw; return netlink_talk(&buf.nh); }
int kernel_route(int operation, const unsigned char *dest, unsigned short plen, const unsigned char *gate, int ifindex, unsigned int metric, const unsigned char *newgate, int newifindex, unsigned int newmetric) { struct { struct rt_msghdr m_rtm; char m_space[512]; } msg; char *data = msg.m_space; int rc, ipv4; char local6[1][1][16] = IN6ADDR_LOOPBACK_INIT; char local4[1][1][16] = {{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x01 }}}; /* Check that the protocol family is consistent. */ if(plen >= 96 && v4mapped(dest)) { if(!v4mapped(gate)) { errno = EINVAL; return -1; } ipv4 = 1; } else { if(v4mapped(gate)) { errno = EINVAL; return -1; } ipv4 = 0; } if(operation == ROUTE_MODIFY && newmetric == metric && memcmp(newgate, gate, 16) == 0 && newifindex == ifindex) return 0; if(operation == ROUTE_MODIFY) { /* Avoid atomic route changes that is buggy on OS X. */ kernel_route(ROUTE_FLUSH, dest, plen, gate, ifindex, metric, NULL, 0, 0); return kernel_route(ROUTE_ADD, dest, plen, newgate, newifindex, newmetric, NULL, 0, 0); } kdebugf("kernel_route: %s %s/%d metric %d dev %d nexthop %s\n", operation == ROUTE_ADD ? "add" : operation == ROUTE_FLUSH ? "flush" : "change", format_address(dest), plen, metric, ifindex, format_address(gate)); if(kernel_socket < 0) kernel_setup_socket(1); memset(&msg, 0, sizeof(msg)); msg.m_rtm.rtm_version = RTM_VERSION; switch(operation) { case ROUTE_FLUSH: msg.m_rtm.rtm_type = RTM_DELETE; break; case ROUTE_ADD: msg.m_rtm.rtm_type = RTM_ADD; break; case ROUTE_MODIFY: msg.m_rtm.rtm_type = RTM_CHANGE; break; default: return -1; }; msg.m_rtm.rtm_index = ifindex; msg.m_rtm.rtm_flags = RTF_UP | RTF_PROTO2; if(plen == 128) msg.m_rtm.rtm_flags |= RTF_HOST; if(metric == KERNEL_INFINITY) { msg.m_rtm.rtm_flags |= RTF_BLACKHOLE; if(ifindex_lo < 0) { ifindex_lo = if_nametoindex("lo0"); if(ifindex_lo <= 0) return -1; } msg.m_rtm.rtm_index = ifindex_lo; } msg.m_rtm.rtm_seq = ++seq; msg.m_rtm.rtm_addrs = RTA_DST | RTA_GATEWAY; if(plen != 128) msg.m_rtm.rtm_addrs |= RTA_NETMASK; #define PUSHEUI(ifindex) \ do { char ifname[IFNAMSIZ]; \ struct sockaddr_dl *sdl = (struct sockaddr_dl*) data; \ if(!if_indextoname((ifindex), ifname)) \ return -1; \ if(get_sdl(sdl, ifname) < 0) \ return -1; \ data = data + ROUNDUP(sdl->sdl_len); \ } while (0) #define PUSHADDR(src) \ do { struct sockaddr_in *sin = (struct sockaddr_in*) data; \ sin->sin_len = sizeof(struct sockaddr_in); \ sin->sin_family = AF_INET; \ memcpy(&sin->sin_addr, (src) + 12, 4); \ data = data + ROUNDUP(sin->sin_len); \ } while (0) #define PUSHADDR6(src) \ do { struct sockaddr_in6 *sin6 = (struct sockaddr_in6*) data; \ sin6->sin6_len = sizeof(struct sockaddr_in6); \ sin6->sin6_family = AF_INET6; \ memcpy(&sin6->sin6_addr, (src), 16); \ if(IN6_IS_ADDR_LINKLOCAL (&sin6->sin6_addr)) \ SET_IN6_LINKLOCAL_IFINDEX (sin6->sin6_addr, ifindex); \ data = data + ROUNDUP(sin6->sin6_len); \ } while (0) /* KAME ipv6 stack does not support IPv4 mapped IPv6, so we have to * duplicate the codepath */ if(ipv4) { PUSHADDR(dest); if (metric == KERNEL_INFINITY) { PUSHADDR(**local4); } else if(plen == 128 && memcmp(dest+12, gate+12, 4) == 0) { #if defined(RTF_CLONING) msg.m_rtm.rtm_flags |= RTF_CLONING; #endif PUSHEUI(ifindex); } else { msg.m_rtm.rtm_flags |= RTF_GATEWAY; PUSHADDR(gate); } if((msg.m_rtm.rtm_addrs & RTA_NETMASK) != 0) { struct in6_addr tmp_sin6_addr; plen2mask(plen, &tmp_sin6_addr); PUSHADDR((char *)&tmp_sin6_addr); } } else { PUSHADDR6(dest); if (metric == KERNEL_INFINITY) { PUSHADDR6(**local6); } else { msg.m_rtm.rtm_flags |= RTF_GATEWAY; PUSHADDR6(gate); } if((msg.m_rtm.rtm_addrs & RTA_NETMASK) != 0) { struct in6_addr tmp_sin6_addr; plen2mask(plen, &tmp_sin6_addr); PUSHADDR6((char*)&tmp_sin6_addr); } } #undef PUSHEUI #undef PUSHADDR #undef PUSHADDR6 msg.m_rtm.rtm_msglen = data - (char *)&msg; rc = write(kernel_socket, (char*)&msg, msg.m_rtm.rtm_msglen); if (rc < msg.m_rtm.rtm_msglen) return -1; return 1; }