2 * 802.1q vlan -> eoip tagging gateway
3 * (c) 2008-2011 Karel Tuma <karel.tuma@pilsfree.net>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * You should have received a copy of the GNU General Public License
11 * (for example /usr/src/linux/COPYING); if not, write to the Free
12 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 #include <sys/ioctl.h>
21 #include <sys/types.h>
22 #include <sys/socket.h>
25 #include <linux/if_tun.h>
31 #include <netinet/ip.h>
32 #include <arpa/inet.h>
34 #define max(a,b) ((a)>(b) ? (a):(b))
41 #define LOG(msg...) {printf(msg); printf("\n");}
44 #define GREHDR "\x20\x01\x64\x00"
54 static int opentun(int flags
, char *name
)
57 int fd
= open("/dev/net/tun", O_RDWR
);
59 memset(&ifr
,0,sizeof(ifr
));
60 ifr
.ifr_flags
= flags
;
61 strncpy(ifr
.ifr_name
, name
, IFNAMSIZ
);
62 // write(2, &ifr, sizeof(ifr));
63 ioctl(fd
, TUNSETIFF
, (void *) &ifr
);
64 // ioctl(fd, TUNSETPERSIST, 1);
71 "%s <intf> <localip> <remoteip - eoip target>\n",a0
);
76 int main(int argc
, char *argv
[])
84 struct sockaddr_in sin
;
93 fdtap
= opentun(IFF_TAP
|IFF_NO_PI
, argv
[1]);
94 locip
= inet_addr(argv
[2]);
95 remip
= inet_addr(argv
[3]);
98 fdraw
= socket(AF_INET
, SOCK_RAW
, 47);
99 sin
.sin_family
= AF_INET
;
100 sin
.sin_addr
.s_addr
= locip
;
101 sin
.sin_port
= htons(47);
102 assert(bind(fdraw
, (struct sockaddr
*)&sin
, sizeof(sin
))==0);
105 memset(&sin
, 0, sizeof(sin
));
106 sin
.sin_family
= AF_INET
;
107 sin
.sin_addr
.s_addr
= remip
;
111 ioctl(fdtap
, TUNSETNOCSUM
, 1);
126 select(max(fdtap
,fdraw
)+1,&fds
,NULL
,NULL
,&tv
);
128 /* got mtk GRE packet */
129 if (FD_ISSET(fdraw
, &fds
)) {
130 len
= recv(fdraw
, pkt
.buf
, sizeof(pkt
), 0);
133 if (pkt
.ip
.daddr
!= locip
) continue;
134 if (pkt
.ip
.saddr
!= remip
) continue;
136 /* move past ip header */
137 p
= pkt
.buf
+ pkt
.ip
.ihl
*4; len
-= pkt
.ip
.ihl
*4;
138 DEBUG("len is=%d\n", len
);
140 /* check its really eoip */
141 if (memcmp(p
, GREHDR
, GREHDRSZ
)) continue;
143 /* move past header */
146 if (len
< 0) continue;
148 tid
= ((uint16_t *) p
)[-1]; /* tunnel id, actually 802.1q tag number */
150 /* IP hdr/eoip length mismatch */
151 if (len
!= ntohs(((uint16_t*)p
)[-2])) {
152 DEBUG("%d %d\n",len
,ntohs(((uint16_t*)p
)[-2]));
157 DEBUG("len=%d\n",len
);
158 for (i
= 0; i
< len
; i
++) DEBUG("%02hhx ", p
[i
]);
161 /* shift src/dst mac by 4 bytes */
163 p
[12-4] = 0x81; p
[13-4] = 0x00;
164 p
[14-4] = /*0x40 | */(tid
>>8);
165 p
[15-4] = tid
& 0xff;
166 write(fdtap
, p
-4, len
+4);
171 if (FD_ISSET(fdtap
, &fds
)) {
173 struct gre_packet gre
;
174 uint8_t mybuf
[65536];
178 len
= read(fdtap
, p
, sizeof(pkt
));
180 if (len
<= 14) continue;
181 /* only tagged packets please */
182 if (p
[12] != 0x81 || p
[13] != 0x00) continue;
183 tid
= ((p
[14] << 8)&0xf00) | p
[15];
185 sin
.sin_port
= htons(47);
186 memcpy(sbuf
.gre
.magic
, GREHDR
, GREHDRSZ
);
187 sbuf
.gre
.len
= htons(len
);
188 sbuf
.gre
.tid
= tid
; /* little endian! */
189 memcpy(sbuf
.gre
.data
, p
, len
);
190 sendto(fdraw
, sbuf
.mybuf
, len
+8, 0, (struct sockaddr
*) &sin
, sizeof(sin
));