/** * same as tcpedit_set_encoder_plugin_byid() except we take the DLT_<name> * as a string to select it */ int tcpedit_set_encoder_dltplugin_byname(tcpedit_t *tcpedit, const char *name) { tcpeditdlt_plugin_t *plugin; tcpeditdlt_t *ctx; assert(tcpedit); ctx = tcpedit->dlt_ctx; assert(ctx); if (ctx->encoder) { tcpedit_seterr(tcpedit, "You have already selected a DLT encoder: %s", ctx->encoder->name); return TCPEDIT_ERROR; } plugin = tcpedit_dlt_getplugin_byname(ctx, name); if (plugin == NULL) { tcpedit_seterr(tcpedit, "No output DLT plugin available for: %s", name); return TCPEDIT_ERROR; } ctx->encoder = plugin; /* init the encoder plugin if it's not the decoder plugin too */ if (ctx->encoder->dlt != ctx->decoder->dlt) { if (ctx->encoder->plugin_init(ctx) != TCPEDIT_OK) { /* plugin should generate the error */ return TCPEDIT_ERROR; } } return TCPEDIT_OK; }
/* * Function to decode the layer 2 header in the packet. * You need to fill out: * - ctx->l2len * - ctx->srcaddr * - ctx->dstaddr * - ctx->proto * - ctx->decoded_extra * Returns: TCPEDIT_ERROR | TCPEDIT_OK | TCPEDIT_WARN */ int dlt_ieee80211_decode(tcpeditdlt_t *ctx, const u_char *packet, const int pktlen) { assert(ctx); assert(packet); assert(pktlen >= dlt_ieee80211_l2len(ctx, packet, pktlen)); dbgx(3, "Decoding 802.11 packet " COUNTER_SPEC, ctx->tcpedit->runtime.packetnum); if (! ieee80211_is_data(ctx, packet, pktlen)) { tcpedit_seterr(ctx->tcpedit, "Packet " COUNTER_SPEC " is not a normal 802.11 data frame", ctx->tcpedit->runtime.packetnum); return TCPEDIT_SOFT_ERROR; } if (ieee80211_is_encrypted(ctx, packet, pktlen)) { tcpedit_seterr(ctx->tcpedit, "Packet " COUNTER_SPEC " is encrypted. Unable to decode frame.", ctx->tcpedit->runtime.packetnum); return TCPEDIT_SOFT_ERROR; } ctx->l2len = dlt_ieee80211_l2len(ctx, packet, pktlen); memcpy(&(ctx->srcaddr), ieee80211_get_src((ieee80211_hdr_t *)packet), ETHER_ADDR_LEN); memcpy(&(ctx->dstaddr), ieee80211_get_dst((ieee80211_hdr_t *)packet), ETHER_ADDR_LEN); ctx->proto = dlt_ieee80211_proto(ctx, packet, pktlen); return TCPEDIT_OK; /* success */ }
/* * Function to decode the layer 2 header in the packet. * You need to fill out: * - ctx->l2len * - ctx->srcaddr * - ctx->dstaddr * - ctx->proto * - ctx->decoded_extra * Returns: TCPEDIT_ERROR | TCPEDIT_OK | TCPEDIT_WARN */ int dlt_jnpr_ether_decode(tcpeditdlt_t *ctx, const u_char *packet, const int pktlen) { int jnpr_header_len = 0; const u_char *ethernet = NULL; jnpr_ether_config_t *config; assert(ctx); assert(packet); assert(pktlen > JUNIPER_ETHER_HEADER_LEN); /* MAGIC + Static fields + Extension Length */ config = (jnpr_ether_config_t *)ctx->encoder->config; /* first, verify magic */ if (memcmp(packet, JUNIPER_ETHER_MAGIC, JUNIPER_ETHER_MAGIC_LEN) != 0) { tcpedit_seterr(ctx->tcpedit, "Invalid magic 0x%02X%02X%02X", packet[0], packet[1], packet[2]); return TCPEDIT_ERROR; } /* next make sure the L2 header is present */ if ((packet[JUNIPER_ETHER_OPTIONS_OFFSET] & JUNIPER_ETHER_L2PRESENT) != JUNIPER_ETHER_L2PRESENT) { tcpedit_seterr(ctx->tcpedit, "Frame is missing L2 Header: %x", packet[JUNIPER_ETHER_OPTIONS_OFFSET]); return TCPEDIT_ERROR; } /* then get the Juniper header length */ memcpy(&jnpr_header_len, &packet[JUNIPER_ETHER_EXTLEN_OFFSET], 2); jnpr_header_len = ntohs(jnpr_header_len) + JUNIPER_ETHER_HEADER_LEN; dbgx(1, "jnpr header len: %d", jnpr_header_len); /* make sure the packet is big enough to find the Ethernet Header */ if (pktlen < jnpr_header_len + TCPR_ETH_H) { tcpedit_seterr(ctx->tcpedit, "Frame is too short! %d < %d", pktlen, (jnpr_header_len + TCPR_ETH_H)); return TCPEDIT_ERROR; } ctx->l2len = jnpr_header_len; /* jump to the appropriate offset */ ethernet = packet + jnpr_header_len; /* let the en10mb plugin decode the rest */ if (tcpedit_dlt_decode(config->subctx, ethernet, (pktlen - jnpr_header_len)) == TCPEDIT_ERROR) return TCPEDIT_ERROR; /* copy the subdecoder state to our encoder state */ if (tcpedit_dlt_copy_decoder_state(ctx, config->subctx) == TCPEDIT_ERROR) return TCPEDIT_ERROR; return TCPEDIT_OK; }
/* * Function to encode the layer 2 header back into the packet. * Returns: total packet len or TCPEDIT_ERROR */ int dlt_hdlc_encode(tcpeditdlt_t *ctx, u_char *packet, int pktlen, _U_ tcpr_dir_t dir) { cisco_hdlc_t *hdlc; hdlc_config_t *config = NULL; hdlc_extra_t *extra = NULL; tcpeditdlt_plugin_t *plugin = NULL; u_char tmpbuff[MAXPACKET]; int newpktlen; assert(ctx); assert(pktlen >= 4); assert(packet); /* Make room for our new l2 header if old l2len != 4 */ if (ctx->l2len > 4) { memmove(packet + 4, packet + ctx->l2len, pktlen - ctx->l2len); } else if (ctx->l2len < 4) { memcpy(tmpbuff, packet, pktlen); memcpy(packet + 4, (tmpbuff + ctx->l2len), pktlen - ctx->l2len); } /* update the total packet length */ newpktlen = pktlen + 4 - ctx->l2len; /* * HDLC doesn't support direction, since we have no real src/dst addresses * to deal with, so we just use the original packet data or option data */ hdlc = (cisco_hdlc_t *)packet; plugin = tcpedit_dlt_getplugin(ctx, dlt_value); config = plugin->config; extra = (hdlc_extra_t *)ctx->decoded_extra; /* set the address field */ if (config->address < 65535) { hdlc->address = (uint8_t)config->address; } else if (extra->hdlc) { hdlc->address = extra->hdlc; } else { tcpedit_seterr(ctx->tcpedit, "%s", "Non-HDLC packet requires --hdlc-address"); return TCPEDIT_ERROR; } /* set the control field */ if (config->control < 65535) { hdlc->control = (uint8_t)config->control; } else if (extra->hdlc) { hdlc->control = extra->hdlc; } else { tcpedit_seterr(ctx->tcpedit, "%s", "Non-HDLC packet requires --hdlc-control"); return TCPEDIT_ERROR; } /* copy over our protocol */ hdlc->protocol = ctx->proto; return newpktlen; /* success */ }
/* * Function to decode the layer 2 header in the packet. * You need to fill out: * - ctx->l2len * - ctx->srcaddr * - ctx->dstaddr * - ctx->proto * - ctx->decoded_extra * Returns: TCPEDIT_ERROR | TCPEDIT_OK | TCPEDIT_WARN */ int dlt_linuxsll_decode(tcpeditdlt_t *ctx, const u_char *packet, const int pktlen) { int type; linux_sll_header_t *linux_sll; assert(ctx); assert(packet); if (pktlen < (int)sizeof(linux_sll_header_t)) return TCPEDIT_ERROR; linux_sll = (linux_sll_header_t *)packet; ctx->proto = linux_sll->proto; ctx->l2len = sizeof(linux_sll_header_t); type = ntohs(linux_sll->type); if (type == ARPHRD_ETHER || type == ARPHRD_LOOPBACK) { /* ethernet or loopback */ memcpy(&(ctx->srcaddr), linux_sll->address, ETHER_ADDR_LEN); } else { tcpedit_seterr(ctx->tcpedit, "%s", "DLT_LINUX_SLL pcap's must contain only ethernet or loopback packets"); return TCPEDIT_ERROR; } return TCPEDIT_OK; /* success */ }
/** * each DLT type may require one or more user specified Layer 2 field * to be able to rewrite it as plain ethernet DLT_EN10MB * returns -1 on error or >= 0 on success */ int dltrequires(tcpedit_t *tcpedit, int dlt) { assert(tcpedit); int req = TCPEDIT_DLT_OK; // no change required by default switch(dlt) { case DLT_JUNIPER_ETHER: case DLT_EN10MB: /* case DLT_USER: case DLT_VLAN: */ /* we have everthing we need in the original packet */ break; case DLT_NULL: case DLT_RAW: case DLT_C_HDLC: case DLT_PPP_SERIAL: req = TCPEDIT_DLT_SRC + TCPEDIT_DLT_DST; /* we just have the proto */ break; case DLT_LINUX_SLL: /* we have proto & SRC address */ req = TCPEDIT_DLT_DST; break; default: tcpedit_seterr(tcpedit, "Invalid DLT Type: %d", dlt); req = -1; } return req; }
/* * Initializer function. This function is called only once, if and only iif * this plugin will be utilized. Remember, if you need to keep track of any state, * store it in your plugin->config, not a global! * Returns: TCPEDIT_ERROR | TCPEDIT_OK | TCPEDIT_WARN */ int dlt_radiotap_init(tcpeditdlt_t *ctx) { tcpeditdlt_plugin_t *plugin; radiotap_config_t *config; assert(ctx); if ((plugin = tcpedit_dlt_getplugin(ctx, dlt_value)) == NULL) { tcpedit_seterr(ctx->tcpedit, "Unable to initalize unregistered plugin %s", dlt_name); return TCPEDIT_ERROR; } /* allocate memory for our deocde extra data */ if (sizeof(radiotap_extra_t) > 0) ctx->decoded_extra = safe_malloc(sizeof(radiotap_extra_t)); /* allocate memory for our config data */ if (sizeof(radiotap_config_t) > 0) plugin->config = safe_malloc(sizeof(radiotap_config_t)); config = (radiotap_config_t *)plugin->config; return TCPEDIT_OK; /* success */ }
/* * Since this is used in a library, we should manually clean up after ourselves * Unless you allocated some memory in dlt_jnpr_ether_init(), this is just an stub. * Returns: TCPEDIT_ERROR | TCPEDIT_OK | TCPEDIT_WARN */ int dlt_jnpr_ether_cleanup(tcpeditdlt_t *ctx) { tcpeditdlt_plugin_t *plugin; jnpr_ether_config_t *config; assert(ctx); if ((plugin = tcpedit_dlt_getplugin(ctx, dlt_value)) == NULL) { tcpedit_seterr(ctx->tcpedit, "Unable to cleanup unregistered plugin %s", dlt_name); return TCPEDIT_ERROR; } if (ctx->decoded_extra != NULL) { safe_free(ctx->decoded_extra); ctx->decoded_extra = NULL; } if (plugin->config != NULL) { /* clean up the en10mb plugin */ config = (jnpr_ether_config_t *)ctx->encoder->config; tcpedit_dlt_cleanup(config->subctx); plugin->config = NULL; } return TCPEDIT_OK; /* success */ }
/* * Initializer function. This function is called only once, if and only iif * this plugin will be utilized. Remember, if you need to keep track of any state, * store it in your plugin->config, not a global! * Returns: TCPEDIT_ERROR | TCPEDIT_OK | TCPEDIT_WARN */ int dlt_hdlc_init(tcpeditdlt_t *ctx) { tcpeditdlt_plugin_t *plugin; hdlc_config_t *config; assert(ctx); if ((plugin = tcpedit_dlt_getplugin(ctx, dlt_value)) == NULL) { tcpedit_seterr(ctx->tcpedit, "Unable to initalize unregistered plugin %s", dlt_name); return TCPEDIT_ERROR; } /* allocate memory for our deocde extra data */ if (sizeof(hdlc_extra_t) > 0) ctx->decoded_extra = safe_malloc(sizeof(hdlc_extra_t)); /* allocate memory for our config data */ if (sizeof(hdlc_config_t) > 0) plugin->config = safe_malloc(sizeof(hdlc_config_t)); config = (hdlc_config_t *)plugin->config; /* default to unset */ config->address = 65535; config->control = 65535; return TCPEDIT_OK; /* success */ }
/* * Function returns the Layer 3 protocol type of the given packet, or TCPEDIT_ERROR on error * Make sure you return this value in NETWORK byte order! */ int dlt_jnpr_ether_proto(tcpeditdlt_t *ctx, const u_char *packet, const int pktlen) { int jnpr_hdr_len; const u_char *ethernet; jnpr_ether_config_t *config; assert(ctx); assert(packet); assert(pktlen > JUNIPER_ETHER_HEADER_LEN); /* MAGIC + Static fields + Extension Length */ config = (jnpr_ether_config_t *)ctx->encoder->config; /* next make sure the L2 header is present */ if ((packet[JUNIPER_ETHER_OPTIONS_OFFSET] & JUNIPER_ETHER_L2PRESENT) != JUNIPER_ETHER_L2PRESENT) { tcpedit_seterr(ctx->tcpedit, "Frame is missing L2 Header: %x", packet[JUNIPER_ETHER_OPTIONS_OFFSET]); return TCPEDIT_ERROR; } /* then get the Juniper header length */ memcpy(&jnpr_hdr_len, &packet[JUNIPER_ETHER_EXTLEN_OFFSET], 2); jnpr_hdr_len = ntohs(jnpr_hdr_len) + JUNIPER_ETHER_HEADER_LEN; ethernet = packet + jnpr_hdr_len; /* let the en10mb plugin do the rest of the work */ return tcpedit_dlt_proto(config->subctx, DLT_EN10MB, ethernet, (pktlen - jnpr_hdr_len)); }
/** * returns the default MTU size for the given DLT type. Returns -1 * for invalid DLT */ int dlt2mtu(tcpedit_t *tcpedit, int dlt) { int mtu; assert(tcpedit); switch (dlt) { /* case DLT_VLAN: case DLT_USER: */ case DLT_PPP_SERIAL: case DLT_EN10MB: case DLT_RAW: case DLT_C_HDLC: case DLT_JUNIPER_ETHER: mtu = 1500; break; case DLT_LINUX_SLL: mtu = 16436; break; case DLT_LOOP: mtu = 16384; break; default: tcpedit_seterr(tcpedit, "Invalid DLT Type: %d", dlt); mtu = -1; break; } return mtu; }
/* * Since this is used in a library, we should manually clean up after ourselves * Unless you allocated some memory in dlt_null_init(), this is just an stub. * Returns: TCPEDIT_ERROR | TCPEDIT_OK | TCPEDIT_WARN */ int dlt_null_cleanup(tcpeditdlt_t *ctx) { tcpeditdlt_plugin_t *plugin; assert(ctx); if ((plugin = tcpedit_dlt_getplugin(ctx, dlt_value)) == NULL) { tcpedit_seterr(ctx->tcpedit, "Unable to cleanup unregistered plugin %s", dlt_name); return TCPEDIT_ERROR; } if (ctx->decoded_extra != NULL) { safe_free(ctx->decoded_extra); ctx->decoded_extra = NULL; ctx->decoded_extra_size = 0; } if (plugin->config != NULL) { safe_free(plugin->config); plugin->config = NULL; plugin->config_size = 0; } return TCPEDIT_OK; /* success */ }
/** * \brief Define the actual L2 header content. * * You need to set the data, it's lenght and which direction(s) to apply to. * BOTH - both directions (or in the case of no tcpprep cache file) * S2C - server to client (primary interface) * C2S - client to server (secondary interface) * * NOTE: the datalen value must be the same between each call. */ int tcpedit_user_set_dlink(tcpedit_t *tcpedit, u_char *data, int datalen, tcpedit_user_dlt_direction direction) { tcpeditdlt_t *ctx; tcpeditdlt_plugin_t *plugin; user_config_t *config; assert(tcpedit); ctx = tcpedit->dlt_ctx; assert(ctx); plugin = ctx->decoder; assert(plugin); config = (user_config_t *)plugin->config; /* sanity checks */ if (datalen <= 0) { tcpedit_seterr(tcpedit, "%s", "user datalink length must be > 0"); return TCPEDIT_ERROR; } else if (datalen > USER_L2MAXLEN) { tcpedit_seterr(tcpedit, "user datalink length is > %d. Please increase USER_L2MAXLEN", USER_L2MAXLEN); return TCPEDIT_ERROR; } if ((config->length > 0) && (config->length != datalen)) { tcpedit_seterr(tcpedit, "%s", "Subsequent calls to tcpedit_user_set_dlink() must use the same datalen"); return TCPEDIT_ERROR; } else { config->length = datalen; switch (direction) { case TCPEDIT_USER_DLT_BOTH: memcpy(config->l2server, data, datalen); memcpy(config->l2client, data, datalen); break; case TCPEDIT_USER_DLT_S2C: memcpy(config->l2server, data, datalen); break; case TCPEDIT_USER_DLT_C2S: memcpy(config->l2client, data, datalen); break; } } return TCPEDIT_OK; }
/* * Function to encode the layer 2 header back into the packet. * Returns: total packet len or TCPEDIT_ERROR */ int dlt_jnpr_ether_encode(tcpeditdlt_t *ctx, u_char *packet, int pktlen, _U_ tcpr_dir_t dir) { assert(ctx); assert(pktlen > JUNIPER_ETHER_HEADER_LEN); /* MAGIC + Static fields + Extension Length */ assert(packet); tcpedit_seterr(ctx->tcpedit, "%s", "DLT_JUNIPER_ETHER plugin does not support packet encoding"); return TCPEDIT_ERROR; }
/* * Function to encode the layer 2 header back into the packet. * Returns: total packet len or TCPEDIT_ERROR */ int dlt_linuxsll_encode(tcpeditdlt_t *ctx, u_char *packet, _U_ int pktlen, _U_ tcpr_dir_t dir) { assert(ctx); assert(packet); tcpedit_seterr(ctx->tcpedit, "%s", "DLT_LINUX_SLL plugin does not support packet encoding"); return TCPEDIT_ERROR; }
/* * Function to encode the layer 2 header back into the packet. * Returns: total packet len or TCPEDIT_ERROR */ int dlt_radiotap_encode(tcpeditdlt_t *ctx, u_char *packet, int pktlen, _U_ tcpr_dir_t dir) { assert(ctx); assert(pktlen > 0); assert(packet); tcpedit_seterr(ctx->tcpedit, "%s", "DLT_IEEE802_11_RADIO plugin does not support packet encoding"); return TCPEDIT_ERROR; }
/* you should never decode packets with this plugin! */ int dlt_user_decode(tcpeditdlt_t *ctx, const u_char *packet, const int pktlen) { assert(ctx); assert(packet); assert(pktlen); tcpedit_seterr(ctx->tcpedit, "%s", "DLT_USER0 plugin does not support packet decoding"); return TCPEDIT_ERROR; }
/* * Function to encode the layer 2 header back into the packet. * Returns: total packet len or TCPEDIT_ERROR */ int dlt_null_encode(tcpeditdlt_t *ctx, u_char *packet, _U_ int pktlen, _U_ tcpr_dir_t dir) { assert(ctx); assert(packet); tcpedit_seterr(ctx->tcpedit, "%s", "DLT_NULL and DLT_LOOP plugins do not support packet encoding"); return TCPEDIT_ERROR; }
/* * Function returns the Layer 3 protocol type of the given packet, or TCPEDIT_ERROR on error */ int dlt_user_proto(tcpeditdlt_t *ctx, const u_char *packet, const int pktlen) { assert(ctx); assert(packet); assert(pktlen); /* calling this for DLT_USER0 is broken */ tcpedit_seterr(ctx->tcpedit, "%s", "Nonsensical calling of dlt_user_proto()"); return TCPEDIT_ERROR; }
/** * Rewrite TCP/UDP ports using the following format: * <src>:<dst>,... */ int tcpedit_set_port_map(tcpedit_t *tcpedit, char *value) { assert(tcpedit); if (! parse_portmap(&tcpedit->portmap, value)) { tcpedit_seterr(tcpedit, "Unable to parse portmap: %s", value); return TCPEDIT_ERROR; } return TCPEDIT_OK; }
/** * Rewrite the Source IP of any packet */ int tcpedit_set_srcip_map(tcpedit_t *tcpedit, char *value) { assert(tcpedit); tcpedit->rewrite_ip = true; if (! parse_cidr_map(&tcpedit->srcipmap, value)) { tcpedit_seterr(tcpedit, "Unable to parse source ip map: %s", value); return TCPEDIT_ERROR; } return TCPEDIT_OK; }
/** * \brief Set the client to server (secondary) CIDR map (Pseudo NAT) * * Set the client to server (secondary) CIDR map using the given string * which is in the format of: * <match cidr>:<target cidr>,... * 192.168.0.0/16:10.77.0.0/16,172.16.0.0/12:10.1.0.0/24 */ int tcpedit_set_cidrmap_c2s(tcpedit_t *tcpedit, char *value) { assert(tcpedit); tcpedit->rewrite_ip = true; if (! parse_cidr_map(&tcpedit->cidrmap2, value)) { tcpedit_seterr(tcpedit, "Unable to parse: %s", value); return TCPEDIT_ERROR; } return TCPEDIT_OK; }
/* * Initializer function. This function is called only once, if and only if * this plugin will be utilized. Remember, if you need to keep track of any state, * store it in your plugin->config, not a global! * Returns: TCPEDIT_ERROR | TCPEDIT_OK | TCPEDIT_WARN */ int dlt_loop_init(tcpeditdlt_t *ctx) { tcpeditdlt_plugin_t *plugin; assert(ctx); if ((plugin = tcpedit_dlt_getplugin(ctx, dlt_value)) == NULL) { tcpedit_seterr(ctx->tcpedit, "Unable to initalize unregistered plugin %s", dlt_name); return TCPEDIT_ERROR; } return TCPEDIT_OK; /* success */ }
/** * initialize our plugin library. Pass the DLT of the source pcap handle. * Actions: * - Create new tcpeditdlt_t context * - Link tcpedit to new context * - Register plugins * - Select decoder plugin using srcdlt * - Select encoder plugin using destination name * - Initialize decoder/encoder plugins * - Parse options for encoder plugin * - Validate provides/reqiures + user options */ tcpeditdlt_t * tcpedit_dlt_init(tcpedit_t *tcpedit, const int srcdlt) { tcpeditdlt_t *ctx; int rcode; assert(tcpedit); assert(srcdlt >= 0); ctx = (tcpeditdlt_t *)safe_malloc(sizeof(tcpeditdlt_t)); /* do we need a side buffer for L3 data? */ #ifdef FORCE_ALIGN ctx->l3buff = (u_char *)safe_malloc(MAXPACKET); #endif /* copy our tcpedit context */ ctx->tcpedit = tcpedit; /* register all our plugins */ if (tcpedit_dlt_register(ctx) != TCPEDIT_OK) { tcpedit_dlt_cleanup(ctx); return NULL; } /* Choose decode plugin */ if ((ctx->decoder = tcpedit_dlt_getplugin(ctx, srcdlt)) == NULL) { tcpedit_seterr(tcpedit, "No DLT plugin available for source DLT: 0x%x", srcdlt); tcpedit_dlt_cleanup(ctx); return NULL; } /* set our dlt type */ ctx->dlt = srcdlt; /* set our address type */ ctx->addr_type = ctx->decoder->plugin_l2addr_type(); /* initalize decoder plugin */ rcode = ctx->decoder->plugin_init(ctx); if (tcpedit_checkerror(ctx->tcpedit, rcode, NULL) != TCPEDIT_OK) { tcpedit_dlt_cleanup(ctx); return NULL; } /* we're OK */ return ctx; }
/** * Get the layer 2 length of the packet using the DLT plugin currently in * place */ int tcpedit_dlt_l2len(tcpeditdlt_t *ctx, int dlt, const u_char *packet, const int pktlen) { tcpeditdlt_plugin_t *plugin; assert(ctx); assert(dlt >= 0); assert(packet); assert(pktlen); if ((plugin = tcpedit_dlt_getplugin(ctx, dlt)) == NULL) { tcpedit_seterr(ctx->tcpedit, "Unable to find plugin for DLT 0x%04x", dlt); return -1; } return plugin->plugin_l2len(ctx, packet, pktlen); }
/** * takes in a libpcap DLT_ type and returns the length of the layer2 header * returns -1 for unsupported DLT */ int dlt2layer2len(tcpedit_t *tcpedit, int dlt) { assert(tcpedit); int len; switch(dlt) { /* case DLT_USER: len = tcpedit->l2.len; break; */ case DLT_NULL: len = 2; break; case DLT_RAW: len = 0; break; case DLT_EN10MB: len = 12; break; /* case DLT_VLAN: len = 14; break; */ case DLT_LINUX_SLL: len = 16; break; case DLT_PPP_SERIAL: case DLT_C_HDLC: len = 4; break; case DLT_JUNIPER_ETHER: len = 36; break; default: tcpedit_seterr(tcpedit, "Invalid DLT Type: %d", dlt); len = -1; } return len; }
/* * This is where you should define all your AutoGen AutoOpts option parsing. * Any user specified option should have it's bit turned on in the 'provides' * bit mask. * Returns: TCPEDIT_ERROR | TCPEDIT_OK | TCPEDIT_WARN */ int dlt_user_parse_opts(tcpeditdlt_t *ctx) { tcpeditdlt_plugin_t *plugin; user_config_t *config; assert(ctx); plugin = tcpedit_dlt_getplugin(ctx, dlt_value); config = plugin->config; /* * --user-dlt will override the output DLT type, otherwise we'll use * the DLT of the decoder */ if (HAVE_OPT(USER_DLT)) { config->dlt = OPT_VALUE_USER_DLT; } else { config->dlt = ctx->decoder->dlt; } /* --user-dlink */ if (HAVE_OPT(USER_DLINK)) { int ct = STACKCT_OPT(USER_DLINK); char **list = STACKLST_OPT(USER_DLINK); int first = 1; do { char *p = *list++; if (first) { config->length = read_hexstring(p, config->l2server, USER_L2MAXLEN); memcpy(config->l2client, config->l2server, config->length); } else { if (config->length != read_hexstring(p, config->l2client, USER_L2MAXLEN)) { tcpedit_seterr(ctx->tcpedit, "%s", "both --dlink's must contain the same number of bytes"); return TCPEDIT_ERROR; } } first = 0; } while (--ct > 0); } return TCPEDIT_OK; /* success */ }
/** * \brief Merge the Layer 3 data back onto the mainbuffer so it's immediately * after the layer 2 header * * Since some L2 headers aren't strictly aligned, we need to "merge" the packet w/ L2 data * and the L3 buffer. This is basically a NO-OP for things like vlan tagged ethernet (16 byte) header * or Cisco HDLC (4 byte header) but is critical for std ethernet (12 byte header) */ u_char * tcpedit_dlt_merge_l3data(tcpeditdlt_t *ctx, int dlt, u_char *packet, const int pktlen, u_char *l3data) { tcpeditdlt_plugin_t *plugin; assert(ctx); assert(dlt >= 0); assert(pktlen >= 0); assert(packet); if (l3data == NULL) return packet; if ((plugin = tcpedit_dlt_getplugin(ctx, dlt)) == NULL) { tcpedit_seterr(ctx->tcpedit, "Unable to find plugin for DLT 0x%04x", dlt); return NULL; } return plugin->plugin_merge_layer3(ctx, packet, pktlen, l3data); }
/* * Function returns the Layer 3 protocol type of the given packet, or TCPEDIT_ERROR on error */ int dlt_null_proto(tcpeditdlt_t *ctx, const u_char *packet, const int pktlen) { assert(ctx); assert(packet); assert(pktlen > 0); uint32_t *af_type; int protocol = 0; af_type = (uint32_t *)packet; if (*af_type == PF_INET || SWAPLONG(*af_type) == PF_INET) { protocol = ETHERTYPE_IP; } else if (*af_type == PF_INET6 || SWAPLONG(*af_type) == PF_INET6) { protocol = ETHERTYPE_IP6; } else { tcpedit_seterr(ctx->tcpedit, "Unsupported DLT_NULL/DLT_LOOP PF_ type: 0x%04x", *af_type); return TCPEDIT_ERROR; } return htons(protocol); }
/* * Function returns a pointer to the layer 3 protocol header or NULL on error */ u_char * dlt_jnpr_ether_get_layer3(tcpeditdlt_t *ctx, u_char *packet, const int pktlen) { int l2len; assert(ctx); assert(packet); /* next make sure the L2 header is present */ if ((packet[JUNIPER_ETHER_OPTIONS_OFFSET] & JUNIPER_ETHER_L2PRESENT) != JUNIPER_ETHER_L2PRESENT) { tcpedit_seterr(ctx->tcpedit, "Frame is missing L2 Header: %x", packet[JUNIPER_ETHER_OPTIONS_OFFSET]); return NULL; } l2len = dlt_jnpr_ether_l2len(ctx, packet, pktlen); assert(pktlen >= l2len); return tcpedit_dlt_l3data_copy(ctx, packet, pktlen, l2len); }