The API for dynamic firewall filters is defined in src/junos/lib/libdfwd
in your backing sandbox, and is documented in the SDK Library reference.
You begin the filter definition by calling junos_dfw_filter_trans_alloc()
, identifying the filter by setting values for namestr_key
and owner_client_id
in the argument filter_info
.
To specify a new filter definition or to change a previously configured filter, you use the operation JUNOS_DFW_FILTER_OP_ADD
or JUNOS_DFW_FILTER_OP_CHANGE
. Multiple terms can be configured in a filter using the handle obtained for these operations.
To configure a term:
junos_dfw_term_start()
.
junos_dfw_term_end()
.
The junos_dfw_filter_types_t
structure determines the type of filter, either classic or fast update. For introductory information about these filter types, see Dynamic Firewall Filters.
The junos_dfw_filter_op_t
structure indicates the configuration operation to be executed.
/* * Globals assumed already set up for example, or they could be * parameters passed to the called function. */ junos_dfw_session_handle_t session; junos_dfw_client_id_t client_id; u_int64_t ctx; int acme_accept_mac_addresses (uint8_t *mac_addr_p, uint8_t mac_prefix_len) { int error; junos_dfw_trans_handle_t trans_hdl; junos_dfw_filter_info_t filter_info; junos_dfw_term_info_t term_info; /* Do some basic checks. */ if (!mac_addr_p || !mac_prefix_len) { acme_log("%s():%d - Bad input parameters!\n", __func__, __LINE__); return -1; } /* Initialize the filter-info structure. */ filter_info.namestr_key = "acme-filter-macs"; filter_info.type = JUNOS_DFW_FILTER_TYPE_CLASSIC; filter_info.addr_family = JUNOS_DFW_FILTER_AF_INET; /* Get a transaction handle. */ error = junos_dfw_filter_trans_alloc(&filter_info, JUNOS_DFW_FILTER_OP_ADD, &trans_hdl); if (error) { /* Couldn't get a transaction handle ... leave! */ acme_log("%s:%d() - junos_dfw_filter_trans_alloc failed!\n", __func__, __LINE__); return error; } /* Define the term. */ term_info.namestr_key = "acme-macs-term"; /* Classic filters require terms to be ordered. */ term_info.type = JUNOS_DFW_TERM_TYPE_ORDERED; term_info.property.order.term_adj_type = JUNOS_DFW_TERM_ADJ_PREV; term_info.property.order.term_adj_namestr_key = NULL; /* Start with the term ... */ error = junos_dfw_term_start(trans_hdl, &term_info, JUNOS_DFW_TERM_OP_ADD); if (error) { /* Couldn't start making a term ... leave! */ acme_log("%s:%d() - junos_dfw_term_start failed!\n", __func__, __LINE__); (void) junos_dfw_trans_handle_free(trans_hdl); return error; } /* Include a match condition. */ error = junos_dfw_term_match_dest_mac(trans_hdl, mac_addr_p, mac_prefix_len, JUNOS_DFW_FILTER_OP_MATCH); if (error) { /* Couldn't create a match condition ... leave! */ acme_log("%s:%d() - junos_dfw_term_match_src_mac failed!\n", __func__, __LINE__); (void) junos_dfw_trans_handle_free(trans_hdl); return error; } /* Specify an action. */ error = junos_dfw_term_action_accept(trans_hdl); if (error) { /* Couldn't specify an action ... leave! */ acme_log("%s:%d() - junos_dfw_term_action_accept failed!\n", __func__, __LINE__); (void) junos_dfw_trans_handle_free(trans_hdl); return error; } /* Close the term. */ error = junos_dfw_term_end(trans_hdl); if (error) { /* Couldn't close term ... leave! */ acme_log("%s:%d() - junos_dfw_term_end failed!\n", __func__, __LINE__); (void) junos_dfw_trans_handle_free(trans_hdl); return error; } /* Send the transaction. */ error = junos_dfw_trans_send(session, trans_hdl, client_id, user_ctx); if (error) { /* Couldn't send the transaction ... leave! */ acme_log("%s:%d() - junos_dfw_trans_send failed!\n", __func__, __LINE__); (void) junos_dfw_trans_handle_free(trans_hdl); return error; } /* We're done. */ return 0; }
At this point, you can apply the filter you have just configured to the input side of an interface (see Sample Code: Applying a Filter to an Interface).
You can use the same logic for other Layer 2 functions, substituting their respective set of parameters.
/* * Configure policers */ junos_dfw_trans_handle_t policer_trans_hdl; junos_dfw_policer_info_t policer_info; /* * First configure policer "voice-traffic" */ policer_info.namestr_key = "voice-traffic"; if (junos_dfw_policer_trans_alloc(&policer_info, JUNOS_DFW_POLICER_OP_ADD, /*operation*/ &policer_trans_hdl) < 0) { perror("junos_dfw_policer_trans_alloc failed\n"); } else if (junos_dfw_policer_parameters(policer_trans_hdl, 300, /*rate*/ JUNOS_DFW_RATE_UNIT_KBPS, /*rate_unit*/ 3, /*burst_size_limit_bytes*/ JUNOS_DFW_BURST_SIZE_UNIT_KBYTE, FALSE) < 0) /*filter_specific*/ { perror("junos_dfw_policer_parameters failed\n"); } else if (junos_dfw_policer_action_discard(policer_trans_hdl) < 0) { perror("junos_dfw_policer_action_discard failed\n"); } else if (junos_dfw_trans_tx(session, policer_trans_hdl, id, user_ctx) < 0) { perror("junos_dfw_trans_tx failed\n"); } /* * Specify filter information. */ junos_dfw_filter_info_t filter_info; /* * Initialize filter info struct to be used for transaction * allocation. */ filter_info.namestr_key = "media-service"; filter_info.type = JUNOS_DFW_FILTER_TYPE_FAST_UPDATE; filter_info.addr_family = JUNOS_DFW_FILTER_AF_INET; /* * Allocate a filter config transaction handle. */ junos_dfw_trans_handle_t trans_hdl; if (junos_dfw_filter_trans_alloc(&filter_info, JUNOS_DFW_FILTER_OP_ADD, /*operation*/ &trans_hdl) < 0) { perror("junos_dfw_filter_trans_alloc failed\n"); } /* * Set up an ordered list of the fields, as required for fast-update filters: * * The junos_dfw_filter_prop_ordered_field_list property sets * the list of fields that can be configured in the filter * and establishes the order in which the fields * will be matched: ip proto, followed by source address, * followed by destination address, followed by source port, * followed by destination port. */ junos_dfw_filter_field_type_t field_list[] = { JUNOS_DFW_FILTER_FIELD_IP_PROTO, JUNOS_DFW_FILTER_FIELD_IP_SRC_ADDR, JUNOS_DFW_FILTER_FIELD_IP_DEST_ADDR, JUNOS_DFW_FILTER_FIELD_SRC_PORT, JUNOS_DFW_FILTER_FIELD_DEST_PORT}; if (junos_dfw_filter_prop_ordered_field_list(trans_hdl, 5, /*num_fields*/ field_list) < 0) { perror("junos_dfw_filter_prop_field_list failed\n"); } /* * Start definition of term "session1". */ junos_dfw_term_info_t term_info; term_info.namestr_key = "session1"; /* * A fast-update filter requires terms of type "prioritised" */ term_info.type = JUNOS_DFW_TERM_TYPE_PRIORITISED; term_info.property.priority = 0; if (junos_dfw_term_start(trans_hdl, &term_info; JUNOS_DFW_TERM_OP_ADD) < 0) /*operation*/ { perror("junos_dfw_term_start failed\n"); } /* * Provide match conditions by calling junos_dfw_term_match_XXX functions. * */ u_int32_t src_addr = 0xC0A8010A; /* 192.168.1.10 */ u_int16_t src_port = 8080; u_int32_t dest_addr = 0x1310010A; /* 19.16.1.10 */ u_int16_t dest_port = 9080; if (junos_dfw_term_match_src_prefix(trans_hdl, &src_addr, 32, /* prefix_len in bits */ JUNOS_DFW_FILTER_OP_MATCH) < 0) /*operation*/ { perror("junos_dfw_term_match_src_prefix failed\n"); } else if (junos_dfw_term_match_dest_prefix(trans_hdl, &dest_addr, 32, /* prefix_len in bits */ JUNOS_DFW_FILTER_OP_MATCH) < 0) /*operation*/ { perror("junos_dfw_term_match_dest_prefix failed\n"); } else if (junos_dfw_term_match_ip_proto(trans_hdl, 6, /*ip_proto_min = tcp*/ 6, /*ip_proto_max = tcp*/ JUNOS_DFW_FILTER_OP_MATCH) < 0) /*operation*/ { perror("junos_dfw_term_match_ip_proto failed\n"); } else if (junos_dfw_term_match_src_port(trans_hdl, src_port, /* port_min */ src_port, /* port_max */ JUNOS_DFW_FILTER_OP_MATCH) < 0) /*operation*/ { perror("junos_dfw_term_match_src_port failed\n"); } else if (junos_dfw_term_match_dest_port(trans_hdl, dest_port, /* port_min */ dest_port, /* port_max */ JUNOS_DFW_FILTER_OP_MATCH) < 0) /*operation*/ { perror("junos_dfw_term_match_dest_port failed\n"); } if (junos_dfw_term_action_policer(trans_hdl, &policer_info) < 0) { perror("junos_dfw_term_action_policer failed\n"); } /* * End definition of term "session1": */ if (junos_dfw_term_end(trans_hdl) < 0) { perror("junos_dfw_term_end failed\n"); } /* * Configure term "voice-signaling". */ term_info.namestr_key = "voice-signaling"; src_addr = 0xC0A80100; /* 192.168.1.0 */ term_info.type = DFWD_TERM_TYPE_PRIORITISED; term_info.property.priority = 0; if (junos_dfw_term_start(trans_hdl, &term_info; DFWD_TERM_OP_ADD) < 0) /*operation*/ { perror("junos_dfw_term_start failed\n"); } else if (junos_dfw_term_match_src_prefix(trans_hdl, &src_addr, 24, /* prefix_len in bits */ DFWD_FILTER_OP_MATCH) < 0) /*operation*/ { perror("junos_dfw_term_match_src_prefix failed\n"); } else if (junos_dfw_term_match_src_port(trans_hdl, 7000, /* port_min */ 9000, /* port_max */ DFWD_FILTER_OP_MATCH) < 0) /*operation*/ { perror("junos_dfw_term_match_src_port failed\n"); } else if (junos_dfw_term_action_policer(trans_hdl, &policer_info) < 0) { perror("junos_dfw_term_action_policer failed\n"); } else if (junos_dfw_term_end(trans_hdl) < 0) { perror("junos_dfw_term_end failed\n"); } if (junos_dfw_trans_send(session, trans_hdl, id, user_ctx) < 0) { perror("junos_dfw_trans_send failed\n"); }
At this point, you can apply the filter you have just configured to the input side of an interface (see Sample Code: Applying a Filter to an Interface, next).
ge-0/0/0.0
. In this example, CLIENT_ID
is the identifier that is returned to your application from JUNOS-DFW
when you open the session by calling junos_dfw_session_open()
.
junos_dfw_trans_handle_t apply_trans_hdl; if(junos_dfw_filter_attach_trans_alloc(&filter_info, JUNOS_DFW_FILTER_ATTACH_POINT_INPUT_INTF, "ge-0/0/0.0", &apply_trans_hdl)) { perror("junos_dfw_filter_attach_trans_alloc failed\n"); } else if (junos_dfw_trans_send(session, apply_trans_hdl, CLIENT_ID, user_ctx) < 0) { perror("junos_dfw_trans_send failed\n"); } else /* Transaction handle must be freed as follows if not saved.*/ if (junos_dfw_trans_handle_free(apply_trans_hdl) < 0) { perror("junos_dfw_trans_handle_free failed\n"); }
JUNOS-DFW
, the application can associate user-specific information (typically, a pointer to a user session control block) with the session. For example:
error = junos_dfw_user_data_set(handle_p, &acme_block_p); if (error) { acme_log("Unable to associate user data\n"); return -1; }
Later, in a callback, the application can retrieve the stored information pointer as follows:
acme_block_s *acme_block_p; error = junos_dfw_user_data_get(handle_p, &acme_block_p); if (error) { acme_log("Unable to retrieve user data\n"); return -1; }