/* function: tcp_translate
 * common between ipv4/ipv6 - setup checksum and send tcp packet
 * fd           - tun interface fd
 * tcp          - source packet tcp header
 * payload      - tcp payload
 * payload_size - size of payload
 * io_targ      - iovec with tun and ipv4/ipv6 header (see below)
 *     array position 0 - tun header
 *     array position 1 - ipv4/ipv6 header
 *     array position 2 - empty (will be tcp header)
 *     array position 3 - empty (will be tcp options or payload)
 *     array position 4 - empty (can be payload)
 * checksum     - partial checksum covering ipv4/ipv6 header
 * options      - pointer to tcp option buffer
 * options_size - size of tcp option buffer
 *
 * TODO: mss rewrite
 * TODO: hosts without pmtu discovery - non DF packets will rely on fragmentation (unimplemented)
 */
void tcp_translate(int fd, const struct tcphdr *tcp, const char *payload, size_t payload_size, struct iovec *io_targ, uint32_t checksum, const char *options, size_t options_size) {
  struct tcphdr tcp_targ;
  int targ_index = 2;

  memcpy(&tcp_targ, tcp, sizeof(tcp_targ));
  tcp_targ.check = 0;

  checksum = ip_checksum_add(checksum, &tcp_targ, sizeof(tcp_targ));
  checksum = ip_checksum_add(checksum, payload, payload_size);
  if(options) {
    checksum = ip_checksum_add(checksum, options, options_size);
  }
  tcp_targ.check = ip_checksum_finish(checksum);

  io_targ[targ_index].iov_base = &tcp_targ;
  io_targ[targ_index].iov_len = sizeof(tcp_targ);
  targ_index++;

  if(options) {
    io_targ[targ_index].iov_base = (char *)options;
    io_targ[targ_index].iov_len = options_size;
    targ_index++;
  }

  io_targ[targ_index].iov_base = (char *)payload;
  io_targ[targ_index].iov_len = payload_size;
  targ_index++;

  writev(fd, io_targ, targ_index);
}
Esempio n. 2
0
/* print udp header */
void dump_udp_generic(const struct udphdr *udp, uint32_t temp_checksum, const char *payload, size_t payload_size) {
  uint16_t my_checksum;

  temp_checksum = ip_checksum_add(temp_checksum, udp, sizeof(struct udphdr));
  temp_checksum = ip_checksum_add(temp_checksum, payload, payload_size);
  my_checksum = ip_checksum_finish(temp_checksum);

  printf("UDP\n");
  printf("source = %x\n",ntohs(udp->source));
  printf("dest = %x\n",ntohs(udp->dest));
  printf("len = %x\n",ntohs(udp->len));
  printf("check = %x (mine %x)\n",udp->check,my_checksum);
}
/* function: udp_translate
 * common between ipv4/ipv6 - setup checksum and send udp packet
 * fd           - tun interface fd
 * udp          - source packet udp header
 * payload      - udp payload
 * payload_size - size of payload
 * io_targ      - iovec with tun and ipv4/ipv6 header (see below)
 *     array position 0 - tun header
 *     array position 1 - ipv4/ipv6 header
 *     array position 2 - empty (will be udp header)
 *     array position 3 - empty (will be payload)
 * checksum     - partial checksum covering ipv4/ipv6 header
 */
void udp_translate(int fd, const struct udphdr *udp, const char *payload, size_t payload_size, struct iovec *io_targ, uint32_t checksum) {
  struct udphdr udp_targ;

  memcpy(&udp_targ, udp, sizeof(udp_targ));
  udp_targ.check = 0; // reset checksum, to be calculated

  checksum = ip_checksum_add(checksum, &udp_targ, sizeof(struct udphdr));
  checksum = ip_checksum_add(checksum, payload, payload_size);
  udp_targ.check = ip_checksum_finish(checksum);

  io_targ[2].iov_base = &udp_targ;
  io_targ[2].iov_len = sizeof(udp_targ);
  io_targ[3].iov_base = (char *)payload;
  io_targ[3].iov_len = payload_size;

  writev(fd, io_targ, 4);
}
Esempio n. 4
0
/* function: packet_checksum
 * calculates the checksum over all the packet components starting from pos
 * checksum - checksum of packet components before pos
 * packet   - packet to calculate the checksum of
 * pos      - position to start counting from
 * returns  - the completed 16-bit checksum, ready to write into a checksum header field
 */
uint16_t packet_checksum(uint32_t checksum, clat_packet packet, clat_packet_index pos) {
  int i;
  for (i = pos; i < CLAT_POS_MAX; i++) {
    if (packet[i].iov_len > 0) {
      checksum = ip_checksum_add(checksum, packet[i].iov_base, packet[i].iov_len);
    }
  }
  return ip_checksum_finish(checksum);
}
/* function: icmp_to_icmp6
 * translate ipv4 icmp to ipv6 icmp
 * fd           - tun interface fd
 * ip           - source packet ipv4 header
 * icmp         - source packet icmp header
 * payload      - icmp payload
 * payload_size - size of payload
 */
void icmp_to_icmp6(int fd, const struct iphdr *ip, const struct icmphdr *icmp, const char *payload, size_t payload_size) {
  struct ip6_hdr ip6_targ;
  struct icmp6_hdr icmp6_targ;
  struct iovec io_targ[4];
  struct tun_pi tun_header;
  uint32_t checksum_temp;

  if(icmp->type != ICMP_ECHO && icmp->type != ICMP_ECHOREPLY) {
#if CLAT_DEBUG
    logmsg(ANDROID_LOG_WARN,"icmp_to_icmp6/unhandled icmp type: 0x%x",icmp->type);
#endif
    return;
  }

  fill_tun_header(&tun_header,ETH_P_IPV6);

  fill_ip6_header(&ip6_targ,payload_size + sizeof(icmp6_targ),IPPROTO_ICMPV6,ip);

  memset(&icmp6_targ, 0, sizeof(icmp6_targ));
  icmp6_targ.icmp6_type = (icmp->type == ICMP_ECHO) ? ICMP6_ECHO_REQUEST : ICMP6_ECHO_REPLY;
  icmp6_targ.icmp6_code = 0;
  icmp6_targ.icmp6_cksum = 0;
  icmp6_targ.icmp6_id = icmp->un.echo.id;
  icmp6_targ.icmp6_seq = icmp->un.echo.sequence;

  checksum_temp = ipv6_pseudo_header_checksum(0,&ip6_targ);
  checksum_temp = ip_checksum_add(checksum_temp,&icmp6_targ,sizeof(icmp6_targ));
  checksum_temp = ip_checksum_add(checksum_temp,payload,payload_size);
  icmp6_targ.icmp6_cksum = ip_checksum_finish(checksum_temp);

  io_targ[0].iov_base = &tun_header;
  io_targ[0].iov_len = sizeof(tun_header);
  io_targ[1].iov_base = &ip6_targ;
  io_targ[1].iov_len = sizeof(ip6_targ);
  io_targ[2].iov_base = &icmp6_targ;
  io_targ[2].iov_len = sizeof(icmp6_targ);
  io_targ[3].iov_base = (char *)payload;
  io_targ[3].iov_len = payload_size;

  writev(fd, io_targ, 4);
}
/* function: icmp6_to_icmp
 * translate ipv6 icmp to ipv4 icmp
 * fd           - tun interface fd
 * ip6          - source packet ipv6 header
 * icmp6        - source packet icmp6 header
 * payload      - icmp6 payload
 * payload_size - size of payload
 */
void icmp6_to_icmp(int fd, const struct ip6_hdr *ip6, const struct icmp6_hdr *icmp6, const char *payload, size_t payload_size) {
  struct iphdr ip_targ;
  struct icmphdr icmp_targ;
  struct iovec io_targ[4];
  struct tun_pi tun_header;
  uint32_t temp_icmp_checksum;

  if((icmp6->icmp6_type != ICMP6_ECHO_REQUEST) && (icmp6->icmp6_type != ICMP6_ECHO_REPLY)) {
#if CLAT_DEBUG
    logmsg(ANDROID_LOG_WARN,"icmp6_to_icmp/unhandled icmp6 type: 0x%x",icmp6->icmp6_type);
#endif
    return;
  }

  memset(&icmp_targ, 0, sizeof(icmp_targ));

  fill_tun_header(&tun_header,ETH_P_IP);
  fill_ip_header(&ip_targ,sizeof(icmp_targ) + payload_size, IPPROTO_ICMP, ip6);

  icmp_targ.type = (icmp6->icmp6_type == ICMP6_ECHO_REQUEST) ? ICMP_ECHO : ICMP_ECHOREPLY;
  icmp_targ.code = 0x0;
  icmp_targ.checksum = 0;
  icmp_targ.un.echo.id = icmp6->icmp6_id;
  icmp_targ.un.echo.sequence = icmp6->icmp6_seq;

  temp_icmp_checksum = ip_checksum_add(0,(void *)&icmp_targ,sizeof(icmp_targ));
  temp_icmp_checksum = ip_checksum_add(temp_icmp_checksum, (void *)payload, payload_size);
  icmp_targ.checksum = ip_checksum_finish(temp_icmp_checksum);

  io_targ[0].iov_base = &tun_header;
  io_targ[0].iov_len = sizeof(tun_header);
  io_targ[1].iov_base = &ip_targ;
  io_targ[1].iov_len = sizeof(ip_targ);
  io_targ[2].iov_base = &icmp_targ;
  io_targ[2].iov_len = sizeof(icmp_targ);
  io_targ[3].iov_base = (char *)payload;
  io_targ[3].iov_len = payload_size;

  writev(fd, io_targ, 4);
}
Esempio n. 7
0
/* print tcp header */
void dump_tcp_generic(const struct tcphdr *tcp, const uint8_t *options, size_t options_size, uint32_t temp_checksum, const uint8_t *payload, size_t payload_size) {
    uint16_t my_checksum;

    temp_checksum = ip_checksum_add(temp_checksum, tcp, sizeof(struct tcphdr));
    if(options) {
        temp_checksum = ip_checksum_add(temp_checksum, options, options_size);
    }
    temp_checksum = ip_checksum_add(temp_checksum, payload, payload_size);
    my_checksum = ip_checksum_finish(temp_checksum);

    printf("TCP\n");
    printf("source = %x\n",ntohs(tcp->source));
    printf("dest = %x\n",ntohs(tcp->dest));
    printf("seq = %x\n",ntohl(tcp->seq));
    printf("ack = %x\n",ntohl(tcp->ack_seq));
    printf("d_off = %x\n",tcp->doff);
    printf("res1 = %x\n",tcp->res1);
#ifdef __BIONIC__
    printf("CWR = %x\n",tcp->cwr);
    printf("ECE = %x\n",tcp->ece);
#else
    printf("CWR/ECE = %x\n",tcp->res2);
#endif
    printf("urg = %x  ack = %x  psh = %x  rst = %x  syn = %x  fin = %x\n",
           tcp->urg, tcp->ack, tcp->psh, tcp->rst, tcp->syn, tcp->fin);
    printf("window = %x\n",ntohs(tcp->window));
    printf("check = %x [mine %x]\n",tcp->check,my_checksum);
    printf("urgent = %x\n",tcp->urg_ptr);

    if(options) {
        size_t i;

        printf("options: ");
        for(i=0; i<options_size; i++) {
            printf("%x ",*(options+i));
        }
        printf("\n");
    }
}