/* * Routing (variable) * * The Routing field is optional and is present only if the Routing * Present bit is set to 1. * * The Routing field is a list of Source Route Entries (SREs). Each * SRE has the form: * * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Address Family | SRE Offset | SRE Length | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Routing Information ... * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * */ libnet_ptag_t libnet_build_gre_sre(uint16_t af, uint8_t offset, uint8_t length, uint8_t *routing, const uint8_t *payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag) { uint32_t n; libnet_pblock_t *p; struct libnet_gre_sre_hdr sre_hdr; if (l == NULL) { return (-1); } n = LIBNET_GRE_SRE_H + length + payload_s; /* * Find the existing protocol block if a ptag is specified, or create * a new one. */ p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_GRE_SRE_H); if (p == NULL) { return (-1); } sre_hdr.af = htons(af); sre_hdr.sre_offset = offset; sre_hdr.sre_length = length; n = libnet_pblock_append(l, p, (uint8_t *)&sre_hdr, LIBNET_GRE_SRE_H); if (n == -1) { /* err msg set in libnet_pblock_append() */ goto bad; } if ((routing && !length) || (!routing && length)) { sprintf(l->err_buf, "%s(): routing inconsistency", __func__); goto bad; } if (routing && length) { n = libnet_pblock_append(l, p, routing, length); if (n == -1) { /* err msg set in libnet_pblock_append() */ goto bad; } } /* boilerplate payload sanity check / append macro */ LIBNET_DO_PAYLOAD(l, p); return (ptag ? ptag : libnet_pblock_update(l, p, 0, LIBNET_PBLOCK_GRE_SRE_H)); bad: libnet_pblock_delete(l, p); return (-1); }
libnet_ptag_t libnet_build_dnsv4(uint16_t h_len, uint16_t id, uint16_t flags, uint16_t num_q, uint16_t num_anws_rr, uint16_t num_auth_rr, uint16_t num_addi_rr, const uint8_t *payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag) { uint32_t n, h; uint offset; libnet_pblock_t *p; struct libnet_dnsv4_hdr dns_hdr; if (l == NULL) { return (-1); } if (h_len != LIBNET_UDP_DNSV4_H && h_len != LIBNET_TCP_DNSV4_H) { snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): invalid header length: %d", __func__, h_len); return (-1); } offset = (h_len == LIBNET_UDP_DNSV4_H ? sizeof(dns_hdr.h_len) : 0); n = h_len + payload_s; h = 0; /* no checksum */ /* * Find the existing protocol block if a ptag is specified, or create * a new one. */ p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_DNSV4_H); if (p == NULL) { return (-1); } /* * The sizeof(dns_hdr.h_len) is not counted is the packet size * for TCP packet. * And since this will be ignored for udp packets, let's compute it * anyway. */ memset(&dns_hdr, 0, sizeof(dns_hdr)); dns_hdr.h_len = htons(n - sizeof (dns_hdr.h_len)); dns_hdr.id = htons(id); dns_hdr.flags = htons(flags); dns_hdr.num_q = htons(num_q); dns_hdr.num_answ_rr = htons(num_anws_rr); dns_hdr.num_auth_rr = htons(num_auth_rr); dns_hdr.num_addi_rr = htons(num_addi_rr); /* * A dirty trick: DNS can be either TCP or UDP based, and depending on * that, the header changes. A 'length' field is present in TCP packets, * but not in UDP packets. As they are the first 2 bytes of the header, * they are skipped if the packet is UDP... */ n = libnet_pblock_append(l, p, ((uint8_t *)&dns_hdr) + offset, h_len); if (n == -1) { goto bad; } /* boilerplate payload sanity check / append macro */ LIBNET_DO_PAYLOAD(l, p); return (ptag ? ptag : libnet_pblock_update(l, p, h, LIBNET_PBLOCK_DNSV4_H)); bad: libnet_pblock_delete(l, p); return (-1); }
libnet_ptag_t libnet_build_gre(uint16_t fv, uint16_t type, uint16_t sum, uint16_t offset, uint32_t key, uint32_t seq, uint16_t len, const uint8_t *payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag) { uint32_t n; libnet_pblock_t *p; struct libnet_gre_hdr gre_hdr; if (l == NULL) { return (-1); } n = libnet_getgre_length(fv) + payload_s; /* * Find the existing protocol block if a ptag is specified, or create * a new one. */ p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_GRE_H); if (p == NULL) { return (-1); } gre_hdr.flags_ver = htons(fv); gre_hdr.type = htons(type); n = libnet_pblock_append(l, p, (uint8_t *)&gre_hdr, LIBNET_GRE_H); if (n == -1) { /* err msg set in libnet_pblock_append() */ goto bad; } if ((!(fv & GRE_VERSION_MASK) && (fv & (GRE_CSUM|GRE_ROUTING))) || /* v0 */ (fv & GRE_VERSION_MASK)) /* v1 */ { sum = htons(sum); n = libnet_pblock_append(l, p, (uint8_t*)&sum, sizeof(gre_hdr.gre_sum)); if (n == -1) { /* err msg set in libnet_pblock_append() */ goto bad; } offset = htons(offset); n = libnet_pblock_append(l, p, (uint8_t*)&offset, sizeof(gre_hdr.gre_offset)); if (n == -1) { /* err msg set in libnet_pblock_append() */ goto bad; } } if ((!(fv & GRE_VERSION_MASK) && (fv & GRE_KEY)) || /* v0 */ ( (fv & GRE_VERSION_MASK) && (fv & GRE_SEQ)) ) /* v1 */ { key = htonl(key); n = libnet_pblock_append(l, p, (uint8_t*)&key, sizeof(gre_hdr.gre_key)); if (n == -1) { /* err msg set in libnet_pblock_append() */ goto bad; } } if ((!(fv & GRE_VERSION_MASK) && (fv & GRE_SEQ)) || /* v0 */ ( (fv & GRE_VERSION_MASK) && (fv & GRE_ACK)) ) /* v1 */ { seq = htonl(seq); n = libnet_pblock_append(l, p, (uint8_t*)&seq, sizeof(gre_hdr.gre_seq)); if (n == -1) { /* err msg set in libnet_pblock_append() */ goto bad; } } /* boilerplate payload sanity check / append macro */ LIBNET_DO_PAYLOAD(l, p); if ( (fv & GRE_CSUM) && (!sum) ) { libnet_pblock_setflags(p, LIBNET_PBLOCK_DO_CHECKSUM); } return (ptag ? ptag : libnet_pblock_update(l, p, len, LIBNET_PBLOCK_GRE_H)); bad: libnet_pblock_delete(l, p); return (-1); }
libnet_ptag_t libnet_build_igmp(u_int8_t type, u_int8_t code, u_int16_t sum, u_int32_t ip, u_int8_t *payload, u_int32_t payload_s, libnet_t *l, libnet_ptag_t ptag) { u_int32_t n, h; libnet_pblock_t *p; struct libnet_igmp_hdr igmp_hdr; if (l == NULL) { return (-1); } n = LIBNET_IGMP_H + payload_s; h = LIBNET_IGMP_H; /* * Find the existing protocol block if a ptag is specified, or create * a new one. */ p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_IGMP_H); if (p == NULL) { return (-1); } memset(&igmp_hdr, 0, sizeof(igmp_hdr)); igmp_hdr.igmp_type = type; /* packet type */ igmp_hdr.igmp_code = code; /* packet code */ igmp_hdr.igmp_sum = (sum ? htons(sum) : 0); /* packet checksum */ igmp_hdr.igmp_group.s_addr = htonl(ip); n = libnet_pblock_append(l, p, (u_int8_t *)&igmp_hdr, LIBNET_IGMP_H); if (n == -1) { goto bad; } if ((payload && !payload_s) || (!payload && payload_s)) { snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): payload inconsistency\n", __func__); goto bad; } if (payload && payload_s) { n = libnet_pblock_append(l, p, payload, payload_s); if (n == -1) { goto bad; } } if (sum == 0) { /* * If checksum is zero, by default libnet will compute a checksum * for the user. The programmer can override this by calling * libnet_toggle_checksum(l, ptag, 1); */ libnet_pblock_setflags(p, LIBNET_PBLOCK_DO_CHECKSUM); } return (ptag ? ptag : libnet_pblock_update(l, p, h, LIBNET_PBLOCK_IGMP_H)); bad: libnet_pblock_delete(l, p); return (-1); }
libnet_ptag_t libnet_build_cdp(uint8_t version, uint8_t ttl, uint16_t sum, uint16_t type, uint16_t len, const uint8_t *value, const uint8_t *payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag) { uint32_t n,h; libnet_pblock_t *p; struct libnet_cdp_hdr cdp_hdr; if (l == NULL) { return (-1); } n = LIBNET_CDP_H + LIBNET_CDP_H + len + payload_s; h = LIBNET_CDP_H + LIBNET_CDP_H + len + payload_s; /* * Find the existing protocol block if a ptag is specified, or create * a new one. */ p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_CDP_H); if (p == NULL) { return (-1); } memset(&cdp_hdr, 0, sizeof(cdp_hdr)); cdp_hdr.cdp_version = version; cdp_hdr.cdp_ttl = ttl; cdp_hdr.cdp_sum = (sum ? htons(sum) : 0); cdp_hdr.cdp_type = htons(type); cdp_hdr.cdp_len = htons(len + 4); /* 4 bytes for len and type */ n = libnet_pblock_append(l, p, (uint8_t *)&cdp_hdr, LIBNET_CDP_H); if (n == -1) { goto bad; } n = libnet_pblock_append(l, p, value, len); if (n == -1) { /* err msg set in libnet_pblock_append() */ goto bad; } /* boilerplate payload sanity check / append macro */ LIBNET_DO_PAYLOAD(l, p); if (sum == 0) { /* * If checksum is zero, by default libnet will compute a checksum * for the user. The programmer can override this by calling * libnet_toggle_checksum(l, ptag, 1); */ libnet_pblock_setflags(p, LIBNET_PBLOCK_DO_CHECKSUM); } return (ptag ? ptag : libnet_pblock_update(l, p, h, LIBNET_PBLOCK_CDP_H)); bad: libnet_pblock_delete(l, p); return (-1); }
libnet_ptag_t libnet_build_hsrp(uint8_t version, uint8_t opcode, uint8_t state, uint8_t hello_time, uint8_t hold_time, uint8_t priority, uint8_t group, uint8_t reserved, uint8_t authdata[HSRP_AUTHDATA_LENGTH], uint32_t virtual_ip, const uint8_t *payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag) { uint32_t n; libnet_pblock_t *p; struct libnet_hsrp_hdr hsrp_hdr; if (l == NULL) { return (-1); } /* * Find the existing protocol block if a ptag is specified, or create * a new one. */ p = libnet_pblock_probe(l, ptag, LIBNET_HSRP_H + payload_s, LIBNET_PBLOCK_HSRP_H); if (p == NULL) { return (-1); } memset(&hsrp_hdr, 0, sizeof(hsrp_hdr)); hsrp_hdr.version = version; hsrp_hdr.opcode = opcode; hsrp_hdr.state = state; hsrp_hdr.hello_time = hello_time; hsrp_hdr.hold_time = hold_time; hsrp_hdr.priority = priority; hsrp_hdr.group = group; hsrp_hdr.reserved = reserved; memcpy(hsrp_hdr.authdata, authdata, HSRP_AUTHDATA_LENGTH*sizeof(uint8_t)); hsrp_hdr.virtual_ip = virtual_ip; n = libnet_pblock_append(l, p, (uint8_t *)&hsrp_hdr, LIBNET_HSRP_H); if (n == -1) { goto bad; } if (payload_s && !payload) { snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): payload inconsistency\n", __func__); goto bad; } if (payload_s) { n = libnet_pblock_append(l, p, payload, payload_s); if (n == -1) { goto bad; } } return (ptag ? ptag : libnet_pblock_update(l, p, 0, LIBNET_PBLOCK_HSRP_H)); bad: libnet_pblock_delete(l, p); return (-1); }
libnet_ptag_t libnet_build_vrrp(uint8_t version, uint8_t type, uint8_t vrouter_id, uint8_t priority, uint8_t ip_count, uint8_t auth_type, uint8_t advert_int, uint16_t sum, const uint8_t *payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag) { uint32_t n, h; libnet_pblock_t *p; struct libnet_vrrp_hdr vrrp_hdr; if (l == NULL) { return (-1); } n = LIBNET_VRRP_H + payload_s; h = LIBNET_VRRP_H + payload_s; /* * Find the existing protocol block if a ptag is specified, or create * a new one. */ p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_VRRP_H); if (p == NULL) { return (-1); } memset(&vrrp_hdr, 0, sizeof(vrrp_hdr)); vrrp_hdr.vrrp_v = version; vrrp_hdr.vrrp_t = type; vrrp_hdr.vrrp_vrouter_id = vrouter_id; vrrp_hdr.vrrp_priority = priority; vrrp_hdr.vrrp_ip_count = ip_count; vrrp_hdr.vrrp_auth_type = auth_type; vrrp_hdr.vrrp_advert_int = advert_int; vrrp_hdr.vrrp_sum = (sum ? htons(sum) : 0); n = libnet_pblock_append(l, p, (uint8_t *)&vrrp_hdr, LIBNET_VRRP_H); if (n == -1) { goto bad; } /* boilerplate payload sanity check / append macro */ LIBNET_DO_PAYLOAD(l, p); if (sum == 0) { /* * If checksum is zero, by default libnet will compute a checksum * for the user. The programmer can override this by calling * libnet_toggle_checksum(l, ptag, 1); */ libnet_pblock_setflags(p, LIBNET_PBLOCK_DO_CHECKSUM); } return (ptag ? ptag : libnet_pblock_update(l, p, h, LIBNET_PBLOCK_VRRP_H)); bad: libnet_pblock_delete(l, p); return (-1); }
libnet_ptag_t libnet_build_dhcpv4(uint8_t opcode, uint8_t htype, uint8_t hlen, uint8_t hopcount, uint32_t xid, uint16_t secs, uint16_t flags, uint32_t cip, uint32_t yip, uint32_t sip, uint32_t gip, const uint8_t *chaddr, const char *sname, const char *file, const uint8_t *payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag) { uint32_t n, h; libnet_pblock_t *p; struct libnet_dhcpv4_hdr dhcp_hdr; if (l == NULL) { return (-1); } n = LIBNET_DHCPV4_H + payload_s; h = 0; /* no checksum */ /* * Find the existing protocol block if a ptag is specified, or create * a new one. */ p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_DHCPV4_H); if (p == NULL) { return (-1); } memset(&dhcp_hdr, 0, sizeof(dhcp_hdr)); dhcp_hdr.dhcp_opcode = opcode; dhcp_hdr.dhcp_htype = htype; dhcp_hdr.dhcp_hlen = hlen; dhcp_hdr.dhcp_hopcount = hopcount; dhcp_hdr.dhcp_xid = htonl(xid); dhcp_hdr.dhcp_secs = htons(secs); dhcp_hdr.dhcp_flags = htons(flags); dhcp_hdr.dhcp_cip = htonl(cip); dhcp_hdr.dhcp_yip = htonl(yip); dhcp_hdr.dhcp_sip = htonl(sip); dhcp_hdr.dhcp_gip = htonl(gip); if (chaddr) { size_t n = sizeof (dhcp_hdr.dhcp_chaddr); if (hlen < n) n = hlen; memcpy(dhcp_hdr.dhcp_chaddr, chaddr, n); } if (sname) { strncpy(dhcp_hdr.dhcp_sname, sname, sizeof (dhcp_hdr.dhcp_sname) - 1); } if (file) { strncpy(dhcp_hdr.dhcp_file, file, sizeof (dhcp_hdr.dhcp_file) - 1); } dhcp_hdr.dhcp_magic = htonl(DHCP_MAGIC); n = libnet_pblock_append(l, p, (uint8_t *)&dhcp_hdr, LIBNET_DHCPV4_H); if (n == -1) { goto bad; } if (payload_s && !payload) { snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): payload inconsistency\n", __func__); goto bad; } if (payload_s) { n = libnet_pblock_append(l, p, payload, payload_s); if (n == -1) { goto bad; } } return (ptag ? ptag : libnet_pblock_update(l, p, h, LIBNET_PBLOCK_DHCPV4_H)); bad: libnet_pblock_delete(l, p); return (-1); }
libnet_ptag_t libnet_build_ospfv2_lsa(uint16_t age, uint8_t opts, uint8_t type, uint32_t lsid, uint32_t advrtr, uint32_t seqnum, uint16_t sum, uint16_t len, const uint8_t *payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag) { uint32_t n, h; libnet_pblock_t *p; struct libnet_lsa_hdr lsa_hdr; if (l == NULL) { return (-1); } n = LIBNET_OSPF_LSA_H + payload_s; h = len + payload_s; /* * Find the existing protocol block if a ptag is specified, or create * a new one. */ p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_OSPF_LSA_H); if (p == NULL) { return (-1); } memset(&lsa_hdr, 0, sizeof(lsa_hdr)); lsa_hdr.lsa_age = htons(age); lsa_hdr.lsa_opts = opts; lsa_hdr.lsa_type = type; lsa_hdr.lsa_id = htonl(lsid); lsa_hdr.lsa_adv.s_addr = htonl(advrtr); lsa_hdr.lsa_seq = htonl(seqnum); lsa_hdr.lsa_sum = sum; lsa_hdr.lsa_len = htons(h); n = libnet_pblock_append(l, p, (uint8_t *)&lsa_hdr, LIBNET_OSPF_LSA_H); if (n == -1) { goto bad; } /* boilerplate payload sanity check / append macro */ LIBNET_DO_PAYLOAD(l, p); if (sum == 0) { /* * If checksum is zero, by default libnet will compute a checksum * for the user. The programmer can override this by calling * libnet_toggle_checksum(l, ptag, 1); */ libnet_pblock_setflags(p, LIBNET_PBLOCK_DO_CHECKSUM); } return (ptag ? ptag : libnet_pblock_update(l, p, h, LIBNET_PBLOCK_OSPF_LSA_H)); bad: libnet_pblock_delete(l, p); return (-1); }
libnet_ptag_t libnet_build_802_1q(u_char *dst, u_char *src, u_short tpi, u_char priority, u_char cfi, u_short vid, u_short len, u_char *payload, u_long payload_s, libnet_t *l, libnet_ptag_t ptag) { u_long n; u_short h; libnet_pblock_t *p; struct libnet_802_1q_hdr _802_1q_hdr; if (l == NULL) { return (-1); } n = LIBNET_802_1Q_H + payload_s; h = 0; /* * Find the existing protocol block if a ptag is specified, or create * a new one. */ p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_802_1Q_H); if (p == NULL) { return (-1); } memcpy(_802_1q_hdr.vlan_dhost, dst, ETHER_ADDR_LEN); memcpy(_802_1q_hdr.vlan_shost, src, ETHER_ADDR_LEN); _802_1q_hdr.vlan_tpi = htons(tpi); _802_1q_hdr.vlan_priority_c_vid = htons((priority << 13) | (cfi << 12) | (vid & LIBNET_802_1Q_VIDMASK)); _802_1q_hdr.vlan_len = htons(len); n = libnet_pblock_append(l, p, (u_char *)&_802_1q_hdr, LIBNET_802_1Q_H); if (n == -1) { goto bad; } if (payload && payload_s) { n = libnet_pblock_append(l, p, payload, payload_s); if (n == -1) { goto bad; } } /* * The link offset is actually 18 bytes (the VLAN tag is 4 bytes). We * need to update the link offset pointer... XXX - should we set this * here..? Probably not. We should make pblock_coalesce check the * pblock type and adjust accordingly. */ l->link_offset = 0x12; return (ptag ? ptag : libnet_pblock_update(l, p, h, LIBNET_PBLOCK_802_1Q_H)); bad: libnet_pblock_free(p); return (-1); }