title: classic BPF on Linux: filter does not work
body: <p>I'm trying to test classic BPF for packet filtering by attaching it to raw socket. I want to catch TCP packets with first byte of source port == 8
  (tcpdump 'tcp[1:1] = 0x50'), but I see no incoming packets on the socket. Without filter my code works OK.</p>
  
  <p>Here is the code example:</p>
  
  <pre><code>#include&lt;stdio.h&gt; //for printf
  #include&lt;string.h&gt; //memset
  #include&lt;sys/socket.h&gt;    //for socket ofcourse
  #include&lt;stdlib.h&gt; //for exit(0);
  #include&lt;errno.h&gt; //For errno - the error number
  #include&lt;netinet/tcp.h&gt;   //Provides declarations for tcp header
  #include&lt;netinet/ip.h&gt;    //Provides declarations for ip header
  #include &lt;sys/socket.h&gt;
  #include &lt;netinet/in.h&gt;
  #include &lt;arpa/inet.h&gt;
  #include &lt;linux/filter.h&gt;
  
  
  #define ARRAY_SIZE(arr) (sizeof(arr)/sizeof((arr)[0])
  /* 
     96 bit (12 bytes) pseudo header needed for tcp header checksum calculation 
  */
  struct pseudo_header
  {
      u_int32_t source_address;
      u_int32_t dest_address;
      u_int8_t placeholder;
      u_int8_t protocol;
      u_int16_t tcp_length;
  };
  
  /*
    Generic checksum calculation function
  */
  unsigned short csum(unsigned short *ptr,int nbytes) 
  {
      register long sum;
      unsigned short oddbyte;
      register short answer;
  
      sum=0;
      while(nbytes&gt;1) {
          sum+=*ptr++;
          nbytes-=2;
      }
      if(nbytes==1) {
          oddbyte=0;
          *((u_char*)&amp;oddbyte)=*(u_char*)ptr;
          sum+=oddbyte;
      }
  
      sum = (sum&gt;&gt;16)+(sum &amp; 0xffff);
      sum = sum + (sum&gt;&gt;16);
      answer=(short)~sum;
  
      return(answer);
  }
  
  int main (void)
  {
      struct sock_filter code[] = {
  
          { 0x28,  0,  0, 0x0000000c },
          { 0x15,  0,  9, 0x00000800 },
          { 0x30,  0,  0, 0x00000017 },
          { 0x15,  0,  7, 0x00000006 },
          { 0x28,  0,  0, 0x00000014 },
          { 0x45,  4,  0, 0x00001fff },
          { 0xb1,  0,  0, 0x0000000e },
          { 0x50,  0,  0, 0x0000000f },
          { 0x15,  0,  2, 0x00000050 },
          { 0x06,  0,  0, 0xffffffff },
          { 0x06,  0,  0, 0xffffffff },
          { 0x06,  0,  0, 0000000000 },
      };
  
      struct sock_fprog bpf;
  //    bpf.len = ARRAY_SIZE(code);
      bpf.len = 12;
      bpf.filter = code;
  //Create a raw socke
      int s = socket (PF_INET, SOCK_RAW, IPPROTO_TCP);
      if(s == -1)
      {
          //socket creation failed, may be because of non-root privileges
          perror("Failed to create socket");
          exit(1);
      }
  
      setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &amp;bpf, sizeof(bpf));
      perror("setsockopt");
  //Datagram to represent the packet
      char datagram[4096] , source_ip[32] , *data , *pseudogram;
  
  //zero out the packet buffer
      memset (datagram, 0, 4096);
  
  //IP header
      struct iphdr *iph = (struct iphdr *) datagram;
  
  //TCP header
      struct tcphdr *tcph = (struct tcphdr *) (datagram + sizeof (struct ip));
      struct sockaddr_in sin;
      struct pseudo_header psh;
  
  //Data part
      data = datagram + sizeof(struct iphdr) + sizeof(struct tcphdr);
      strcpy(data , "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
  
  //some address resolution
      strcpy(source_ip , "127.0.0.1");
      sin.sin_family = AF_INET;
      sin.sin_port = htons(80);
      sin.sin_addr.s_addr = inet_addr ("127.0.0.1");
  
      bind(s, (struct sockaddr *)&amp;sin, sizeof(sin));
      perror("bind");
  
  //Fill in the IP Header
      iph-&gt;ihl = 5;
      iph-&gt;version = 4;
      iph-&gt;tos = 0;
      iph-&gt;tot_len = sizeof (struct iphdr) + sizeof (struct tcphdr) + strlen(data);
      iph-&gt;id = htonl (54321); //Id of this packet
      iph-&gt;frag_off = 0;
      iph-&gt;ttl = 255;
      iph-&gt;protocol = IPPROTO_TCP;
      iph-&gt;check = 0;      //Set to 0 before calculating checksum
      iph-&gt;saddr = inet_addr ( source_ip );    //Spoof the source ip address
      iph-&gt;daddr = sin.sin_addr.s_addr;
  
  //Ip checksum
      iph-&gt;check = csum ((unsigned short *) datagram, iph-&gt;tot_len);
  
  //TCP Header
      tcph-&gt;source = htons (1234);
      tcph-&gt;dest = htons (80);
      tcph-&gt;seq = 0;
      tcph-&gt;ack_seq = 0;
      tcph-&gt;doff = 5;  //tcp header size
      tcph-&gt;fin=0;
      tcph-&gt;syn=1;
      tcph-&gt;rst=0;
      tcph-&gt;psh=0;
      tcph-&gt;ack=0;
      tcph-&gt;urg=0;
      tcph-&gt;window = htons (5840); /* maximum allowed window size */
      tcph-&gt;check = 0; //leave checksum 0 now, filled later by pseudo header
      tcph-&gt;urg_ptr = 0;
  
  //Now the TCP checksum
      psh.source_address = inet_addr( source_ip );
      psh.dest_address = sin.sin_addr.s_addr;
      psh.placeholder = 0;
      psh.protocol = IPPROTO_TCP;
      psh.tcp_length = htons(sizeof(struct tcphdr) + strlen(data) );
  
      int psize = sizeof(struct pseudo_header) + sizeof(struct tcphdr) + strlen(data);
      pseudogram = malloc(psize);
  
      memcpy(pseudogram , (char*) &amp;psh , sizeof (struct pseudo_header));
      memcpy(pseudogram + sizeof(struct pseudo_header) , tcph , sizeof(struct tcphdr) + strlen(data));
  
      tcph-&gt;check = csum( (unsigned short*) pseudogram , psize);
  
  //IP_HDRINCL to tell the kernel that headers are included in the packet
      int one = 1;
      const int *val = &amp;one;
  
      if (setsockopt (s, IPPROTO_IP, IP_HDRINCL, val, sizeof (one)) &lt; 0)
      {
          perror("Error setting IP_HDRINCL");
          exit(0);
      }
  
  //loop if you want to flood :)
      while (1)
      {
          //Send the packet
          if (sendto (s, datagram, iph-&gt;tot_len ,  0, (struct sockaddr *) &amp;sin, sizeof (sin)) &lt; 0)
          {
              perror("sendto failed");
          }
          //Data send successfully
          else
          {
              char bbuf[500];
              int re = 0;
              printf ("Packet Send. Length : %d \n" , iph-&gt;tot_len);
              if (recvfrom(s, bbuf, 500, 0, (struct sockaddr *) &amp;sin, &amp;re) &lt; 0)
                  printf("Recv failed\n");
              else
              {
                  printf("%x %x %x %x %x \n", bbuf[0], bbuf[1], bbuf[2], bbuf[3], bbuf[4] );
              }
              if (recvfrom(s, bbuf, 500, 0, (struct sockaddr *) &amp;sin, &amp;re) &lt; 0)
                  printf("Recv failed\n");
              else
              {
                  printf("%x %x %x %x %x \n", bbuf[0], bbuf[1], bbuf[2], bbuf[3], bbuf[4] );
              }
          }
          break;
      }
  
      return 0;
  }
  </code></pre>
  
  <p>The code for filter was generated by bpf_asm -c from the following:</p>
  
  <pre><code>ldh      [12]
  jneq      #0x800, drop
  ldb      [23]
  jneq      #0x6, drop
  ldh      [20]
  jset     #0x1fff, good
  ldxb     4*([14]&amp;0xf)
  ldb      [x + 15]
  jneq      #0x50, drop
  ret #-1
  good: ret      #-1
  drop: ret      #0
  </code></pre>
  
  <p>I also tried the following instructions:
  I also tried the following:</p>
  
  <pre><code>tcpdump 'ether[35:1] = 0x50'
  
  ldb      [35]
  jneq      #0x50, drop
  ret      #-1
  drop: ret      #0
  </code></pre>
  
  <p>it works for tcpdump only =(</p>