Exemple #1
0
libnet_ptag_t
libnet_build_tcp(u_int16_t sp, u_int16_t dp, u_int32_t seq, u_int32_t ack,
u_int8_t control, u_int16_t win, u_int16_t sum, u_int16_t urg, u_int16_t len,
u_int8_t *payload, u_int32_t payload_s, libnet_t *l, libnet_ptag_t ptag)
{
    int n, offset;
    u_int32_t i, j;
    libnet_pblock_t *p, *p_data, *p_temp;
    libnet_ptag_t ptag_hold, ptag_data;
    struct libnet_tcp_hdr tcp_hdr;
    struct libnet_ipv4_hdr *ip_hdr;

    if (l == NULL)
    { 
        return (-1);
    } 

    ptag_data = 0;                      /* for possible options */

    /*
     *  Find the existing protocol block if a ptag is specified, or create
     *  a new one.
     */
    p = libnet_pblock_probe(l, ptag, LIBNET_TCP_H, LIBNET_PBLOCK_TCP_H);
    if (p == NULL)
    {
        return (-1);
    }

    memset(&tcp_hdr, 0, sizeof(tcp_hdr));
    tcp_hdr.th_sport   = htons(sp);    /* source port */
    tcp_hdr.th_dport   = htons(dp);    /* destination port */
    tcp_hdr.th_seq     = htonl(seq);   /* sequence number */
    tcp_hdr.th_ack     = htonl(ack);   /* acknowledgement number */
    tcp_hdr.th_flags   = control;      /* control flags */
    tcp_hdr.th_x2      = 0;            /* UNUSED */
    tcp_hdr.th_off     = 5;            /* 20 byte header */

    /* check to see if there are TCP options to include */
    if (p->prev)
    {
        p_temp = p->prev;
        while ((p_temp->prev) && (p_temp->type != LIBNET_PBLOCK_TCPO_H))
        {
            p_temp = p_temp->prev;
        }
        if (p_temp->type == LIBNET_PBLOCK_TCPO_H)
        {
            /*
             *  Count up number of 32-bit words in options list, padding if
             *  neccessary.
             */
            for (i = 0, j = 0; i < p_temp->b_len; i++)
            {
                (i % 4) ? j : j++;
            }
            tcp_hdr.th_off += j;
        }
    }

    tcp_hdr.th_win     = htons(win);   /* window size */
    tcp_hdr.th_sum     = (sum ? htons(sum) : 0);   /* checksum */ 
    tcp_hdr.th_urp     = htons(urg);          /* urgent pointer */

    n = libnet_pblock_append(l, p, (u_int8_t *)&tcp_hdr, LIBNET_TCP_H);
    if (n == -1)
    {
        goto bad;
    }

    ptag_hold = ptag;
    if (ptag == LIBNET_PTAG_INITIALIZER)
    {
        ptag = libnet_pblock_update(l, p, len, LIBNET_PBLOCK_TCP_H);
    }

    /* find and set the appropriate ptag, or else use the default of 0 */
    offset = payload_s;
    if (ptag_hold && p->prev)
    {
        p_temp = p->prev;
        while (p_temp->prev &&
              (p_temp->type != LIBNET_PBLOCK_TCPDATA) &&
              (p_temp->type != LIBNET_PBLOCK_TCP_H))
        {
           p_temp = p_temp->prev;
        }

        if (p_temp->type == LIBNET_PBLOCK_TCPDATA)
        {
            ptag_data = p_temp->ptag;
            offset -=  p_temp->b_len;
            p->h_len += offset;
        }
        else
        {
            snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
				    "%s(): TCP data pblock not found\n", __func__);
        }
     }

    /* update ip_len if present */
    if (ptag_hold && p->next)
    {
        p_temp = p->next;
        while (p_temp->next && (p_temp->type != LIBNET_PBLOCK_IPV4_H))
        {
            p_temp = p_temp->next;
        }
        if (p_temp->type == LIBNET_PBLOCK_IPV4_H)
        {
            ip_hdr = (struct libnet_ipv4_hdr *)p_temp->buf;
            n = ntohs(ip_hdr->ip_len) + offset;
            ip_hdr->ip_len = htons(n);
        }
    }

    if ((payload && !payload_s) || (!payload && payload_s))
    {
        snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
			    "%s(): payload inconsistency\n", __func__);
        goto bad;
    }

    /* if there is a payload, add it in the context */
    if (payload && payload_s)
    {
        /* update ptag_data with the new payload */
        p_data = libnet_pblock_probe(l, ptag_data, payload_s,
                LIBNET_PBLOCK_TCPDATA);
        if (p_data == NULL) 
        {
            return (-1);
        }

        if (libnet_pblock_append(l, p_data, payload, payload_s) == -1)
        {
            goto bad;
        }

        if (ptag_data == LIBNET_PTAG_INITIALIZER)
        {
            if (p_data->prev->type == LIBNET_PBLOCK_TCP_H)
            {
                libnet_pblock_update(l, p_data, payload_s,
                        LIBNET_PBLOCK_TCPDATA);
                /* swap pblocks to correct the protocol order */
                libnet_pblock_swap(l, p->ptag, p_data->ptag);
            }
            else
            {
                /* update without setting this as the final pblock */
                p_data->type  =  LIBNET_PBLOCK_TCPDATA;
                p_data->ptag  =  ++(l->ptag_state);
                p_data->h_len =  payload_s;

                /* Adjust h_len for checksum. */
                p->h_len += payload_s;

                /* data was added after the initial construction */
                for (p_temp = l->protocol_blocks;
                        p_temp->type == LIBNET_PBLOCK_TCP_H ||
                        p_temp->type == LIBNET_PBLOCK_TCPO_H;
                        p_temp = p_temp->next)
                {
                    libnet_pblock_insert_before(l, p_temp->ptag, p_data->ptag);
                    break;
                }
                /* The end block needs to have its next pointer cleared. */
                l->pblock_end->next = NULL;
            }

            if (p_data->prev && p_data->prev->type == LIBNET_PBLOCK_TCPO_H)
            {
                libnet_pblock_swap(l, p_data->prev->ptag, p_data->ptag);
            }
        }
    }
    else
    {
        p_data = libnet_pblock_find(l, ptag_data);
        if (p_data) 
        {
            libnet_pblock_delete(l, p_data);
        }
    }

    if (sum == 0)
    {
        /*
         *  If checksum is zero, by default libnet will compute a checksum
         *  for the user.  The programmer can override this by calling
         *  libnet_toggle_checksum(l, ptag, 1);
         */
        libnet_pblock_setflags(p, LIBNET_PBLOCK_DO_CHECKSUM);
    }
    return (ptag);
bad:
    libnet_pblock_delete(l, p);
    return (-1);
}
Exemple #2
0
/*-
-- ptag = n:ipv4{
    -- required arguments
      src=ipaddr,
      dst=ipaddr,
      protocol=int,
    -- optional arguments
      ptag=int,
      payload=str,
      options=ip_options,
      len=int, -- default is correct length
      tos=int,
      id=int,
      frag=int,
      ttl=int, -- defaults to 64
  }

ptag is optional, defaults to creating a new protocol block
options is optional
*/
static int lnet_ipv4 (lua_State *L)
{
    libnet_t* ud = checkudata(L);
    const char* src = v_arg_string(L, 2, "src");
    const char* dst = v_arg_string(L, 2, "dst");
    uint32_t src_n = check_ip_pton(L, src, "src");
    uint32_t dst_n = check_ip_pton(L, dst, "dst");
    int protocol = v_arg_integer(L, 2, "protocol"); /* TODO make optional */
    int ptag = lnet_arg_ptag(L, ud, 2, LIBNET_PBLOCK_IPV4_H);
    uint32_t payloadsz = 0;
    const uint8_t* payload = checkpayload(L, 2, &payloadsz);
    int options_ptag = 0;
    uint32_t optionsz = 0;
    const uint8_t* options = checklbuffer(L, 2, "options", &optionsz);
    int len = v_arg_integer_opt(L, 2, "len", -1);
    int tos = v_arg_integer_opt(L, 2, "tos", 0);
    int id = v_arg_integer_opt(L, 2, "id", 0);
    int frag = v_arg_integer_opt(L, 2, "frag", 0);
    int ttl = v_arg_integer_opt(L, 2, "ttl", 64);
    int cksum = 0; /* 0 is a flag requesting libnet to fill in correct cksum */
    libnet_pblock_t* oblock = NULL;

#ifdef NET_DUMP
    printf("net ipv4 src %s dst %s len %d payloadsz %lu ptag %d optionsz %lu\n", src, dst, len, payloadsz, ptag, optionsz);
#endif

    oblock = ptag ? libnet_pblock_find(ud, ptag)->prev : ud->pblock_end;

    if(!oblock || oblock->type != LIBNET_PBLOCK_IPO_H)
      oblock = NULL;
    else
      options_ptag = oblock->ptag;

#ifdef NET_DUMP
    printf("  options_ptag %d optionsz from %lu to %lu\n",
            options_ptag, oblock ? oblock->b_len : 0, optionsz);
#endif

    /* Two initial states possible:
     *   - has prev ip options block, or not
     * Two final states desired:
     *   - has prev ip options block, or not
     */

    if(!options) {
      libnet_pblock_delete(ud, oblock);
    } else {
      options_ptag = libnet_build_ipv4_options(options, optionsz, ud, options_ptag);

      check_error(L, ud, options_ptag);

      if(oblock) {
	/* we replaced an existing block that was correctly placed */
      } else if(ptag) {
	libnet_pblock_insert_before(ud, ptag, options_ptag);
      } else {
          /* we just pushed a new options block, and are about to push a new ip block */
      }
    }

    /* If len unspecified, rewrite it to be len of ipv4 pblock + previous blocks. */
    /* FIXME I don't think defaulting to end is correct

-- libnet doesn't have a generic icmp construction api, see bug#1373
local function build_icmp(n, icmp)
    local typecode = string.char(assert(icmp.type), assert(icmp.code))
    local data = icmp.data or ""
    local checksum = net.checksum(typecode, "\0\0", data)
    local packet = typecode..checksum..data

    return n:ipv4{
        src      = arg.localip,
        dst      = arg.dutip,
        protocol = 1, -- ICMP is protocol 1 FIXME get from iana.ip.types.icmp
        payload  = packet,
        len      = 20 + #packet,
        ptag     = icmp.ptag
    }
end

getmetatable(n).icmp = build_icmp

-- set up the pblock stack, top to bottom
local ptag = n:icmp{type=0, code=0}
n:eth{src=arg.localmac, dst=arg.dutmac}

   n:icmp{ptag=ptag, type=type, code=code, payload=data}

print(n:dump())
print(n:get_ipv4())


~/w/wt/achilles-engine/data/Plugins/Grammar % sudo ./icmp-data-grammar-l2 dutip=1.1.1.1 localdev=lo localip=2.2.2.2 dutmac=11:11:11:11:11:11 localmac=22:22:22:22:22:22 pcap=pc.pcap
tag 2 flags 0 type ipdata/0xf buf 0x6541e0 b_len  4 h_len  4 copied 4 prev -1 next 1
tag 1 flags 1 type ipv4/0xd buf 0x6582f0 b_len 20 h_len 20 copied 20 prev 2 next 3
tag 3 flags 0 type eth/0x4 buf 0x647580 b_len 14 h_len  0 copied 14 prev 1 next -1
link_offset 14 aligner 0 total_size 38 nblocks 3

Total:1
Subtest 1: ICMP type 0 code 1 with payload size 1
tag 2 flags 0 type ipdata/0xf buf 0x6541e0 b_len  4 h_len  4 copied 4 prev -1 next 1
tag 1 flags 1 type ipv4/0xd buf 0x6582f0 b_len 20 h_len 20 copied 20 prev 2 next 3
tag 3 flags 0 type eth/0x4 buf 0x647580 b_len 14 h_len  0 copied 14 prev 1 next -1
link_offset 14 aligner 0 total_size 38 nblocks 3

{
ptag = 1, protocol = 1, _iphl = 5, id = 0, options = "", dst = "1.1.1.1", src = "2.2.2.2", _sum = 0, _ipv = 4, tos = 0, _len = 28, ttl = 64, frag = 0
}


============>> note that _len is 28, it should be 24
    
    */
    if(len < 0) {
        libnet_pblock_t* p = ptag ? libnet_pblock_find(ud, ptag)->prev : ud->pblock_end;

        len = LIBNET_IPV4_H + payloadsz;

        while(p) {
            len += p->b_len;
            p = p->prev;
        }
    }

    ptag = libnet_build_ipv4(
            len, tos, id, frag, ttl, protocol, cksum,
            src_n, dst_n,
            payload, payloadsz,
            ud, ptag);

    check_error(L, ud, ptag);

    lua_pushinteger(L, ptag);

    return 1;
}
Exemple #3
0
libnet_ptag_t
libnet_build_tcp(
            uint16_t sp, uint16_t dp, uint32_t seq, uint32_t ack,
            uint8_t control, uint16_t win, uint16_t sum, uint16_t urg, uint16_t h_len,
            const uint8_t *payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag)
{
    int n, offset;
    libnet_pblock_t *p = NULL;
    libnet_ptag_t ptag_data = 0;
    struct libnet_tcp_hdr tcp_hdr;

    if (l == NULL)
        return -1;

    if (payload_s && !payload)
    {
        snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
			    "%s(): payload inconsistency", __func__);
        return -1;
    }

    p = libnet_pblock_probe(l, ptag, LIBNET_TCP_H, LIBNET_PBLOCK_TCP_H);
    if (p == NULL)
        return -1;

    memset(&tcp_hdr, 0, sizeof(tcp_hdr));
    tcp_hdr.th_sport   = htons(sp);    /* source port */
    tcp_hdr.th_dport   = htons(dp);    /* destination port */
    tcp_hdr.th_seq     = htonl(seq);   /* sequence number */
    tcp_hdr.th_ack     = htonl(ack);   /* acknowledgement number */
    tcp_hdr.th_flags   = control;      /* control flags */
    tcp_hdr.th_x2      = 0;            /* UNUSED */
    tcp_hdr.th_off     = 5;            /* 20 byte header */

    /* check to see if there are TCP options to include */
    if (p->prev && p->prev->type == LIBNET_PBLOCK_TCPO_H)
    {
        /* Note that the tcp options pblock is already padded */
        tcp_hdr.th_off += (p->prev->b_len/4);
    }

    tcp_hdr.th_win     = htons(win);   /* window size */
    tcp_hdr.th_sum     = (sum ? htons(sum) : 0);   /* checksum */ 
    tcp_hdr.th_urp     = htons(urg);          /* urgent pointer */

    n = libnet_pblock_append(l, p, (uint8_t *)&tcp_hdr, LIBNET_TCP_H);
    if (n == -1)
    {
        goto bad;
    }

    if (ptag == LIBNET_PTAG_INITIALIZER)
    {
        libnet_pblock_update(l, p, h_len, LIBNET_PBLOCK_TCP_H);
    }

    offset = payload_s;

    /* If we are going to modify a TCP data block, find it, and figure out the
     * "offset", the possibly negative amount by which we are increasing the ip
     * data length. */
    if (ptag)
    {
        libnet_pblock_t* datablock = p->prev;

        if (datablock && datablock->type == LIBNET_PBLOCK_TCPO_H)
            datablock = datablock->prev;

        if (datablock && datablock->type == LIBNET_PBLOCK_TCPDATA)
        {
            ptag_data = datablock->ptag;
            offset -=  datablock->b_len;
        }
        p->h_len += offset;
    }

    /* If we are modifying a TCP block, we should look forward and apply the offset
     * to our IPv4 header, if we have one.
     */
    if (p->next)
    {
        libnet_pblock_t* ipblock = p->next;

        if(ipblock->type == LIBNET_PBLOCK_IPO_H)
            ipblock = ipblock->next;

        if(ipblock && ipblock->type == LIBNET_PBLOCK_IPV4_H)
        {
            struct libnet_ipv4_hdr * ip_hdr = (struct libnet_ipv4_hdr *)ipblock->buf;
            int ip_len = ntohs(ip_hdr->ip_len) + offset;
            ip_hdr->ip_len = htons(ip_len);
        }
    }

    /* if there is a payload, add it in the context */
    if (payload_s)
    {
        /* update ptag_data with the new payload */
        libnet_pblock_t* p_data = libnet_pblock_probe(l, ptag_data, payload_s, LIBNET_PBLOCK_TCPDATA);
        if (!p_data)
        {
            goto bad;
        }

        n = libnet_pblock_append(l, p_data, payload, payload_s);
        if (n == -1)
        {
            goto bad;
        }

        if (ptag_data == LIBNET_PTAG_INITIALIZER)
        {
            int insertbefore = p->ptag;

            /* Then we created it, and we need to shuffle it back until it's before
             * the tcp header and options. */
            libnet_pblock_update(l, p_data, payload_s, LIBNET_PBLOCK_TCPDATA);

            if(p->prev && p->prev->type == LIBNET_PBLOCK_TCPO_H)
                insertbefore = p->prev->ptag;

            libnet_pblock_insert_before(l, insertbefore, p_data->ptag);
        }
    }
    else
    {
        libnet_pblock_t* p_data = libnet_pblock_find(l, ptag_data);
        libnet_pblock_delete(l, p_data);
    }

    if (sum == 0)
    {
        /*
         *  If checksum is zero, by default libnet will compute a checksum
         *  for the user.  The programmer can override this by calling
         *  libnet_toggle_checksum(l, ptag, 1);
         */
        libnet_pblock_setflags(p, LIBNET_PBLOCK_DO_CHECKSUM);
    }
    return (p->ptag);
bad:
    libnet_pblock_delete(l, p);
    return (-1);
}
Exemple #4
0
/*-
-- ptag = n:tcp{
    -- required arguments
      src=port,
      dst=port,
      seq=int,
      ack=int,
      flags=int,
      win=int,
      urg=int,
    -- optional arguments
      ptag=int,
      payload=str,
      options=tcp_options,
  }

ptag is optional, defaults to creating a new protocol block
options is optional
*/
static int lnet_tcp (lua_State *L)
{
    libnet_t* ud = checkudata(L);
    int src = v_arg_integer(L, 2, "src");
    int dst = v_arg_integer(L, 2, "dst");
    int seq = v_arg_integer(L, 2, "seq");
    int ack = v_arg_integer(L, 2, "ack");
    int flags = v_arg_integer(L, 2, "flags");
    int win = v_arg_integer(L, 2, "win");
    int urg = v_arg_integer(L, 2, "urg");
    int ptag = lnet_arg_ptag(L, ud, 2, LIBNET_PBLOCK_TCP_H);
    uint32_t payloadsz = 0;
    const uint8_t* payload = checkpayload(L, 2, &payloadsz);
    int options_ptag = 0;
    uint32_t optionsz = 0;
    const uint8_t* options = checklbuffer(L, 2, "options", &optionsz);
    int cksum = 0; /* 0 is a flag requesting libnet to fill in correct cksum */
    libnet_pblock_t* oblock = NULL;
    int len = 0; /* libnet needs len for checksum calculation */

    oblock = ptag ? libnet_pblock_find(ud, ptag)->prev : ud->pblock_end;

    if(!oblock || oblock->type != LIBNET_PBLOCK_TCPO_H)
      oblock = NULL;
    else
      options_ptag = oblock->ptag;

    /* Two initial states possible:
     *   - has prev ip options block, or not
     * Two final states desired:
     *   - has prev ip options block, or not
     */

    if(!options) {
      libnet_pblock_delete(ud, oblock);
    } else {
      options_ptag = libnet_build_tcp_options(options, optionsz, ud, options_ptag);

      check_error(L, ud, options_ptag);

      if(oblock) {
	/* we replaced an existing block that was correctly placed */
      } else if(ptag) {
	libnet_pblock_insert_before(ud, ptag, options_ptag);
      } else {
          /* we just pushed a new options block, and are about to push a new ip block */
      }
    }

    /* Rewrite len to be len of tcp pblock + previous blocks. */
    {
        libnet_pblock_t* p = ptag ? libnet_pblock_find(ud, ptag)->prev : ud->pblock_end;

        len = LIBNET_TCP_H + payloadsz;

        while(p) {
            /* don't count tcpdata pblock... we will replace it payloadsz data below */
            if(p->type != LIBNET_PBLOCK_TCPDATA)
                len += p->b_len;
            p = p->prev;
        }
    }

    ptag = libnet_build_tcp(
            src, dst, seq, ack, flags, win, cksum, urg,
            len,
            payload, payloadsz,
            ud, ptag);

    check_error(L, ud, ptag);

    lua_pushinteger(L, ptag);

    return 1;
}