Chinaunix首页 | 论坛 | 博客
  • 博客访问: 289324
  • 博文数量: 102
  • 博客积分: 230
  • 博客等级: 入伍新兵
  • 技术积分: 477
  • 用 户 组: 普通用户
  • 注册时间: 2010-12-13 15:58
文章存档

2014年(23)

2013年(2)

2012年(45)

2011年(32)

分类:

2012-04-11 16:17:42

实例分析Iptables基本原理(Part 1 - Big Picture)

  本文源码分析基于Iptables1.4.7.
  本文档版权归hereitis所有,可以自由拷贝/转载,转载时请保持文档的完整性并且注明来源,禁止用于任何商业用途。
  hereitis.cu@gmail.com

  1. Iptables命令
iptables -t nat -A PREROUTING -p tcp -d 172.20.9.80 -i eth0  --sport 1024:65535 --dport 21 -j DNAT --to-destination 192.168.1.100:21
  1. 源码分析
    1. 主函数
int
 main(int argc, char *argv[])
 {
     int ret;
     char *table = "filter"; //默认表,如果没-t选项,则默认将对filter表进行操作
     struct iptc_handle *handle = NULL;

     iptables_globals.program_name = "iptables";
     ret = xtables_init_all(&iptables_globals, NFPROTO_IPV4);
     if (ret < 0) {
         fprintf(stderr, "%s/%s Failed to initialize xtables\n",
                 iptables_globals.program_name,
                 iptables_globals.program_version);
                 exit(1);
     }
 #if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
     init_extensions();
 #endif

     ret = do_command(argc, argv, &table, &handle);
     if (ret) {
         ret = iptc_commit(handle);
         iptc_free(handle);
     }

     if (!ret) {
         if (errno == EINVAL) {
             fprintf(stderr, "iptables: %s. "
                     "Run `dmesg' for more information.\n",
                 iptc_strerror(errno));
         } else {
             fprintf(stderr, "iptables: %s.\n",
                 iptc_strerror(errno));
         }
         if (errno == EAGAIN) {
             exit(RESOURCE_PROBLEM);
         }
     }

     exit(!ret);
 }
  1. do_command
  1. 源代码

1316: int do_command(int argc, char *argv[], char **table, struct iptc_handle **handle)
1317: {
1318: struct ipt_entry fw, *e = NULL;
1319: int invert = 0;
1320: unsigned int nsaddrs = 0, ndaddrs = 0;
1321: struct in_addr *saddrs = NULL, *smasks = NULL;
1322: struct in_addr *daddrs = NULL, *dmasks = NULL;
1323:
1324: int c, verbose = 0;
1325: const char *chain = NULL;
1326: const char *shostnetworkmask = NULL, *dhostnetworkmask = NULL;
1327: const char *policy = NULL, *newname = NULL;
1328: unsigned int rulenum = 0, options = 0, command = 0;
1329: const char *pcnt = NULL, *bcnt = NULL;
1330: int ret = 1;
1331: struct xtables_match *m;
1332: struct xtables_rule_match *matches = NULL;
1333: struct xtables_rule_match *matchp;
1334: struct xtables_target *target = NULL;
1335: struct xtables_target *t;
1336: const char *jumpto = "";
1337: char *protocol = NULL;
1338: int proto_used = 0;
1339: unsigned long long cnt;
1340:
1341: memset(&fw, 0, sizeof(fw));
1342:
1343: /* re-set optind to 0 in case do_command gets called
1344: * a second time */

1345: optind = 0;
1346:
1347: /* clear mflags in case do_command gets called a second time
1348: * (we clear the global list of all matches for security)*/

1349: for (m = xtables_matches; m; m = m->next)
1350: m->mflags = 0;
1351:
1352: for (t = xtables_targets; t; t = t->next) {
1353: t->tflags = 0;
1354: t->used = 0;
1355: }
1356:
1357: /* Suppress error messages: we may add new options if we
1358: demand-load a protocol. */

1359: opterr = 0;
1360:
1361: while ((c = getopt_long(argc, argv,
1362: "-A:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvnt:m:xc:g:",
1363: opts, NULL)) != -1) {
1364: switch (c) {
1365: /*
1366: * Command selection
1367: */

1368: case 'A':
1369: add_command(&command, CMD_APPEND, CMD_NONE,
1370: invert);
1371: chain = optarg;
1372: break;
1373:
......
1516: /*
1517: * Option selection
1518: */

1519: case 'p':
1520: xtables_check_inverse(optarg, &invert, &optind, argc, argv);
1521: set_option(&options, OPT_PROTOCOL, &fw.ip.invflags,
1522: invert);
1523:
1524: /* Canonicalize into lower case */
1525: for (protocol = optarg; *protocol; protocol++)
1526: *protocol = tolower(*protocol);
1527:
1528: protocol = optarg;
1529: fw.ip.proto = xtables_parse_protocol(protocol);
1530:
1531: if (fw.ip.proto == 0
1532: && (fw.ip.invflags & IPT_INV_PROTO))
1533: xtables_error(PARAMETER_PROBLEM,
1534: "rule would never match protocol");
1535: break;
1536:
......
1544: case 'd':
1545: xtables_check_inverse(optarg, &invert, &optind, argc, argv);
1546: set_option(&options, OPT_DESTINATION, &fw.ip.invflags,
1547: invert);
1548: dhostnetworkmask = optarg;
1549: break;
1550:
......
1559:
1560: case 'j':
1561: set_option(&options, OPT_JUMP, &fw.ip.invflags,
1562: invert);
1563: jumpto = parse_target(optarg);
1564: /* TRY_LOAD (may be chain name) */
1565: target = xtables_find_target(jumpto, XTF_TRY_LOAD);
1566:
1567: if (target) {
1568: size_t size;
1569:
1570: size = IPT_ALIGN(sizeof(struct ipt_entry_target))
1571: + target->size;
1572:
1573: target->t = xtables_calloc(1, size);
1574: target->t->u.target_size = size;
1575: strcpy(target->t->u.user.name, jumpto);
1576: xtables_set_revision(target->t->u.user.name,
1577: target->revision);
1578: if (target->init != NULL)
1579: target->init(target->t);
1580: opts = xtables_merge_options(opts,
1581: target->extra_opts,
1582: &target->option_offset);
1583: if (opts == NULL)
1584: xtables_error(OTHER_PROBLEM,
1585: "can't alloc memory!");
1586: }
1587: break;
1588:
1589:
1590: case 'i':
1591: xtables_check_inverse(optarg, &invert, &optind, argc, argv);
1592: set_option(&options, OPT_VIANAMEIN, &fw.ip.invflags,
1593: invert);
1594: xtables_parse_interface(optarg,
1595: fw.ip.iniface,
1596: fw.ip.iniface_mask);
1597: break;
1598:
......
1655: case 't':
1656: if (invert)
1657: xtables_error(PARAMETER_PROBLEM,
1658: "unexpected ! flag before --table");
1659: *table = optarg;
1660: break;
1661:
......
1726:
1727: default:
1728: if (target == NULL || target->parse == NULL ||
1729: !target->parse(c - target->option_offset,
1730: argv, invert,
1731: &target->tflags,
1732: &fw, &target->t)) {
1733: for (matchp = matches; matchp; matchp = matchp->next) {
1734: if (matchp->completed ||
1735: matchp->match->parse == NULL)
1736: continue;
1737: if (matchp->match->parse(c - matchp->match->option_offset,
1738: argv, invert,
1739: &matchp->match->mflags,
1740: &fw,
1741: &matchp->match->m))
1742: break;
1743: }
1744: m = matchp ? matchp->match : NULL;
1745:
1746: /* If you listen carefully, you can
1747: actually hear this code suck. */

1748:
1749: /* some explanations (after four different bugs
1750: * in 3 different releases): If we encounter a
1751: * parameter, that has not been parsed yet,
1752: * it's not an option of an explicitly loaded
1753: * match or a target. However, we support
1754: * implicit loading of the protocol match
1755: * extension. '-p tcp' means 'l4 proto 6' and
1756: * at the same time 'load tcp protocol match on
1757: * demand if we specify --dport'.
1758: *
1759: * To make this work, we need to make sure:
1760: * - the parameter has not been parsed by
1761: * a match (m above)
1762: * - a protocol has been specified
1763: * - the protocol extension has not been
1764: * loaded yet, or is loaded and unused
1765: * [think of iptables-restore!]
1766: * - the protocol extension can be successively
1767: * loaded
1768: */

1769: if (m == NULL
1770: && protocol
1771: && (!find_proto(protocol, XTF_DONT_LOAD,
1772: options&OPT_NUMERIC, NULL)
1773: || (find_proto(protocol, XTF_DONT_LOAD,
1774: options&OPT_NUMERIC, NULL)
1775: && (proto_used == 0))
1776: )
1777: && (m = find_proto(protocol, XTF_TRY_LOAD,
1778: options&OPT_NUMERIC, &matches))) {
1779: /* Try loading protocol */
1780: size_t size;
1781:
1782: proto_used = 1;
1783:
1784: size = IPT_ALIGN(sizeof(struct ipt_entry_match))
1785: + m->size;
1786:
1787: m->m = xtables_calloc(1, size);
1788: m->m->u.match_size = size;
1789: strcpy(m->m->u.user.name, m->name);
1790: xtables_set_revision(m->m->u.user.name,
1791: m->revision);
1792: if (m->init != NULL)
1793: m->init(m->m);
1794:
1795: opts = xtables_merge_options(opts,
1796: m->extra_opts,
1797: &m->option_offset);
1798: if (opts == NULL)
1799: xtables_error(OTHER_PROBLEM,
1800: "can't alloc memory!");
1801:
1802: optind--;
1803: continue;
1804: }
1805: if (!m) {
1806: if (c == '?') {
1807: if (optopt) {
1808: xtables_error(
1809: PARAMETER_PROBLEM,
1810: "option `%s' "
1811: "requires an "
1812: "argument",
1813: argv[optind-1]);
1814: } else {
1815: xtables_error(
1816: PARAMETER_PROBLEM,
1817: "unknown option "
1818: "`%s'",
1819: argv[optind-1]);
1820: }
1821: }
1822: xtables_error(PARAMETER_PROBLEM,
1823: "Unknown arg `%s'", optarg);
1824: }
1825: }
1826: }
1827: invert = FALSE;
1828: }
1829:
1830: if (strcmp(*table, "nat") == 0 &&
1831: ((policy != NULL && strcmp(policy, "DROP") == 0) ||
1832: (jumpto != NULL && strcmp(jumpto, "DROP") == 0)))
1833: xtables_error(PARAMETER_PROBLEM,
1834: "\nThe \"nat\" table is not intended for filtering, "
1835: "the use of DROP is therefore inhibited.\n\n");
1836:
1837: for (matchp = matches; matchp; matchp = matchp->next)
1838: if (matchp->match->final_check != NULL)
1839: matchp->match->final_check(matchp->match->mflags);
1840:
1841: if (target != NULL && target->final_check != NULL)
1842: target->final_check(target->tflags);
1843:
1844: /* Fix me: must put inverse options checking here --MN */
1845:
1846: if (optind < argc)
1847: xtables_error(PARAMETER_PROBLEM,
1848: "unknown arguments found on commandline");
1849: if (!command)
1850: xtables_error(PARAMETER_PROBLEM, "no command specified");
1851: if (invert)
1852: xtables_error(PARAMETER_PROBLEM,
1853: "nothing appropriate following !");
1854:
1855: if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND)) {
1856: if (!(options & OPT_DESTINATION))
1857: dhostnetworkmask = "0.0.0.0/0";
1858: if (!(options & OPT_SOURCE))
1859: shostnetworkmask = "0.0.0.0/0";
1860: }
1861:
1862: if (shostnetworkmask)
1863: xtables_ipparse_multiple(shostnetworkmask, &saddrs,
1864: &smasks, &nsaddrs);
1865:
1866: if (dhostnetworkmask)
1867: xtables_ipparse_multiple(dhostnetworkmask, &daddrs,
1868: &dmasks, &ndaddrs);
1869:
1870: if ((nsaddrs > 1 || ndaddrs > 1) &&
1871: (fw.ip.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP)))
1872: xtables_error(PARAMETER_PROBLEM, "! not allowed with multiple"
1873: " source or destination IP addresses");
1874:
1875: if (command == CMD_REPLACE && (nsaddrs != 1 || ndaddrs != 1))
1876: xtables_error(PARAMETER_PROBLEM, "Replacement rule does not "
1877: "specify a unique address");
1878:
1879: generic_opt_check(command, options);
1880:
1881: if (chain && strlen(chain) > IPT_FUNCTION_MAXNAMELEN)
1882: xtables_error(PARAMETER_PROBLEM,
1883: "chain name `%s' too long (must be under %i chars)",
1884: chain, IPT_FUNCTION_MAXNAMELEN);
1885:
1886: /* only allocate handle if we weren't called with a handle */
1887: if (!*handle)
1888: *handle = iptc_init(*table);
1889:
1890: /* try to insmod the module if iptc_init failed */
1891: if (!*handle && xtables_load_ko(xtables_modprobe_program, false) != -1)
1892: *handle = iptc_init(*table);
1893:
1894: if (!*handle)
1895: xtables_error(VERSION_PROBLEM,
1896: "can't initialize iptables table `%s': %s",
1897: *table, iptc_strerror(errno));
1898:
1899: if (command == CMD_APPEND
1900: || command == CMD_DELETE
1901: || command == CMD_INSERT
1902: || command == CMD_REPLACE) {
1903: if (strcmp(chain, "PREROUTING") == 0
1904: || strcmp(chain, "INPUT") == 0) {
1905: /* -o not valid with incoming packets. */
1906: if (options & OPT_VIANAMEOUT)
1907: xtables_error(PARAMETER_PROBLEM,
1908: "Can't use -%c with %s\n",
1909: opt2char(OPT_VIANAMEOUT),
1910: chain);
1911: }
1912:
1913: if (strcmp(chain, "POSTROUTING") == 0
1914: || strcmp(chain, "OUTPUT") == 0) {
1915: /* -i not valid with outgoing packets */
1916: if (options & OPT_VIANAMEIN)
1917: xtables_error(PARAMETER_PROBLEM,
1918: "Can't use -%c with %s\n",
1919: opt2char(OPT_VIANAMEIN),
1920: chain);
1921: }
1922:
1923: if (target && iptc_is_chain(jumpto, *handle)) {
1924: fprintf(stderr,
1925: "Warning: using chain %s, not extension\n",
1926: jumpto);
1927:
1928: if (target->t)
1929: free(target->t);
1930:
1931: target = NULL;
1932: }
1933:
1934: /* If they didn't specify a target, or it's a chain
1935: name, use standard. */

1936: if (!target
1937: && (strlen(jumpto) == 0
1938: || iptc_is_chain(jumpto, *handle))) {
1939: size_t size;
1940:
1941: target = xtables_find_target(IPT_STANDARD_TARGET,
1942: XTF_LOAD_MUST_SUCCEED);
1943:
1944: size = sizeof(struct ipt_entry_target)
1945: + target->size;
1946: target->t = xtables_calloc(1, size);
1947: target->t->u.target_size = size;
1948: strcpy(target->t->u.user.name, jumpto);
1949: if (!iptc_is_chain(jumpto, *handle))
1950: xtables_set_revision(target->t->u.user.name,
1951: target->revision);
1952: if (target->init != NULL)
1953: target->init(target->t);
1954: }
1955:
1956: if (!target) {
1957: /* it is no chain, and we can't load a plugin.
1958: * We cannot know if the plugin is corrupt, non
1959: * existant OR if the user just misspelled a
1960: * chain. */

1961: #ifdef IPT_F_GOTO
1962: if (fw.ip.flags & IPT_F_GOTO)
1963: xtables_error(PARAMETER_PROBLEM,
1964: "goto '%s' is not a chain\n", jumpto);
1965: #endif
1966: xtables_find_target(jumpto, XTF_LOAD_MUST_SUCCEED);
1967: } else {
1968: e = generate_entry(&fw, matches, target->t);
1969: free(target->t);
1970: }
1971: }
1972:
1973: switch (command) {
1974: case CMD_APPEND:
1975: ret = append_entry(chain, e,
1976: nsaddrs, saddrs, smasks,
1977: ndaddrs, daddrs, dmasks,
1978: options&OPT_VERBOSE,
1979: *handle);
1980: break;
1981: case CMD_DELETE:
1982: ret = delete_entry(chain, e,
1983: nsaddrs, saddrs, smasks,
1984: ndaddrs, daddrs, dmasks,
1985: options&OPT_VERBOSE,
1986: *handle, matches, target);
1987: break;
1988: case CMD_DELETE_NUM:
1989: ret = iptc_delete_num_entry(chain, rulenum - 1, *handle);
1990: break;
1991: case CMD_REPLACE:
1992: ret = replace_entry(chain, e, rulenum - 1,
1993: saddrs, smasks, daddrs, dmasks,
1994: options&OPT_VERBOSE, *handle);
1995: break;
1996: case CMD_INSERT:
1997: ret = insert_entry(chain, e, rulenum - 1,
1998: nsaddrs, saddrs, smasks,
1999: ndaddrs, daddrs, dmasks,
2000: options&OPT_VERBOSE,
2001: *handle);
2002: break;
2003: case CMD_FLUSH:
2004: ret = flush_entries(chain, options&OPT_VERBOSE, *handle);
2005: break;
2006: case CMD_ZERO:
2007: ret = zero_entries(chain, options&OPT_VERBOSE, *handle);
2008: break;
2009: case CMD_ZERO_NUM:
2010: ret = iptc_zero_counter(chain, rulenum, *handle);
2011: break;
2012: case CMD_LIST:
2013: case CMD_LIST|CMD_ZERO:
2014: case CMD_LIST|CMD_ZERO_NUM:
2015: ret = list_entries(chain,
2016: rulenum,
2017: options&OPT_VERBOSE,
2018: options&OPT_NUMERIC,
2019: options&OPT_EXPANDED,
2020: options&OPT_LINENUMBERS,
2021: *handle);
2022: if (ret && (command & CMD_ZERO))
2023: ret = zero_entries(chain,
2024: options&OPT_VERBOSE, *handle);
2025: if (ret && (command & CMD_ZERO_NUM))
2026: ret = iptc_zero_counter(chain, rulenum, *handle);
2027: break;
2028: case CMD_LIST_RULES:
2029: case CMD_LIST_RULES|CMD_ZERO:
2030: case CMD_LIST_RULES|CMD_ZERO_NUM:
2031: ret = list_rules(chain,
2032: rulenum,
2033: options&OPT_VERBOSE,
2034: *handle);
2035: if (ret && (command & CMD_ZERO))
2036: ret = zero_entries(chain,
2037: options&OPT_VERBOSE, *handle);
2038: if (ret && (command & CMD_ZERO_NUM))
2039: ret = iptc_zero_counter(chain, rulenum, *handle);
2040: break;
2041: case CMD_NEW_CHAIN:
2042: ret = iptc_create_chain(chain, *handle);
2043: break;
2044: case CMD_DELETE_CHAIN:
2045: ret = delete_chain(chain, options&OPT_VERBOSE, *handle);
2046: break;
2047: case CMD_RENAME_CHAIN:
2048: ret = iptc_rename_chain(chain, newname, *handle);
2049: break;
2050: case CMD_SET_POLICY:
2051: ret = iptc_set_policy(chain, policy, options&OPT_COUNTERS ? &fw.counters : NULL, *handle);
2052: break;
2053: default:
2054: /* We should never reach this... */
2055: exit_tryhelp(2);
2056: }
2057:
2058: if (verbose > 1)
2059: dump_entries(*handle);
2060:
2061: clear_rule_matches(&matches);
2062:
2063: if (e != NULL) {
2064: free(e);
2065: e = NULL;
2066: }
2067:
2068: free(saddrs);
2069: free(smasks);
2070: free(daddrs);
2071: free(dmasks);
2072: xtables_free_opts(1);
2073:
2074: return ret;
2075: }
2076:

      1. Big pictures




    下一部分将重点分析图中重点标的函数,以及最终由该条命令生成的数据结构,这些结构将用于数据包到达后在相应的HOOK上做相关查询。
阅读(1293) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~