en10mb.c 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949
  1. /* $Id$ */
  2. /*
  3. * Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
  4. * Copyright (c) 2013-2026 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  5. *
  6. * The Tcpreplay Suite of tools is free software: you can redistribute it
  7. * and/or modify it under the terms of the GNU General Public License as
  8. * published by the Free Software Foundation, either version 3 of the
  9. * License, or with the authors permission any later version.
  10. *
  11. * The Tcpreplay Suite is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with the Tcpreplay Suite. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "en10mb.h"
  20. #include "../ethernet.h"
  21. #include "dlt_utils.h"
  22. #include "tcpedit.h"
  23. #include "tcpedit_stub.h"
  24. #include <stdlib.h>
  25. #include <string.h>
  26. static char dlt_name[] = "en10mb";
  27. static char dlt_prefix[] = "enet";
  28. static uint16_t dlt_value = DLT_EN10MB;
  29. /*
  30. * Function to register ourselves. This function is always called, regardless
  31. * of what DLT types are being used, so it shouldn't be allocating extra buffers
  32. * or anything like that (use the dlt_en10mb_init() function below for that).
  33. * Tasks:
  34. * - Create a new plugin struct
  35. * - Fill out the provides/requires bit masks. Note: Only specify which fields are
  36. * actually in the header.
  37. * - Add the plugin to the context's plugin chain
  38. * Returns: TCPEDIT_ERROR | TCPEDIT_OK | TCPEDIT_WARN
  39. */
  40. int
  41. dlt_en10mb_register(tcpeditdlt_t *ctx)
  42. {
  43. tcpeditdlt_plugin_t *plugin;
  44. assert(ctx);
  45. /* create a new plugin structure */
  46. plugin = tcpedit_dlt_newplugin();
  47. /* set what we provide & require */
  48. plugin->provides += PLUGIN_MASK_PROTO + PLUGIN_MASK_SRCADDR + PLUGIN_MASK_DSTADDR;
  49. plugin->requires += PLUGIN_MASK_PROTO + PLUGIN_MASK_SRCADDR + PLUGIN_MASK_DSTADDR;
  50. /* what is our dlt type? */
  51. plugin->dlt = dlt_value;
  52. /* set the prefix name of our plugin. This is also used as the prefix for our options */
  53. plugin->name = safe_strdup(dlt_prefix);
  54. /*
  55. * Point to our functions, note, you need a function for EVERY method.
  56. * Even if it is only an empty stub returning success.
  57. */
  58. plugin->plugin_init = dlt_en10mb_init;
  59. plugin->plugin_cleanup = dlt_en10mb_cleanup;
  60. plugin->plugin_parse_opts = dlt_en10mb_parse_opts;
  61. plugin->plugin_decode = dlt_en10mb_decode;
  62. plugin->plugin_encode = dlt_en10mb_encode;
  63. plugin->plugin_proto = dlt_en10mb_proto;
  64. plugin->plugin_l2addr_type = dlt_en10mb_l2addr_type;
  65. plugin->plugin_l2len = dlt_en10mb_l2len;
  66. plugin->plugin_get_layer3 = dlt_en10mb_get_layer3;
  67. plugin->plugin_merge_layer3 = dlt_en10mb_merge_layer3;
  68. plugin->plugin_get_mac = dlt_en10mb_get_mac;
  69. /* add it to the available plugin list */
  70. return tcpedit_dlt_addplugin(ctx, plugin);
  71. }
  72. /*
  73. * Initializer function. This function is called only once, if and only if
  74. * this plugin will be utilized. Remember, if you need to keep track of any state,
  75. * store it in your plugin->config, not a global!
  76. * Returns: TCPEDIT_ERROR | TCPEDIT_OK | TCPEDIT_WARN
  77. */
  78. int
  79. dlt_en10mb_init(tcpeditdlt_t *ctx)
  80. {
  81. tcpeditdlt_plugin_t *plugin;
  82. en10mb_config_t *config;
  83. assert(ctx);
  84. /* vlan tags need an additional 4 bytes */
  85. if ((plugin = tcpedit_dlt_getplugin(ctx, dlt_value)) == NULL) {
  86. tcpedit_seterr(ctx->tcpedit, "%s", "Unable to initialize unregistered plugin en10mb");
  87. return TCPEDIT_ERROR;
  88. }
  89. if (ctx->decoded_extra_size > 0) {
  90. if (ctx->decoded_extra_size < sizeof(en10mb_extra_t)) {
  91. ctx->decoded_extra_size = sizeof(en10mb_extra_t);
  92. ctx->decoded_extra = safe_realloc(ctx->decoded_extra, ctx->decoded_extra_size);
  93. }
  94. } else {
  95. ctx->decoded_extra_size = sizeof(en10mb_extra_t);
  96. ctx->decoded_extra = safe_malloc(ctx->decoded_extra_size);
  97. }
  98. plugin->config_size = sizeof(en10mb_config_t);
  99. plugin->config = safe_malloc(plugin->config_size);
  100. config = (en10mb_config_t *)plugin->config;
  101. /* init vlan user values to -1 to indicate not set */
  102. config->vlan_tag = 65535;
  103. config->vlan_pri = 255;
  104. config->vlan_cfi = 255;
  105. /* VLAN protocol = 802.1q */
  106. config->vlan_proto = ETHERTYPE_VLAN;
  107. return TCPEDIT_OK; /* success */
  108. }
  109. /*
  110. * Since this is used in a library, we should manually clean up after ourselves
  111. * Unless you allocated some memory in dlt_en10mb_init(), this is just an stub.
  112. * Returns: TCPEDIT_ERROR | TCPEDIT_OK | TCPEDIT_WARN
  113. */
  114. int
  115. dlt_en10mb_cleanup(tcpeditdlt_t *ctx)
  116. {
  117. tcpeditdlt_plugin_t *plugin;
  118. assert(ctx);
  119. if ((plugin = tcpedit_dlt_getplugin(ctx, dlt_value)) == NULL) {
  120. tcpedit_seterr(ctx->tcpedit, "Unable to cleanup unregistered plugin %s", dlt_name);
  121. return TCPEDIT_ERROR;
  122. }
  123. safe_free(plugin->name);
  124. plugin->name = NULL;
  125. if (plugin->config != NULL) {
  126. en10mb_config_t *config = (en10mb_config_t *)plugin->config;
  127. safe_free(config->subs.entries);
  128. safe_free(plugin->config);
  129. plugin->config = NULL;
  130. plugin->config_size = 0;
  131. }
  132. return TCPEDIT_OK; /* success */
  133. }
  134. int
  135. dlt_en10mb_parse_subsmac_entry(const char *raw, en10mb_sub_entry_t *entry)
  136. {
  137. char *candidate = safe_strdup(raw);
  138. int parse_result = dualmac2hex(candidate, entry->target, entry->rewrite, SUBSMAC_ENTRY_LEN);
  139. free(candidate);
  140. return parse_result;
  141. }
  142. en10mb_sub_entry_t *
  143. dlt_en10mb_realloc_merge(en10mb_sub_conf_t config, en10mb_sub_entry_t *new_entries, int entries_count)
  144. {
  145. int i;
  146. config.entries = safe_realloc(config.entries, (config.count + entries_count) * sizeof(en10mb_sub_entry_t));
  147. for (i = 0; i < entries_count; i++) {
  148. config.entries[config.count + i] = new_entries[i];
  149. }
  150. return config.entries;
  151. }
  152. int
  153. dlt_en10mb_parse_subsmac(tcpeditdlt_t *ctx, en10mb_config_t *config, const char *input)
  154. {
  155. size_t input_len = strlen(input);
  156. size_t possible_entries_number = (input_len / (SUBSMAC_ENTRY_LEN + 1)) + 1;
  157. size_t entry;
  158. en10mb_sub_entry_t *entries = safe_malloc(possible_entries_number * sizeof(en10mb_sub_entry_t));
  159. for (entry = 0; entry < possible_entries_number; entry++) {
  160. const size_t read_offset = entry + entry * SUBSMAC_ENTRY_LEN;
  161. if (input_len - read_offset < SUBSMAC_ENTRY_LEN) {
  162. free(entries);
  163. tcpedit_seterr(ctx->tcpedit, "Unable to parse --enet-subsmac=%s", input);
  164. return TCPEDIT_ERROR;
  165. }
  166. switch (dlt_en10mb_parse_subsmac_entry(input + read_offset, &entries[entry])) {
  167. case 3:
  168. /* Both read; This is what we want */
  169. break;
  170. default:
  171. free(entries);
  172. tcpedit_seterr(ctx->tcpedit, "Unable to parse --enet-subsmac=%s", input);
  173. return TCPEDIT_ERROR;
  174. }
  175. }
  176. config->subs.entries = dlt_en10mb_realloc_merge(config->subs, entries, (int)possible_entries_number);
  177. config->subs.count += (int)possible_entries_number;
  178. free(entries);
  179. return TCPEDIT_OK;
  180. }
  181. /*
  182. * This is where you should define all your AutoGen AutoOpts option parsing.
  183. * Any user specified option should have it's bit turned on in the 'provides'
  184. * bit mask.
  185. * Returns: TCPEDIT_ERROR | TCPEDIT_OK | TCPEDIT_WARN
  186. */
  187. int
  188. dlt_en10mb_parse_opts(tcpeditdlt_t *ctx)
  189. {
  190. tcpeditdlt_plugin_t *plugin;
  191. en10mb_config_t *config;
  192. assert(ctx);
  193. plugin = tcpedit_dlt_getplugin(ctx, dlt_value);
  194. if (!plugin)
  195. return TCPEDIT_ERROR;
  196. config = (en10mb_config_t *)plugin->config;
  197. if (plugin->config_size < sizeof(*config))
  198. return TCPEDIT_ERROR;
  199. /* --subsmacs */
  200. if (HAVE_OPT(ENET_SUBSMAC)) {
  201. int i, count = STACKCT_OPT(ENET_SUBSMAC);
  202. char **list = (char **)STACKLST_OPT(ENET_SUBSMAC);
  203. for (i = 0; i < count; i++) {
  204. int parse_result = dlt_en10mb_parse_subsmac(ctx, config, list[i]);
  205. if (parse_result == TCPEDIT_ERROR) {
  206. return TCPEDIT_ERROR;
  207. }
  208. }
  209. }
  210. /* --mac-seed */
  211. if (HAVE_OPT(ENET_MAC_SEED)) {
  212. int i, j;
  213. config->random.set = OPT_VALUE_ENET_MAC_SEED;
  214. for (i = 0; i < 6; i++) {
  215. config->random.mask[i] = (u_char)tcpr_random(&config->random.set) % 256;
  216. /* only unique numbers */
  217. for (j = 0; j < i; j++) {
  218. if (config->random.mask[i] == config->random.mask[j]) {
  219. i--;
  220. break;
  221. }
  222. }
  223. }
  224. if (HAVE_OPT(ENET_MAC_SEED_KEEP_BYTES)) {
  225. config->random.keep = OPT_VALUE_ENET_MAC_SEED_KEEP_BYTES;
  226. }
  227. }
  228. /* --dmac */
  229. if (HAVE_OPT(ENET_DMAC)) {
  230. int macparse;
  231. macparse = dualmac2hex(OPT_ARG(ENET_DMAC),
  232. config->intf1_dmac,
  233. config->intf2_dmac,
  234. (int)strlen(OPT_ARG(ENET_DMAC)));
  235. switch (macparse) {
  236. case 1:
  237. config->mac_mask += TCPEDIT_MAC_MASK_DMAC1;
  238. break;
  239. case 2:
  240. config->mac_mask += TCPEDIT_MAC_MASK_DMAC2;
  241. break;
  242. case 3:
  243. config->mac_mask += TCPEDIT_MAC_MASK_DMAC1;
  244. config->mac_mask += TCPEDIT_MAC_MASK_DMAC2;
  245. break;
  246. case 0:
  247. /* nothing to do */
  248. break;
  249. default:
  250. tcpedit_seterr(ctx->tcpedit, "Unable to parse --enet-dmac=%s", OPT_ARG(ENET_DMAC));
  251. return TCPEDIT_ERROR;
  252. }
  253. plugin->requires -= PLUGIN_MASK_DSTADDR;
  254. }
  255. /* --smac */
  256. if (HAVE_OPT(ENET_SMAC)) {
  257. int macparse;
  258. macparse = dualmac2hex(OPT_ARG(ENET_SMAC),
  259. config->intf1_smac,
  260. config->intf2_smac,
  261. (int)strlen(OPT_ARG(ENET_SMAC)));
  262. switch (macparse) {
  263. case 1:
  264. config->mac_mask += TCPEDIT_MAC_MASK_SMAC1;
  265. break;
  266. case 2:
  267. config->mac_mask += TCPEDIT_MAC_MASK_SMAC2;
  268. break;
  269. case 3:
  270. config->mac_mask += TCPEDIT_MAC_MASK_SMAC1;
  271. config->mac_mask += TCPEDIT_MAC_MASK_SMAC2;
  272. break;
  273. case 0:
  274. /* nothing to do */
  275. break;
  276. default:
  277. tcpedit_seterr(ctx->tcpedit, "Unable to parse --enet-smac=%s", OPT_ARG(ENET_SMAC));
  278. return TCPEDIT_ERROR;
  279. }
  280. plugin->requires -= PLUGIN_MASK_SRCADDR;
  281. }
  282. /*
  283. * Validate 802.1q vlan args and populate tcpedit->vlan_record
  284. */
  285. if (HAVE_OPT(ENET_VLAN)) {
  286. if (strcmp(OPT_ARG(ENET_VLAN), "add") == 0) { /* add or change */
  287. config->vlan = TCPEDIT_VLAN_ADD;
  288. } else if (strcmp(OPT_ARG(ENET_VLAN), "del") == 0) {
  289. config->vlan = TCPEDIT_VLAN_DEL;
  290. } else {
  291. tcpedit_seterr(ctx->tcpedit, "Invalid --enet-vlan=%s", OPT_ARG(ENET_VLAN));
  292. return -1;
  293. }
  294. if (config->vlan != TCPEDIT_VLAN_OFF) {
  295. if (config->vlan == TCPEDIT_VLAN_ADD) {
  296. if (!HAVE_OPT(ENET_VLAN_TAG)) {
  297. tcpedit_seterr(ctx->tcpedit,
  298. "%s",
  299. "Must specify a new 802.1 VLAN tag if vlan "
  300. "mode is add");
  301. return TCPEDIT_ERROR;
  302. }
  303. /*
  304. * fill out the 802.1q header
  305. */
  306. config->vlan_tag = OPT_VALUE_ENET_VLAN_TAG;
  307. dbgx(1, "We will %s 802.1q headers", config->vlan == TCPEDIT_VLAN_DEL ? "delete" : "add/modify");
  308. if (HAVE_OPT(ENET_VLAN_PRI))
  309. config->vlan_pri = OPT_VALUE_ENET_VLAN_PRI;
  310. if (HAVE_OPT(ENET_VLAN_CFI))
  311. config->vlan_cfi = OPT_VALUE_ENET_VLAN_CFI;
  312. /*
  313. * Warn once if priority and/or CFI were not supplied: for
  314. * packets that are not already VLAN tagged there is no
  315. * existing value to preserve, so they default to 0.
  316. */
  317. if (!HAVE_OPT(ENET_VLAN_PRI) || !HAVE_OPT(ENET_VLAN_CFI)) {
  318. notice("%s%s%s not specified; previously untagged "
  319. "packets will be tagged with priority 0 and/or CFI 0.",
  320. HAVE_OPT(ENET_VLAN_PRI) ? "" : "--enet-vlan-pri",
  321. (!HAVE_OPT(ENET_VLAN_PRI) && !HAVE_OPT(ENET_VLAN_CFI)) ? " and " : "",
  322. HAVE_OPT(ENET_VLAN_CFI) ? "" : "--enet-vlan-cfi");
  323. }
  324. }
  325. if (HAVE_OPT(ENET_VLAN_PROTO)) {
  326. if (strcasecmp(OPT_ARG(ENET_VLAN_PROTO), "802.1q") == 0) {
  327. config->vlan_proto = ETHERTYPE_VLAN;
  328. } else if (strcasecmp(OPT_ARG(ENET_VLAN_PROTO), "802.1ad") == 0) {
  329. config->vlan_proto = ETHERTYPE_Q_IN_Q;
  330. } else {
  331. tcpedit_seterr(ctx->tcpedit, "VLAN protocol \"%s\" is invalid", OPT_ARG(ENET_VLAN_PROTO));
  332. return TCPEDIT_ERROR;
  333. }
  334. }
  335. }
  336. }
  337. return TCPEDIT_OK; /* success */
  338. }
  339. /*
  340. * Function to decode the layer 2 header in the packet
  341. * Returns: TCPEDIT_ERROR | TCPEDIT_OK | TCPEDIT_WARN
  342. */
  343. int
  344. dlt_en10mb_decode(tcpeditdlt_t *ctx, const u_char *packet, int pktlen)
  345. {
  346. struct tcpr_ethernet_hdr *eth_hdr;
  347. uint32_t pkt_len = pktlen;
  348. en10mb_extra_t *extra;
  349. uint32_t vlan_offset;
  350. uint16_t protcol;
  351. uint32_t l2offset;
  352. uint32_t l2len;
  353. int res;
  354. assert(ctx);
  355. assert(packet);
  356. extra = (en10mb_extra_t *)ctx->decoded_extra;
  357. if (ctx->decoded_extra_size < sizeof(*extra)) {
  358. tcpedit_seterr(ctx->tcpedit, "Decode extra size too short! %d < %u", ctx->decoded_extra_size, sizeof(*extra));
  359. return TCPEDIT_ERROR;
  360. }
  361. res = get_l2len_protocol(packet, pkt_len, dlt_value, &protcol, &l2len, &l2offset, &vlan_offset);
  362. if (res == -1)
  363. return TCPEDIT_ERROR;
  364. if (pkt_len < TCPR_802_3_H + l2offset)
  365. return TCPEDIT_ERROR;
  366. eth_hdr = (struct tcpr_ethernet_hdr *)(packet + l2offset);
  367. protcol = ntohs(eth_hdr->ether_type);
  368. memcpy(&(ctx->dstaddr.ethernet), eth_hdr, ETHER_ADDR_LEN);
  369. memcpy(&(ctx->srcaddr.ethernet), &(eth_hdr->ether_shost), ETHER_ADDR_LEN);
  370. ctx->proto_vlan_tag = ntohs(eth_hdr->ether_type);
  371. if (vlan_offset != 0) {
  372. if (vlan_offset == l2offset + sizeof(*eth_hdr)) {
  373. vlan_hdr_t *vlan_hdr;
  374. vlan_hdr = (vlan_hdr_t *)(packet + vlan_offset);
  375. if (pkt_len < vlan_offset + sizeof(*vlan_hdr)) {
  376. tcpedit_seterr(ctx->tcpedit,
  377. "Frame is too short for VLAN headers! %d < %d",
  378. pktlen,
  379. vlan_offset + sizeof(*vlan_hdr));
  380. return TCPEDIT_ERROR;
  381. }
  382. extra->vlan = 1;
  383. extra->vlan_offset = vlan_offset;
  384. extra->vlan_proto = ntohs(vlan_hdr->vlan_tpid);
  385. extra->vlan_tag = htons(vlan_hdr->vlan_tci) & TCPR_802_1Q_VIDMASK;
  386. extra->vlan_pri = htons(vlan_hdr->vlan_tci) & TCPR_802_1Q_PRIMASK;
  387. extra->vlan_cfi = htons(vlan_hdr->vlan_tci) & TCPR_802_1Q_CFIMASK;
  388. } else {
  389. /* VLAN headers cannot be after MPLS. There are other protocols such
  390. * Cisco Metatdata that could be before VLAN, but we don't support
  391. * them yet.
  392. */
  393. return TCPEDIT_ERROR;
  394. }
  395. } else {
  396. extra->vlan = 0;
  397. extra->vlan_offset = l2offset + sizeof(*eth_hdr);
  398. extra->vlan_proto = protcol;
  399. }
  400. ctx->proto = ntohs(protcol);
  401. ctx->l2offset = (int)l2offset;
  402. ctx->l2len = (int)l2len;
  403. return TCPEDIT_OK; /* success */
  404. }
  405. /*
  406. * Function to encode the layer 2 header back into the packet.
  407. * Returns: TCPEDIT_ERROR | TCPEDIT_OK | TCPEDIT_WARN
  408. */
  409. int
  410. dlt_en10mb_encode(tcpeditdlt_t *ctx, u_char *packet, int pktlen, tcpr_dir_t dir)
  411. {
  412. struct tcpr_802_1q_hdr *vlan_hdr;
  413. struct tcpr_ethernet_hdr *eth;
  414. tcpeditdlt_plugin_t *plugin;
  415. en10mb_config_t *config;
  416. en10mb_extra_t *extra;
  417. uint32_t newl2len = 0;
  418. uint32_t oldl2len = 0;
  419. assert(ctx);
  420. assert(packet);
  421. if (pktlen < TCPR_802_3_H) {
  422. tcpedit_seterr(ctx->tcpedit,
  423. "Unable to process packet #" COUNTER_SPEC " since it is less then 14 bytes.",
  424. ctx->tcpedit->runtime.packetnum);
  425. return TCPEDIT_ERROR;
  426. }
  427. plugin = tcpedit_dlt_getplugin(ctx, dlt_value);
  428. if (!plugin)
  429. return TCPEDIT_ERROR;
  430. config = plugin->config;
  431. if (plugin->config_size < sizeof(*config))
  432. return TCPEDIT_ERROR;
  433. extra = (en10mb_extra_t *)ctx->decoded_extra;
  434. if (ctx->decoded_extra_size < sizeof(*extra))
  435. return TCPEDIT_ERROR;
  436. /*
  437. * Validate VLAN options *before* mutating the packet buffer below.
  438. * A previously untagged packet has no existing VLAN info to fall
  439. * back on, so a tag must be supplied by the user in that case
  440. * (priority and CFI default to 0).
  441. */
  442. if (config->vlan == TCPEDIT_VLAN_ADD && !extra->vlan && config->vlan_tag == 65535) {
  443. tcpedit_seterr(ctx->tcpedit, "%s", "Non-VLAN tagged packet requires --enet-vlan-tag");
  444. return TCPEDIT_ERROR;
  445. }
  446. /* figure out the new layer2 length, first for the case: ethernet -> ethernet? */
  447. if (ctx->decoder->dlt == dlt_value) {
  448. switch (config->vlan) {
  449. case TCPEDIT_VLAN_ADD:
  450. oldl2len = extra->vlan_offset;
  451. newl2len = extra->vlan_offset + sizeof(vlan_hdr_t);
  452. break;
  453. case TCPEDIT_VLAN_DEL:
  454. if (extra->vlan) {
  455. oldl2len = extra->vlan_offset + sizeof(vlan_hdr_t);
  456. newl2len = extra->vlan_offset;
  457. }
  458. break;
  459. case TCPEDIT_VLAN_OFF:
  460. if (extra->vlan) {
  461. oldl2len = extra->vlan_offset;
  462. newl2len = extra->vlan_offset;
  463. }
  464. break;
  465. }
  466. }
  467. /* newl2len for some other DLT -> ethernet */
  468. else {
  469. newl2len = config->vlan == TCPEDIT_VLAN_ADD ? TCPR_802_1Q_H : TCPR_802_3_H;
  470. oldl2len = ctx->l2len;
  471. }
  472. if ((uint32_t)pktlen < newl2len || pktlen + newl2len - ctx->l2len > MAXPACKET) {
  473. tcpedit_seterr(ctx->tcpedit,
  474. "Unable to process packet #" COUNTER_SPEC " since its new length is %d bytes.",
  475. ctx->tcpedit->runtime.packetnum,
  476. newl2len);
  477. return TCPEDIT_ERROR;
  478. }
  479. if (pktlen < ctx->l2len) {
  480. tcpedit_seterr(ctx->tcpedit,
  481. "Unable to process packet #" COUNTER_SPEC " since its new length less then %d L2 bytes.",
  482. ctx->tcpedit->runtime.packetnum,
  483. ctx->l2len);
  484. return TCPEDIT_ERROR;
  485. }
  486. /* Make space for our new L2 header */
  487. if (newl2len > 0 && newl2len != oldl2len) {
  488. if (pktlen + (newl2len - oldl2len) > MAXPACKET) {
  489. tcpedit_seterr(ctx->tcpedit,
  490. "New frame too big, new length %d exceeds %d",
  491. pktlen + (newl2len - ctx->l2len),
  492. MAXPACKET);
  493. return TCPEDIT_ERROR;
  494. }
  495. memmove(packet + newl2len, packet + oldl2len, pktlen - oldl2len);
  496. }
  497. /* update the total packet length */
  498. pktlen += (int)(newl2len - oldl2len);
  499. /* set the src & dst address as the first 12 bytes */
  500. eth = (struct tcpr_ethernet_hdr *)(packet + ctx->l2offset);
  501. if (dir == TCPR_DIR_C2S) {
  502. /* copy user supplied SRC MAC if provided or from original packet */
  503. if (config->mac_mask & TCPEDIT_MAC_MASK_SMAC1) {
  504. if ((ctx->addr_type == ETHERNET &&
  505. ((ctx->skip_broadcast && is_unicast_ethernet(ctx, ctx->srcaddr.ethernet)) || !ctx->skip_broadcast)) ||
  506. ctx->addr_type != ETHERNET) {
  507. memcpy(eth->ether_shost, config->intf1_smac, ETHER_ADDR_LEN);
  508. } else {
  509. memcpy(eth->ether_shost, ctx->srcaddr.ethernet, ETHER_ADDR_LEN);
  510. }
  511. } else if (ctx->addr_type == ETHERNET) {
  512. extra->src_modified = memcmp(eth->ether_shost, ctx->srcaddr.ethernet, ETHER_ADDR_LEN);
  513. memcpy(eth->ether_shost, ctx->srcaddr.ethernet, ETHER_ADDR_LEN);
  514. } else {
  515. tcpedit_seterr(ctx->tcpedit, "%s", "Please provide a source address");
  516. return TCPEDIT_ERROR;
  517. }
  518. /* copy user supplied DMAC MAC if provided or from original packet */
  519. if (config->mac_mask & TCPEDIT_MAC_MASK_DMAC1) {
  520. if ((ctx->addr_type == ETHERNET &&
  521. ((ctx->skip_broadcast && is_unicast_ethernet(ctx, ctx->dstaddr.ethernet)) || !ctx->skip_broadcast)) ||
  522. ctx->addr_type != ETHERNET) {
  523. memcpy(eth->ether_dhost, config->intf1_dmac, ETHER_ADDR_LEN);
  524. } else {
  525. memcpy(eth->ether_dhost, ctx->dstaddr.ethernet, ETHER_ADDR_LEN);
  526. }
  527. } else if (ctx->addr_type == ETHERNET) {
  528. extra->dst_modified = memcmp(eth->ether_dhost, ctx->dstaddr.ethernet, ETHER_ADDR_LEN);
  529. memcpy(eth->ether_dhost, ctx->dstaddr.ethernet, ETHER_ADDR_LEN);
  530. } else {
  531. tcpedit_seterr(ctx->tcpedit, "%s", "Please provide a destination address");
  532. return TCPEDIT_ERROR;
  533. }
  534. } else if (dir == TCPR_DIR_S2C) {
  535. /* copy user supplied SRC MAC if provided or from original packet */
  536. if (config->mac_mask & TCPEDIT_MAC_MASK_SMAC2) {
  537. if ((ctx->addr_type == ETHERNET &&
  538. ((ctx->skip_broadcast && is_unicast_ethernet(ctx, ctx->srcaddr.ethernet)) || !ctx->skip_broadcast)) ||
  539. ctx->addr_type != ETHERNET) {
  540. memcpy(eth->ether_shost, config->intf2_smac, ETHER_ADDR_LEN);
  541. } else {
  542. memcpy(eth->ether_shost, ctx->srcaddr.ethernet, ETHER_ADDR_LEN);
  543. }
  544. } else if (ctx->addr_type == ETHERNET) {
  545. memcpy(eth->ether_shost, ctx->srcaddr.ethernet, ETHER_ADDR_LEN);
  546. } else {
  547. tcpedit_seterr(ctx->tcpedit, "%s", "Please provide a source address");
  548. return TCPEDIT_ERROR;
  549. }
  550. /* copy user supplied DMAC MAC if provided or from original packet */
  551. if (config->mac_mask & TCPEDIT_MAC_MASK_DMAC2) {
  552. if ((ctx->addr_type == ETHERNET &&
  553. ((ctx->skip_broadcast && is_unicast_ethernet(ctx, ctx->dstaddr.ethernet)) || !ctx->skip_broadcast)) ||
  554. ctx->addr_type != ETHERNET) {
  555. memcpy(eth->ether_dhost, config->intf2_dmac, ETHER_ADDR_LEN);
  556. } else {
  557. memcpy(eth->ether_dhost, ctx->dstaddr.ethernet, ETHER_ADDR_LEN);
  558. }
  559. } else if (ctx->addr_type == ETHERNET) {
  560. memcpy(eth->ether_dhost, ctx->dstaddr.ethernet, ETHER_ADDR_LEN);
  561. } else {
  562. tcpedit_seterr(ctx->tcpedit, "%s", "Please provide a destination address");
  563. return TCPEDIT_ERROR;
  564. }
  565. } else {
  566. tcpedit_seterr(ctx->tcpedit, "%s", "Encoders only support C2S or C2S!");
  567. return TCPEDIT_ERROR;
  568. }
  569. if (config->subs.entries) {
  570. int entry = 0;
  571. for (entry = 0; entry < config->subs.count; entry++) {
  572. en10mb_sub_entry_t *current = &config->subs.entries[entry];
  573. if (!memcmp(eth->ether_dhost, current->target, ETHER_ADDR_LEN)) {
  574. memcpy(eth->ether_dhost, current->rewrite, ETHER_ADDR_LEN);
  575. }
  576. if (!memcmp(eth->ether_shost, current->target, ETHER_ADDR_LEN)) {
  577. memcpy(eth->ether_shost, current->rewrite, ETHER_ADDR_LEN);
  578. }
  579. }
  580. }
  581. if (config->random.set) {
  582. int unicast_src = is_unicast_ethernet(ctx, eth->ether_shost);
  583. int unicast_dst = is_unicast_ethernet(ctx, eth->ether_dhost);
  584. int i = config->random.keep;
  585. for (; i < ETHER_ADDR_LEN; i++) {
  586. eth->ether_shost[i] = MAC_MASK_APPLY(eth->ether_shost[i], config->random.mask[i], unicast_src);
  587. eth->ether_dhost[i] = MAC_MASK_APPLY(eth->ether_dhost[i], config->random.mask[i], unicast_dst);
  588. }
  589. /* avoid making unicast packets multicast */
  590. if (!config->random.keep) {
  591. eth->ether_shost[0] &= ~(0x01 * unicast_src);
  592. eth->ether_dhost[0] &= ~(0x01 * unicast_dst);
  593. }
  594. }
  595. if (newl2len == TCPR_802_3_H) {
  596. /* all we need for 802.3 is the proto */
  597. eth->ether_type = ctx->proto;
  598. }
  599. if (config->vlan == TCPEDIT_VLAN_ADD || (config->vlan == TCPEDIT_VLAN_OFF && extra->vlan)) {
  600. vlan_hdr = (struct tcpr_802_1q_hdr *)(packet + extra->vlan_offset);
  601. if (config->vlan == TCPEDIT_VLAN_ADD) {
  602. struct tcpr_ethernet_hdr *eth_hdr;
  603. eth_hdr = (struct tcpr_ethernet_hdr *)(packet + ctx->l2offset);
  604. eth_hdr->ether_type = htons(config->vlan_proto);
  605. vlan_hdr->vlan_tpid = htons(ctx->proto_vlan_tag);
  606. }
  607. /* are we changing VLAN info? */
  608. if (config->vlan_tag < 65535) {
  609. vlan_hdr->vlan_tci = htons((uint16_t)config->vlan_tag & TCPR_802_1Q_VIDMASK);
  610. } else if (extra->vlan) {
  611. vlan_hdr->vlan_tci = htons(extra->vlan_tag);
  612. }
  613. /* else: a previously-untagged packet without a tag is rejected early
  614. * in dlt_en10mb_encode(), before the buffer is mutated */
  615. if (config->vlan_pri < 255) {
  616. vlan_hdr->vlan_tci += htons((uint16_t)config->vlan_pri << 13);
  617. } else if (extra->vlan) {
  618. vlan_hdr->vlan_tci += htons(extra->vlan_pri);
  619. }
  620. /* else: previously-untagged packet, priority defaults to 0
  621. * (warned about once in dlt_en10mb_parse_opts) */
  622. if (config->vlan_cfi < 255) {
  623. vlan_hdr->vlan_tci += htons((uint16_t)config->vlan_cfi << 12);
  624. } else if (extra->vlan) {
  625. vlan_hdr->vlan_tci += htons(extra->vlan_cfi);
  626. }
  627. /* else: previously-untagged packet, CFI defaults to 0
  628. * (warned about once in dlt_en10mb_parse_opts) */
  629. } else if (config->vlan == TCPEDIT_VLAN_DEL && newl2len > 0) {
  630. /* all we need for 802.3 is the proto */
  631. eth->ether_type = htons(extra->vlan_proto);
  632. }
  633. return pktlen;
  634. }
  635. /*
  636. * Function returns the Layer 3 protocol type of the given packet, or TCPEDIT_ERROR on error
  637. */
  638. int
  639. dlt_en10mb_proto(tcpeditdlt_t *ctx, const u_char *packet, int pktlen)
  640. {
  641. uint32_t _U_ vlan_offset;
  642. uint16_t ether_type;
  643. uint32_t _U_ l2offset;
  644. uint32_t _U_ l2len;
  645. int res;
  646. assert(ctx);
  647. assert(packet);
  648. if (pktlen < (int)sizeof(struct tcpr_ethernet_hdr)) {
  649. tcpedit_seterr(ctx->tcpedit, "Ethernet packet length too short: %d", pktlen);
  650. return TCPEDIT_ERROR;
  651. }
  652. res = get_l2len_protocol(packet, pktlen, dlt_value, &ether_type, &l2len, &l2offset, &vlan_offset);
  653. if (res == -1)
  654. return TCPEDIT_ERROR;
  655. return htons(ether_type);
  656. }
  657. /*
  658. * Function returns a pointer to the layer 3 protocol header or NULL on error
  659. */
  660. u_char *
  661. dlt_en10mb_get_layer3(tcpeditdlt_t *ctx, u_char *packet, int pktlen)
  662. {
  663. int l2len;
  664. assert(ctx);
  665. assert(packet);
  666. l2len = dlt_en10mb_l2len(ctx, packet, pktlen);
  667. if (l2len == -1 || pktlen < l2len)
  668. return NULL;
  669. return tcpedit_dlt_l3data_copy(ctx, packet, pktlen, l2len);
  670. }
  671. static bool is_ipv4_multicast_address(const uint32_t ip)
  672. {
  673. /* multicast/broadcast is 224.0.0.0 to 239.255.255.255 */
  674. return (ntohl(ip) & 0xf0000000) == 0xe0000000;
  675. }
  676. static bool is_ipv6_multicast_address(const struct tcpr_in6_addr *ip6)
  677. {
  678. return ip6->tcpr_s6_addr[0] == 0xff;
  679. }
  680. /*
  681. * Modify MAC address if IPv4 address is Multicast (#563)
  682. * ip: 32-bit IP address in network order
  683. * mac: pointer to packet ethernet source or destination address (6 bytes)
  684. */
  685. static void
  686. dlt_en10mb_ipv4_multicast_mac_update(const uint32_t ip, uint8_t mac[], size_t mac_len)
  687. {
  688. uint32_t cpu_ip;
  689. if (mac_len < ETHER_ADDR_LEN)
  690. return;
  691. /* only modify multicast packets */
  692. if (!is_ipv4_multicast_address(ip))
  693. return;
  694. cpu_ip = ntohl(ip);
  695. mac[0] = 0x01;
  696. mac[1] = 0x0;
  697. mac[2] = 0x5e;
  698. mac[3] = (uint8_t)(cpu_ip >> 16) & 0x7f;
  699. mac[4] = (uint8_t)(cpu_ip >> 8) & 0xff;
  700. mac[5] = (uint8_t)(cpu_ip >> 0) & 0xff;
  701. }
  702. /*
  703. * Modify MAC address if IPv4 address is Multicast (#563)
  704. * ip6: 128-bit IPv6 address in network order
  705. * mac: pointer to packet ethernet source or destination address (6 bytes)
  706. */
  707. static void
  708. dlt_en10mb_ipv6_multicast_mac_update(const struct tcpr_in6_addr *ip6, uint8_t mac[], size_t mac_len)
  709. {
  710. if (mac_len < ETHER_ADDR_LEN)
  711. return;
  712. /* only modify multicast packets */
  713. if (!is_ipv6_multicast_address(ip6))
  714. return;
  715. mac[0] = 0x33;
  716. mac[1] = 0x33;
  717. mac[2] = ip6->tcpr_s6_addr[12];
  718. mac[3] = ip6->tcpr_s6_addr[13];
  719. mac[4] = ip6->tcpr_s6_addr[14];
  720. mac[5] = ip6->tcpr_s6_addr[15];
  721. }
  722. /*
  723. * function merges the packet (containing L2 and old L3) with the l3data buffer
  724. * containing the new l3 data. Note, if L2 % 4 == 0, then they're pointing to the
  725. * same buffer, otherwise there was a memcpy involved on strictly aligned architectures
  726. * like SPARC
  727. */
  728. u_char *
  729. dlt_en10mb_merge_layer3(tcpeditdlt_t *ctx, u_char *packet, int pktlen, u_char *ipv4_data, u_char *ipv6_data)
  730. {
  731. en10mb_extra_t *extra;
  732. struct tcpr_ethernet_hdr *eth;
  733. int l2len;
  734. assert(ctx);
  735. assert(packet);
  736. l2len = dlt_en10mb_l2len(ctx, packet, pktlen);
  737. if (l2len == -1 || pktlen < l2len)
  738. return NULL;
  739. assert(ctx->decoded_extra_size >= sizeof(*extra));
  740. extra = (en10mb_extra_t *)ctx->decoded_extra;
  741. eth = (struct tcpr_ethernet_hdr *)(packet + ctx->l2offset);
  742. assert(eth);
  743. /* modify source/destination MAC if source/destination IP is multicast */
  744. if (ipv4_data) {
  745. if ((size_t)pktlen >= sizeof(*eth) + sizeof(struct tcpr_ipv4_hdr)) {
  746. /* only destination MAC addresses will have to be modified for destination multicast IP addreses */
  747. struct tcpr_ipv4_hdr *ip_hdr = (struct tcpr_ipv4_hdr *)ipv4_data;
  748. if (!extra->dst_modified)
  749. dlt_en10mb_ipv4_multicast_mac_update(ip_hdr->ip_dst.s_addr, eth->ether_dhost,
  750. sizeof(eth->ether_dhost));
  751. }
  752. return tcpedit_dlt_l3data_merge(ctx, packet, pktlen, ipv4_data, l2len);
  753. } else if (ipv6_data) {
  754. if ((size_t)pktlen >= sizeof(*eth) + sizeof(struct tcpr_ipv6_hdr)) {
  755. /* only destination MAC addresses will have to be modified for destination multicast IPv6 addreses */
  756. struct tcpr_ipv6_hdr *ip6_hdr = (struct tcpr_ipv6_hdr *)ipv6_data;
  757. if (!extra->dst_modified)
  758. dlt_en10mb_ipv6_multicast_mac_update(&ip6_hdr->ip_dst, eth->ether_dhost, sizeof(eth->ether_dhost));
  759. }
  760. return tcpedit_dlt_l3data_merge(ctx, packet, pktlen, ipv6_data, l2len);
  761. }
  762. return NULL;
  763. }
  764. /*
  765. * return a static pointer to the source/destination MAC address
  766. * return NULL on error/address doesn't exist
  767. */
  768. u_char *
  769. dlt_en10mb_get_mac(tcpeditdlt_t *ctx, tcpeditdlt_mac_type_t mac, const u_char *packet, int pktlen)
  770. {
  771. assert(ctx);
  772. assert(packet);
  773. if (pktlen < 14)
  774. return NULL;
  775. /* FIXME: return a ptr to the source or dest mac address. */
  776. switch (mac) {
  777. case SRC_MAC:
  778. memcpy(ctx->srcmac, &packet[6], ETHER_ADDR_LEN);
  779. return (ctx->srcmac);
  780. case DST_MAC:
  781. memcpy(ctx->dstmac, packet, ETHER_ADDR_LEN);
  782. return (ctx->dstmac);
  783. default:
  784. errx(1, "Invalid tcpeditdlt_mac_type_t: %d", mac);
  785. }
  786. }
  787. /*
  788. * return the length of the L2 header of the current packet
  789. */
  790. int
  791. dlt_en10mb_l2len(tcpeditdlt_t *ctx, const u_char *packet, int pktlen)
  792. {
  793. int l2len;
  794. assert(ctx);
  795. assert(packet);
  796. if (pktlen < (int)sizeof(eth_hdr_t)) {
  797. tcpedit_seterr(ctx->tcpedit, "dlt_en10mb_l2len: pktlen=%u is less than size of Ethernet header", pktlen);
  798. return TCPEDIT_ERROR;
  799. }
  800. l2len = get_l2len(packet, pktlen, dlt_value);
  801. if (l2len > 0) {
  802. if (pktlen < l2len) {
  803. /* can happen if fuzzing is enabled */
  804. tcpedit_seterr(ctx->tcpedit, "dlt_en10mb_l2len: pktlen=%u is less than l2len=%u", pktlen, l2len);
  805. return TCPEDIT_ERROR;
  806. }
  807. return l2len;
  808. }
  809. tcpedit_seterr(ctx->tcpedit, "dlt_en10mb_l2len: %s", "Whoops! Bug in my code!");
  810. return TCPEDIT_ERROR;
  811. }
  812. tcpeditdlt_l2addr_type_t
  813. dlt_en10mb_l2addr_type(void)
  814. {
  815. return ETHERNET;
  816. }