// load the name table void upkg::get_names(void) { int i, index; index = hdr->name_offset; for (i = 0; i < hdr->name_count; i++) { if (hdr->file_version >= 64) { get_string(&header[index + 1], get_s8(&header[index])); index++; } else { get_string(&header[index], UPKG_NAME_NOCOUNT); } index += data_size; strncpy(names[i].name, buf, UPKG_MAX_NAME_SIZE); names[i].flags = get_s32(&header[index]); index += data_size; } // hdr->name_count + 1 names total, this one's last strncpy(names[i].name, "(NULL)", UPKG_MAX_NAME_SIZE); names[i].flags = 0; }
// load the type_names void upkg::get_type(char *buf, int e, int d) { int i, j, index; signed long tmp; char *chtmp; index = 0; for (i = 0, j = strlen(export_desc[d].order); i < j; i++) { switch (export_desc[d].order[i]) { case UPKG_DATA_FCI: tmp = get_fci(&buf[index]); index += data_size; break; case UPKG_DATA_32: tmp = get_s32(&buf[index]); index += data_size; break; case UPKG_DATA_16: tmp = get_s16(&buf[index]); index += data_size; break; case UPKG_DATA_8: tmp = get_s8(&buf[index]); index += data_size; break; case UPKG_DATA_ASCIC: chtmp = get_string(&buf[index + 1], get_s8(&buf[index++])); index += data_size; break; case UPKG_DATA_ASCIZ: chtmp = get_string(&buf[index], UPKG_NAME_NOCOUNT); index += data_size; break; case UPKG_OBJ_JUNK: // do nothing!!! break; case UPKG_OBJ_NAME: exports[e].type_name = tmp; break; case UPKG_EXP_SIZE: // maybe we'll do something later on break; case UPKG_OBJ_SIZE: exports[e].object_size = tmp; break; default: exports[e].type_name = -1; return; } } exports[e].object_offset = exports[e].serial_offset + index; }
void upkg::get_exports(void) { int i, index; char readbuf[1024]; reader->seek(hdr->export_offset); reader->read(readbuf, 1024); index = 0; for (i = 0; i < hdr->export_count; i++) { exports[i].class_index = get_fci(&readbuf[index]); index += data_size; exports[i].package_index = get_s32(&readbuf[index]); index += data_size; exports[i].super_index = get_fci(&readbuf[index]); index += data_size; exports[i].object_name = get_fci(&readbuf[index]); index += data_size; exports[i].object_flags = get_s32(&readbuf[index]); index += data_size; exports[i].serial_size = get_fci(&readbuf[index]); index += data_size; if (exports[i].serial_size > 0) { exports[i].serial_offset = get_fci(&readbuf[index]); index += data_size; } else { exports[i].serial_offset = -1; } get_exports_cpnames(i); // go grab the class & package names } }
// load the import table (notice a trend?). same story as get_exports() void upkg::get_imports(void) { int i, index; char readbuf[1024]; reader->seek(hdr->import_offset); reader->read(readbuf, 1024); index = 0; for (i = 0; i < hdr->import_count; i++) { imports[i].class_package = get_fci(&readbuf[index]); index += data_size; imports[i].class_name = get_fci(&readbuf[index]); index += data_size; imports[i].package_index = get_s32(&readbuf[index]); index += data_size; imports[i].object_name = get_fci(&readbuf[index]); index += data_size; } }
static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { int dist_size = 0; struct rtattr *tail; struct tc_netem_qopt opt = { .limit = 1000 }; struct tc_netem_corr cor; struct tc_netem_reorder reorder; struct tc_netem_corrupt corrupt; struct tc_netem_gimodel gimodel; struct tc_netem_gemodel gemodel; struct tc_netem_rate rate; __s16 *dist_data = NULL; __u16 loss_type = NETEM_LOSS_UNSPEC; int present[__TCA_NETEM_MAX]; __u64 rate64 = 0; memset(&cor, 0, sizeof(cor)); memset(&reorder, 0, sizeof(reorder)); memset(&corrupt, 0, sizeof(corrupt)); memset(&rate, 0, sizeof(rate)); memset(present, 0, sizeof(present)); for( ; argc > 0; --argc, ++argv) { if (matches(*argv, "limit") == 0) { NEXT_ARG(); if (get_size(&opt.limit, *argv)) { explain1("limit"); return -1; } } else if (matches(*argv, "latency") == 0 || matches(*argv, "delay") == 0) { NEXT_ARG(); if (get_ticks(&opt.latency, *argv)) { explain1("latency"); return -1; } if (NEXT_IS_NUMBER()) { NEXT_ARG(); if (get_ticks(&opt.jitter, *argv)) { explain1("latency"); return -1; } if (NEXT_IS_NUMBER()) { NEXT_ARG(); ++present[TCA_NETEM_CORR]; if (get_percent(&cor.delay_corr, *argv)) { explain1("latency"); return -1; } } } } else if (matches(*argv, "loss") == 0 || matches(*argv, "drop") == 0) { if (opt.loss > 0 || loss_type != NETEM_LOSS_UNSPEC) { explain1("duplicate loss argument\n"); return -1; } NEXT_ARG(); /* Old (deprecated) random loss model syntax */ if (isdigit(argv[0][0])) goto random_loss_model; if (!strcmp(*argv, "random")) { NEXT_ARG(); random_loss_model: if (get_percent(&opt.loss, *argv)) { explain1("loss percent"); return -1; } if (NEXT_IS_NUMBER()) { NEXT_ARG(); ++present[TCA_NETEM_CORR]; if (get_percent(&cor.loss_corr, *argv)) { explain1("loss correllation"); return -1; } } } else if (!strcmp(*argv, "state")) { double p13; NEXT_ARG(); if (parse_percent(&p13, *argv)) { explain1("loss p13"); return -1; } /* set defaults */ set_percent(&gimodel.p13, p13); set_percent(&gimodel.p31, 1. - p13); set_percent(&gimodel.p32, 0); set_percent(&gimodel.p23, 1.); set_percent(&gimodel.p14, 0); loss_type = NETEM_LOSS_GI; if (!NEXT_IS_NUMBER()) continue; NEXT_ARG(); if (get_percent(&gimodel.p31, *argv)) { explain1("loss p31"); return -1; } if (!NEXT_IS_NUMBER()) continue; NEXT_ARG(); if (get_percent(&gimodel.p32, *argv)) { explain1("loss p32"); return -1; } if (!NEXT_IS_NUMBER()) continue; NEXT_ARG(); if (get_percent(&gimodel.p23, *argv)) { explain1("loss p23"); return -1; } if (!NEXT_IS_NUMBER()) continue; NEXT_ARG(); if (get_percent(&gimodel.p14, *argv)) { explain1("loss p14"); return -1; } } else if (!strcmp(*argv, "gemodel")) { NEXT_ARG(); if (get_percent(&gemodel.p, *argv)) { explain1("loss gemodel p"); return -1; } /* set defaults */ set_percent(&gemodel.r, 1.); set_percent(&gemodel.h, 0); set_percent(&gemodel.k1, 0); loss_type = NETEM_LOSS_GE; if (!NEXT_IS_NUMBER()) continue; NEXT_ARG(); if (get_percent(&gemodel.r, *argv)) { explain1("loss gemodel r"); return -1; } if (!NEXT_IS_NUMBER()) continue; NEXT_ARG(); if (get_percent(&gemodel.h, *argv)) { explain1("loss gemodel h"); return -1; } /* netem option is "1-h" but kernel * expects "h". */ gemodel.h = max_percent_value - gemodel.h; if (!NEXT_IS_NUMBER()) continue; NEXT_ARG(); if (get_percent(&gemodel.k1, *argv)) { explain1("loss gemodel k"); return -1; } } else { fprintf(stderr, "Unknown loss parameter: %s\n", *argv); return -1; } } else if (matches(*argv, "ecn") == 0) { present[TCA_NETEM_ECN] = 1; } else if (matches(*argv, "reorder") == 0) { NEXT_ARG(); present[TCA_NETEM_REORDER] = 1; if (get_percent(&reorder.probability, *argv)) { explain1("reorder"); return -1; } if (NEXT_IS_NUMBER()) { NEXT_ARG(); ++present[TCA_NETEM_CORR]; if (get_percent(&reorder.correlation, *argv)) { explain1("reorder"); return -1; } } } else if (matches(*argv, "corrupt") == 0) { NEXT_ARG(); present[TCA_NETEM_CORRUPT] = 1; if (get_percent(&corrupt.probability, *argv)) { explain1("corrupt"); return -1; } if (NEXT_IS_NUMBER()) { NEXT_ARG(); ++present[TCA_NETEM_CORR]; if (get_percent(&corrupt.correlation, *argv)) { explain1("corrupt"); return -1; } } } else if (matches(*argv, "gap") == 0) { NEXT_ARG(); if (get_u32(&opt.gap, *argv, 0)) { explain1("gap"); return -1; } } else if (matches(*argv, "duplicate") == 0) { NEXT_ARG(); if (get_percent(&opt.duplicate, *argv)) { explain1("duplicate"); return -1; } if (NEXT_IS_NUMBER()) { NEXT_ARG(); if (get_percent(&cor.dup_corr, *argv)) { explain1("duplicate"); return -1; } } } else if (matches(*argv, "distribution") == 0) { NEXT_ARG(); dist_data = calloc(sizeof(dist_data[0]), MAX_DIST); dist_size = get_distribution(*argv, dist_data, MAX_DIST); if (dist_size <= 0) { free(dist_data); return -1; } } else if (matches(*argv, "rate") == 0) { ++present[TCA_NETEM_RATE]; NEXT_ARG(); if (get_rate64(&rate64, *argv)) { explain1("rate"); return -1; } if (NEXT_IS_SIGNED_NUMBER()) { NEXT_ARG(); if (get_s32(&rate.packet_overhead, *argv, 0)) { explain1("rate"); return -1; } } if (NEXT_IS_NUMBER()) { NEXT_ARG(); if (get_u32(&rate.cell_size, *argv, 0)) { explain1("rate"); return -1; } } if (NEXT_IS_SIGNED_NUMBER()) { NEXT_ARG(); if (get_s32(&rate.cell_overhead, *argv, 0)) { explain1("rate"); return -1; } } } else if (strcmp(*argv, "help") == 0) { explain(); return -1; } else { fprintf(stderr, "What is \"%s\"?\n", *argv); explain(); return -1; } } tail = NLMSG_TAIL(n); if (reorder.probability) { if (opt.latency == 0) { fprintf(stderr, "reordering not possible without specifying some delay\n"); explain(); return -1; } if (opt.gap == 0) opt.gap = 1; } else if (opt.gap > 0) { fprintf(stderr, "gap specified without reorder probability\n"); explain(); return -1; } if (present[TCA_NETEM_ECN]) { if (opt.loss <= 0 && loss_type == NETEM_LOSS_UNSPEC) { fprintf(stderr, "ecn requested without loss model\n"); explain(); return -1; } } if (dist_data && (opt.latency == 0 || opt.jitter == 0)) { fprintf(stderr, "distribution specified but no latency and jitter values\n"); explain(); return -1; } if (addattr_l(n, 1024, TCA_OPTIONS, &opt, sizeof(opt)) < 0) return -1; if (present[TCA_NETEM_CORR] && addattr_l(n, 1024, TCA_NETEM_CORR, &cor, sizeof(cor)) < 0) return -1; if (present[TCA_NETEM_REORDER] && addattr_l(n, 1024, TCA_NETEM_REORDER, &reorder, sizeof(reorder)) < 0) return -1; if (present[TCA_NETEM_ECN] && addattr_l(n, 1024, TCA_NETEM_ECN, &present[TCA_NETEM_ECN], sizeof(present[TCA_NETEM_ECN])) < 0) return -1; if (present[TCA_NETEM_CORRUPT] && addattr_l(n, 1024, TCA_NETEM_CORRUPT, &corrupt, sizeof(corrupt)) < 0) return -1; if (loss_type != NETEM_LOSS_UNSPEC) { struct rtattr *start; start = addattr_nest(n, 1024, TCA_NETEM_LOSS | NLA_F_NESTED); if (loss_type == NETEM_LOSS_GI) { if (addattr_l(n, 1024, NETEM_LOSS_GI, &gimodel, sizeof(gimodel)) < 0) return -1; } else if (loss_type == NETEM_LOSS_GE) { if (addattr_l(n, 1024, NETEM_LOSS_GE, &gemodel, sizeof(gemodel)) < 0) return -1; } else { fprintf(stderr, "loss in the weeds!\n"); return -1; } addattr_nest_end(n, start); } if (present[TCA_NETEM_RATE]) { if (rate64 >= (1ULL << 32)) { if (addattr_l(n, 1024, TCA_NETEM_RATE64, &rate64, sizeof(rate64)) < 0) return -1; rate.rate = ~0U; } else { rate.rate = rate64; } if (addattr_l(n, 1024, TCA_NETEM_RATE, &rate, sizeof(rate)) < 0) return -1; } if (dist_data) { if (addattr_l(n, MAX_DIST * sizeof(dist_data[0]), TCA_NETEM_DELAY_DIST, dist_data, dist_size * sizeof(dist_data[0])) < 0) return -1; free(dist_data); } tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; return 0; } static int netem_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) { const struct tc_netem_corr *cor = NULL; const struct tc_netem_reorder *reorder = NULL; const struct tc_netem_corrupt *corrupt = NULL; const struct tc_netem_gimodel *gimodel = NULL; const struct tc_netem_gemodel *gemodel = NULL; int *ecn = NULL; struct tc_netem_qopt qopt; const struct tc_netem_rate *rate = NULL; int len = RTA_PAYLOAD(opt) - sizeof(qopt); __u64 rate64 = 0; SPRINT_BUF(b1); if (opt == NULL) return 0; if (len < 0) { fprintf(stderr, "options size error\n"); return -1; } memcpy(&qopt, RTA_DATA(opt), sizeof(qopt)); if (len > 0) { struct rtattr *tb[TCA_NETEM_MAX+1]; parse_rtattr(tb, TCA_NETEM_MAX, RTA_DATA(opt) + sizeof(qopt), len); if (tb[TCA_NETEM_CORR]) { if (RTA_PAYLOAD(tb[TCA_NETEM_CORR]) < sizeof(*cor)) return -1; cor = RTA_DATA(tb[TCA_NETEM_CORR]); } if (tb[TCA_NETEM_REORDER]) { if (RTA_PAYLOAD(tb[TCA_NETEM_REORDER]) < sizeof(*reorder)) return -1; reorder = RTA_DATA(tb[TCA_NETEM_REORDER]); } if (tb[TCA_NETEM_CORRUPT]) { if (RTA_PAYLOAD(tb[TCA_NETEM_CORRUPT]) < sizeof(*corrupt)) return -1; corrupt = RTA_DATA(tb[TCA_NETEM_CORRUPT]); } if (tb[TCA_NETEM_LOSS]) { struct rtattr *lb[NETEM_LOSS_MAX + 1]; parse_rtattr_nested(lb, NETEM_LOSS_MAX, tb[TCA_NETEM_LOSS]); if (lb[NETEM_LOSS_GI]) gimodel = RTA_DATA(lb[NETEM_LOSS_GI]); if (lb[NETEM_LOSS_GE]) gemodel = RTA_DATA(lb[NETEM_LOSS_GE]); } if (tb[TCA_NETEM_RATE]) { if (RTA_PAYLOAD(tb[TCA_NETEM_RATE]) < sizeof(*rate)) return -1; rate = RTA_DATA(tb[TCA_NETEM_RATE]); } if (tb[TCA_NETEM_ECN]) { if (RTA_PAYLOAD(tb[TCA_NETEM_ECN]) < sizeof(*ecn)) return -1; ecn = RTA_DATA(tb[TCA_NETEM_ECN]); } if (tb[TCA_NETEM_RATE64]) { if (RTA_PAYLOAD(tb[TCA_NETEM_RATE64]) < sizeof(rate64)) return -1; rate64 = rta_getattr_u64(tb[TCA_NETEM_RATE64]); } } fprintf(f, "limit %d", qopt.limit); if (qopt.latency) { fprintf(f, " delay %s", sprint_ticks(qopt.latency, b1)); if (qopt.jitter) { fprintf(f, " %s", sprint_ticks(qopt.jitter, b1)); if (cor && cor->delay_corr) fprintf(f, " %s", sprint_percent(cor->delay_corr, b1)); } } if (qopt.loss) { fprintf(f, " loss %s", sprint_percent(qopt.loss, b1)); if (cor && cor->loss_corr) fprintf(f, " %s", sprint_percent(cor->loss_corr, b1)); } if (gimodel) { fprintf(f, " loss state p13 %s", sprint_percent(gimodel->p13, b1)); fprintf(f, " p31 %s", sprint_percent(gimodel->p31, b1)); fprintf(f, " p32 %s", sprint_percent(gimodel->p32, b1)); fprintf(f, " p23 %s", sprint_percent(gimodel->p23, b1)); fprintf(f, " p14 %s", sprint_percent(gimodel->p14, b1)); } if (gemodel) { fprintf(f, " loss gemodel p %s", sprint_percent(gemodel->p, b1)); fprintf(f, " r %s", sprint_percent(gemodel->r, b1)); fprintf(f, " 1-h %s", sprint_percent(max_percent_value - gemodel->h, b1)); fprintf(f, " 1-k %s", sprint_percent(gemodel->k1, b1)); } if (qopt.duplicate) { fprintf(f, " duplicate %s", sprint_percent(qopt.duplicate, b1)); if (cor && cor->dup_corr) fprintf(f, " %s", sprint_percent(cor->dup_corr, b1)); } if (reorder && reorder->probability) { fprintf(f, " reorder %s", sprint_percent(reorder->probability, b1)); if (reorder->correlation) fprintf(f, " %s", sprint_percent(reorder->correlation, b1)); } if (corrupt && corrupt->probability) { fprintf(f, " corrupt %s", sprint_percent(corrupt->probability, b1)); if (corrupt->correlation) fprintf(f, " %s", sprint_percent(corrupt->correlation, b1)); } if (rate && rate->rate) { if (rate64) fprintf(f, " rate %s", sprint_rate(rate64, b1)); else fprintf(f, " rate %s", sprint_rate(rate->rate, b1)); if (rate->packet_overhead) fprintf(f, " packetoverhead %d", rate->packet_overhead); if (rate->cell_size) fprintf(f, " cellsize %u", rate->cell_size); if (rate->cell_overhead) fprintf(f, " celloverhead %d", rate->cell_overhead); } if (ecn) fprintf(f, " ecn "); if (qopt.gap) fprintf(f, " gap %lu", (unsigned long)qopt.gap); return 0; } struct qdisc_util netem_qdisc_util = { .id = "netem", .parse_qopt = netem_parse_opt, .print_qopt = netem_print_opt, };
static void DmpLoc( uint_8 const *p, uint length, uint addr_size ) /****************************************************************/ { uint_8 const *end; uint_8 op; dw_locop_op opr; int_32 op1s; uint_32 op1u; int_32 op2s; uint_32 addr; end = &p[length]; Wdputslc( "\n Loc expr: " ); if( p == end ) { Wdputslc( "<NULL>\n" ); } while( p < end ) { op = *p; ++p; Wdputs( OpName[ op ] ); opr = LocOpr[ op ]; if( opr == DW_LOP_REG1 || opr == DW_LOP_BRG1 ) { Wdputs( "/" ); } else { Wdputs( " " ); } switch( opr ) { case DW_LOP_NOOP: break; case DW_LOP_ADDR: if( addr_size == 4 ) { addr = *(uint_32 *)p; } else if( addr_size == 2 ) { addr = *(uint_16 *)p; } else if( addr_size == 1 ) { addr = *(uint_8 *)p; } else { addr = 0; } Puthex( addr, addr_size * 2 ); p += addr_size; break; case DW_LOP_OPU1: op1u = *(uint_8 *)p; p += sizeof( uint_8 ); Putdec( op1u ); break; case DW_LOP_OPS1: op1s = *(int_8 *)p; p += sizeof(int_8 ); Putdec( op1s ); break; case DW_LOP_OPU2: op1u = get_u16( (uint_16 *)p ); p += sizeof( uint_16 ); Putdec( op1u ); break; case DW_LOP_OPS2: op1s = get_s16( (int_16 *)p ); p += sizeof( int_16 ); Putdec( op1s ); break; case DW_LOP_OPU4: op1u = get_u32( (uint_32 *)p ); p += sizeof( uint_32 ); Putdec( op1u ); break; case DW_LOP_OPS4: op1s = get_s32( (int_32 *)p ); p += sizeof( int_32 ); Putdec( op1s ); break; case DW_LOP_U128: p = DecodeULEB128( p, &op1u ); Putdec( op1u ); break; case DW_LOP_S128: p = DecodeSLEB128( p, &op1s ); Putdecs( op1s ); break; case DW_LOP_U128_S128: p = DecodeULEB128( p, &op1u ); p = DecodeSLEB128( p, &op2s ); Putdec( op1u ); Wdputs( "," ); Putdecs( op2s ); break; case DW_LOP_LIT1: op1u = op-DW_OP_lit0; op = DW_OP_lit0; break; case DW_LOP_REG1: op1u = op-DW_OP_reg0; op = DW_OP_reg0; Wdputs( RegName[ op1u] ); break; case DW_LOP_BRG1: op1u = op-DW_OP_breg0; p = DecodeSLEB128( p, &op2s ); Wdputs( RegName[ op1u] ); if( op2s < 0 ) { Wdputs( " -" ); op2s = -op2s; } else { Wdputs( " +" ); } Putdec( op2s ); op = DW_OP_breg0; break; } Wdputslc( " " ); } Wdputslc( "\n" ); }
static int authd_sockfn_set(struct sock *sk, int optval, void __user *user, unsigned int len) { int option; int res = 0; /* Check a few things, then read our option index */ if (optval != SO_AUTHD) return -EBADF; if (len < sizeof(option)) return -EINVAL; if (copy_from_user(&option, user, sizeof(option))) return -EFAULT; user += sizeof(option); len -= sizeof(option); bh_lock_sock(sk); switch (option) { default: printk(KERN_ERR "authd-sockopt: bad setsockopt option %d\n", option); res = -EBADMSG; break; case AUTHD_OP_EXTIRPATE: /* Extirpate unrequited data */ #ifdef CONFIG_IP_NF_SET_URLFRAG_MODULE if (sk->sk_authd_url != NULL) { kfree(sk->sk_authd_url); sk->sk_authd_url = NULL; } #endif #ifdef CONFIG_IP_NF_SET_POLYNUM_MODULE if (sk->sk_authd_groups != NULL) { kfree(sk->sk_authd_groups); sk->sk_authd_groups = NULL; } if (sk->sk_authd_ts_categories != NULL) { kfree(sk->sk_authd_ts_categories); sk->sk_authd_ts_categories = NULL; } #endif #ifdef CONFIG_NETFILTER_XT_MATCH_SOCKOPT_MODULE sk->sk_authd_dev = 0; sk->sk_authd_saddr = 0; sk->sk_authd_daddr = 0; #endif #ifdef CONFIG_NETFILTER_XT_MATCH_TSREPUTATION_MODULE sk->sk_authd_tsreputation = 0; #endif break; #ifdef CONFIG_NETFILTER_XT_MATCH_SOCKOPT_MODULE case AUTHD_OP_DEV: res = get_u32(&sk->sk_authd_dev, user, len); case AUTHD_OP_SADDR: res = get_u32(&sk->sk_authd_saddr, user, len); break; case AUTHD_OP_DADDR: res = get_u32(&sk->sk_authd_daddr, user, len); break; #endif #ifdef CONFIG_IP_NF_SET_URLFRAG_MODULE case AUTHD_OP_URL: res = get_string(&sk->sk_authd_url, user, len); break; #endif #ifdef CONFIG_IP_NF_SET_POLYNUM_MODULE case AUTHD_OP_GROUPS: res = get_u32_list(&sk->sk_authd_groups, user, len); break; #endif #ifdef CONFIG_IP_NF_SET_POLYNUM_MODULE case AUTHD_OP_TSCATEGORIES: res = get_u32_list(&sk->sk_authd_ts_categories, user, len); break; #endif #ifdef CONFIG_NETFILTER_XT_MATCH_TSREPUTATION_MODULE case AUTHD_OP_TSREPUTATION: res = get_s32(&sk->sk_authd_tsreputation, user, len); break; #endif } bh_unlock_sock(sk); return res; }
static int iprule_modify(int cmd, int argc, char **argv) { int table_ok = 0; struct { struct nlmsghdr n; struct rtmsg r; char buf[1024]; } req; memset(&req, 0, sizeof(req)); req.n.nlmsg_type = cmd; req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.r.rtm_family = preferred_family; req.r.rtm_protocol = RTPROT_BOOT; req.r.rtm_scope = RT_SCOPE_UNIVERSE; req.r.rtm_table = 0; req.r.rtm_type = RTN_UNSPEC; req.r.rtm_flags = 0; if (cmd == RTM_NEWRULE) { req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL; req.r.rtm_type = RTN_UNICAST; } while (argc > 0) { if (strcmp(*argv, "not") == 0) { req.r.rtm_flags |= FIB_RULE_INVERT; } else if (strcmp(*argv, "from") == 0) { inet_prefix dst; NEXT_ARG(); get_prefix(&dst, *argv, req.r.rtm_family); req.r.rtm_src_len = dst.bitlen; addattr_l(&req.n, sizeof(req), FRA_SRC, &dst.data, dst.bytelen); } else if (strcmp(*argv, "to") == 0) { inet_prefix dst; NEXT_ARG(); get_prefix(&dst, *argv, req.r.rtm_family); req.r.rtm_dst_len = dst.bitlen; addattr_l(&req.n, sizeof(req), FRA_DST, &dst.data, dst.bytelen); } else if (matches(*argv, "preference") == 0 || matches(*argv, "order") == 0 || matches(*argv, "priority") == 0) { __u32 pref; NEXT_ARG(); if (get_u32(&pref, *argv, 0)) invarg("preference value is invalid\n", *argv); addattr32(&req.n, sizeof(req), FRA_PRIORITY, pref); } else if (strcmp(*argv, "tos") == 0 || matches(*argv, "dsfield") == 0) { __u32 tos; NEXT_ARG(); if (rtnl_dsfield_a2n(&tos, *argv)) invarg("TOS value is invalid\n", *argv); req.r.rtm_tos = tos; } else if (strcmp(*argv, "fwmark") == 0) { char *slash; __u32 fwmark, fwmask; NEXT_ARG(); if ((slash = strchr(*argv, '/')) != NULL) *slash = '\0'; if (get_u32(&fwmark, *argv, 0)) invarg("fwmark value is invalid\n", *argv); addattr32(&req.n, sizeof(req), FRA_FWMARK, fwmark); if (slash) { if (get_u32(&fwmask, slash+1, 0)) invarg("fwmask value is invalid\n", slash+1); addattr32(&req.n, sizeof(req), FRA_FWMASK, fwmask); } } else if (matches(*argv, "realms") == 0) { __u32 realm; NEXT_ARG(); if (get_rt_realms_or_raw(&realm, *argv)) invarg("invalid realms\n", *argv); addattr32(&req.n, sizeof(req), FRA_FLOW, realm); } else if (matches(*argv, "table") == 0 || strcmp(*argv, "lookup") == 0) { __u32 tid; NEXT_ARG(); if (rtnl_rttable_a2n(&tid, *argv)) invarg("invalid table ID\n", *argv); if (tid < 256) req.r.rtm_table = tid; else { req.r.rtm_table = RT_TABLE_UNSPEC; addattr32(&req.n, sizeof(req), FRA_TABLE, tid); } table_ok = 1; } else if (matches(*argv, "suppress_prefixlength") == 0 || strcmp(*argv, "sup_pl") == 0) { int pl; NEXT_ARG(); if (get_s32(&pl, *argv, 0) || pl < 0) invarg("suppress_prefixlength value is invalid\n", *argv); addattr32(&req.n, sizeof(req), FRA_SUPPRESS_PREFIXLEN, pl); } else if (matches(*argv, "suppress_ifgroup") == 0 || strcmp(*argv, "sup_group") == 0) { NEXT_ARG(); int group; if (rtnl_group_a2n(&group, *argv)) invarg("Invalid \"suppress_ifgroup\" value\n", *argv); addattr32(&req.n, sizeof(req), FRA_SUPPRESS_IFGROUP, group); } else if (strcmp(*argv, "dev") == 0 || strcmp(*argv, "iif") == 0) { NEXT_ARG(); addattr_l(&req.n, sizeof(req), FRA_IFNAME, *argv, strlen(*argv)+1); } else if (strcmp(*argv, "oif") == 0) { NEXT_ARG(); addattr_l(&req.n, sizeof(req), FRA_OIFNAME, *argv, strlen(*argv)+1); } else if (strcmp(*argv, "nat") == 0 || matches(*argv, "map-to") == 0) { NEXT_ARG(); fprintf(stderr, "Warning: route NAT is deprecated\n"); addattr32(&req.n, sizeof(req), RTA_GATEWAY, get_addr32(*argv)); req.r.rtm_type = RTN_NAT; } else { int type; if (strcmp(*argv, "type") == 0) { NEXT_ARG(); } if (matches(*argv, "help") == 0) usage(); else if (matches(*argv, "goto") == 0) { __u32 target; type = FR_ACT_GOTO; NEXT_ARG(); if (get_u32(&target, *argv, 0)) invarg("invalid target\n", *argv); addattr32(&req.n, sizeof(req), FRA_GOTO, target); } else if (matches(*argv, "nop") == 0) type = FR_ACT_NOP; else if (rtnl_rtntype_a2n(&type, *argv)) invarg("Failed to parse rule type", *argv); req.r.rtm_type = type; table_ok = 1; } argc--; argv++; } if (req.r.rtm_family == AF_UNSPEC) req.r.rtm_family = AF_INET; if (!table_ok && cmd == RTM_NEWRULE) req.r.rtm_table = RT_TABLE_MAIN; if (rtnl_talk(&rth, &req.n, NULL, 0) < 0) return -2; return 0; }