1 /* source: xio-interface.c */
2 /* Copyright Gerhard Rieger and contributors (see file CHANGES) */
3 /* Published under the GNU General Public License V.2, see file COPYING */
5 /* this file contains the source for opening addresses of raw socket type */
7 #include "xiosysincludes.h"
12 #include "xio-socket.h"
13 #include "xio-ascii.h"
15 #include "xio-interface.h"
18 static int xioopen_interface(int argc
, const char *argv
[], struct opt
*opts
, int xioflags
, xiofile_t
*xfd
, const struct addrdesc
*addrdesc
);
20 /*0 const struct optdesc opt_interface_addr = { "interface-addr", "address", OPT_INTERFACE_ADDR, GROUP_INTERFACE, PH_FD, TYPE_STRING, OFUNC_SPEC };*/
21 /*0 const struct optdesc opt_interface_netmask = { "interface-netmask", "netmask", OPT_INTERFACE_NETMASK, GROUP_INTERFACE, PH_FD, TYPE_STRING, OFUNC_SPEC };*/
22 const struct optdesc opt_iff_up
= { "iff-up", "up", OPT_IFF_UP
, GROUP_INTERFACE
, PH_OFFSET
, TYPE_BOOL
, OFUNC_OFFSET_MASKS
, XIO_OFFSETOF(para
.interface
.iff_opts
), XIO_SIZEOF(para
.interface
.iff_opts
), IFF_UP
};
23 const struct optdesc opt_iff_broadcast
= { "iff-broadcast", NULL
, OPT_IFF_BROADCAST
, GROUP_INTERFACE
, PH_OFFSET
, TYPE_BOOL
, OFUNC_OFFSET_MASKS
, XIO_OFFSETOF(para
.interface
.iff_opts
), XIO_SIZEOF(para
.interface
.iff_opts
), IFF_BROADCAST
};
24 const struct optdesc opt_iff_debug
= { "iff-debug" , NULL
, OPT_IFF_DEBUG
, GROUP_INTERFACE
, PH_OFFSET
, TYPE_BOOL
, OFUNC_OFFSET_MASKS
, XIO_OFFSETOF(para
.interface
.iff_opts
), XIO_SIZEOF(para
.interface
.iff_opts
), IFF_DEBUG
};
25 const struct optdesc opt_iff_loopback
= { "iff-loopback" , "loopback", OPT_IFF_LOOPBACK
, GROUP_INTERFACE
, PH_OFFSET
, TYPE_BOOL
, OFUNC_OFFSET_MASKS
, XIO_OFFSETOF(para
.interface
.iff_opts
), XIO_SIZEOF(para
.interface
.iff_opts
), IFF_LOOPBACK
};
26 const struct optdesc opt_iff_pointopoint
= { "iff-pointopoint", "pointopoint",OPT_IFF_POINTOPOINT
, GROUP_INTERFACE
, PH_OFFSET
, TYPE_BOOL
, OFUNC_OFFSET_MASKS
, XIO_OFFSETOF(para
.interface
.iff_opts
), XIO_SIZEOF(para
.interface
.iff_opts
), IFF_POINTOPOINT
};
27 const struct optdesc opt_iff_notrailers
= { "iff-notrailers", "notrailers", OPT_IFF_NOTRAILERS
, GROUP_INTERFACE
, PH_OFFSET
, TYPE_BOOL
, OFUNC_OFFSET_MASKS
, XIO_OFFSETOF(para
.interface
.iff_opts
), XIO_SIZEOF(para
.interface
.iff_opts
), IFF_NOTRAILERS
};
28 const struct optdesc opt_iff_running
= { "iff-running", "running", OPT_IFF_RUNNING
, GROUP_INTERFACE
, PH_OFFSET
, TYPE_BOOL
, OFUNC_OFFSET_MASKS
, XIO_OFFSETOF(para
.interface
.iff_opts
), XIO_SIZEOF(para
.interface
.iff_opts
), IFF_RUNNING
};
29 const struct optdesc opt_iff_noarp
= { "iff-noarp", "noarp", OPT_IFF_NOARP
, GROUP_INTERFACE
, PH_OFFSET
, TYPE_BOOL
, OFUNC_OFFSET_MASKS
, XIO_OFFSETOF(para
.interface
.iff_opts
), XIO_SIZEOF(para
.interface
.iff_opts
), IFF_NOARP
};
30 const struct optdesc opt_iff_promisc
= { "iff-promisc", "promisc", OPT_IFF_PROMISC
, GROUP_INTERFACE
, PH_OFFSET
, TYPE_BOOL
, OFUNC_OFFSET_MASKS
, XIO_OFFSETOF(para
.interface
.iff_opts
), XIO_SIZEOF(para
.interface
.iff_opts
), IFF_PROMISC
};
31 const struct optdesc opt_iff_allmulti
= { "iff-allmulti", "allmulti", OPT_IFF_ALLMULTI
, GROUP_INTERFACE
, PH_OFFSET
, TYPE_BOOL
, OFUNC_OFFSET_MASKS
, XIO_OFFSETOF(para
.interface
.iff_opts
), XIO_SIZEOF(para
.interface
.iff_opts
), IFF_ALLMULTI
};
33 const struct optdesc opt_iff_master
= { "iff-master", "master", OPT_IFF_MASTER
, GROUP_INTERFACE
, PH_OFFSET
, TYPE_BOOL
, OFUNC_OFFSET_MASKS
, XIO_OFFSETOF(para
.interface
.iff_opts
), XIO_SIZEOF(para
.interface
.iff_opts
), IFF_MASTER
};
36 const struct optdesc opt_iff_slave
= { "iff-slave", "slave", OPT_IFF_SLAVE
, GROUP_INTERFACE
, PH_OFFSET
, TYPE_BOOL
, OFUNC_OFFSET_MASKS
, XIO_OFFSETOF(para
.interface
.iff_opts
), XIO_SIZEOF(para
.interface
.iff_opts
), IFF_SLAVE
};
38 const struct optdesc opt_iff_multicast
= { "iff-multicast", NULL
, OPT_IFF_MULTICAST
, GROUP_INTERFACE
, PH_OFFSET
, TYPE_BOOL
, OFUNC_OFFSET_MASKS
, XIO_OFFSETOF(para
.interface
.iff_opts
), XIO_SIZEOF(para
.interface
.iff_opts
), IFF_MULTICAST
};
40 const struct optdesc opt_iff_portsel
= { "iff-portsel", "portsel", OPT_IFF_PORTSEL
, GROUP_INTERFACE
, PH_OFFSET
, TYPE_BOOL
, OFUNC_OFFSET_MASKS
, XIO_OFFSETOF(para
.interface
.iff_opts
), XIO_SIZEOF(para
.interface
.iff_opts
), IFF_PORTSEL
};
43 const struct optdesc opt_iff_automedia
= { "iff-automedia", "automedia", OPT_IFF_AUTOMEDIA
, GROUP_INTERFACE
, PH_OFFSET
, TYPE_BOOL
, OFUNC_OFFSET_MASKS
, XIO_OFFSETOF(para
.interface
.iff_opts
), XIO_SIZEOF(para
.interface
.iff_opts
), IFF_AUTOMEDIA
};
45 /*const struct optdesc opt_iff_dynamic = { "iff-dynamic", "dynamic", OPT_IFF_DYNAMIC, GROUP_INTERFACE, PH_OFFSET, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.interface.iff_opts), XIO_SIZEOF(short), IFF_DYNAMIC };*/
47 const struct optdesc opt_retrieve_vlan
= { "retrieve-vlan", NULL
, OPT_RETRIEVE_VLAN
, GROUP_INTERFACE
, PH_LATE
, TYPE_CONST
, OFUNC_SPEC
};
50 const struct optdesc opt_route
= { "route", NULL
, OPT_ROUTE
, GROUP_INTERFACE
, PH_INIT
, TYPE_STRING
, OFUNC_SPEC
};
54 const struct addrdesc xioaddr_interface
= { "INTERFACE", 3, xioopen_interface
, GROUP_FD
|GROUP_SOCKET
|GROUP_INTERFACE
, PF_PACKET
, 0, 0 HELP(":<interface>") };
55 #endif /* WITH_INTERFACE */
59 int _xioopen_interface(const char *ifname
,
60 struct opt
*opts
, int xioflags
, xiofile_t
*xxfd
,
61 groups_t groups
, int pf
) {
62 xiosingle_t
*sfd
= &xxfd
->stream
;
63 union sockaddr_union us
= {{0}};
65 int socktype
= SOCK_RAW
;
67 bool needbind
= false;
68 char *bindstring
= NULL
;
69 struct sockaddr_ll sall
= { 0 };
72 if (ifindex(ifname
, &ifidx
, -1) < 0) {
73 Error1("unknown interface \"%s\"", ifname
);
74 ifidx
= 0; /* desparate attempt to continue */
77 if (sfd
->howtoend
== END_UNSPEC
)
78 sfd
->howtoend
= END_INTERFACE
;
79 retropt_int(opts
, OPT_SO_TYPE
, &socktype
);
81 retropt_socket_pf(opts
, &pf
);
84 if (applyopts_single(sfd
, opts
, PH_INIT
) < 0) return -1;
85 applyopts(sfd
, -1, opts
, PH_INIT
);
87 sfd
->salen
= sizeof(sfd
->peersa
);
88 if (pf
== PF_UNSPEC
) {
89 pf
= sfd
->peersa
.soa
.sa_family
;
92 sfd
->dtype
= XIODATA_RECVFROM_SKIPIP
;
94 if (retropt_string(opts
, OPT_BIND
, &bindstring
)) {
98 us
.ll
.sll_family
= pf
;
99 us
.ll
.sll_protocol
= htons(ETH_P_ALL
);
100 us
.ll
.sll_ifindex
= ifidx
;
101 uslen
= sizeof(sall
);
103 sfd
->peersa
= (union sockaddr_union
)us
;
106 _xioopen_dgram_sendto(needbind
?&us
:NULL
, uslen
,
107 opts
, xioflags
, sfd
, groups
, pf
, socktype
, 0, 0);
111 strncpy(sfd
->para
.interface
.name
, ifname
, IFNAMSIZ
);
112 _xiointerface_get_iff(sfd
->fd
, ifname
, &sfd
->para
.interface
.save_iff
);
113 _xiointerface_apply_iff(sfd
->fd
, ifname
, sfd
->para
.interface
.iff_opts
);
114 if (_interface_retrieve_vlan(sfd
, opts
) < 0)
117 #ifdef PACKET_IGNORE_OUTGOING
118 /* Raw socket might also provide packets that are outbound - we are not
119 interested in these and disable this "feature" in kernel if possible */
120 if (Setsockopt(sfd
->fd
, SOL_PACKET
, PACKET_IGNORE_OUTGOING
, &one
, sizeof(one
)) < 0) {
121 Warn2("setsockopt(%d, SOL_PACKET, PACKET_IGNORE_OUTGOING, {1}): %s",
122 sfd
->fd
, strerror(errno
));
124 #endif /*defined(PACKET_IGNORE_OUTGOING) */
130 int _interface_retrieve_vlan(struct single
*sfd
, struct opt
*opts
) {
131 #if HAVE_STRUCT_TPACKET_AUXDATA
132 if (retropt_bool(opts
, OPT_RETRIEVE_VLAN
,
133 &sfd
->para
.socket
.retrieve_vlan
)
135 if (!xioparms
.experimental
) {
136 Warn1("option %s is experimental", opts
->desc
->defname
);
139 if (sfd
->para
.socket
.retrieve_vlan
) {
140 if (_interface_setsockopt_auxdata(sfd
->fd
, 1) < 0) {
144 #endif /* HAVE_STRUCT_TPACKET_AUXDATA */
148 int _interface_setsockopt_auxdata(int fd
, int auxdata
) {
149 #ifdef PACKET_AUXDATA
150 /* Linux strips VLAN tag off incoming packets and makes it available per
151 ancillary data as auxdata. Apply option packet-auxdata if you want the
152 VLAN tag to be restored by Socat in the received packet */
155 Info1("setsockopt(fd=%d, level=SOL_PACKET, optname=PACKET_AUXDATA)", fd
);
156 rc
= Setsockopt(fd
, SOL_PACKET
, PACKET_AUXDATA
, &auxdata
, sizeof(auxdata
));
158 Error3("setsockopt(%d, SOL_PACKET, PACKET_AUXDATA, , {%d}): %s",
159 fd
, auxdata
, strerror(errno
));
162 #endif /* defined(PACKET_AUXDATA) */
167 int xioopen_interface(
173 const struct addrdesc
*addrdesc
)
175 xiosingle_t
*sfd
= &xxfd
->stream
;
179 xio_syntax(argv
[0], 1, argc
-1, addrdesc
->syntax
);
184 _xioopen_interface(argv
[1], opts
, xioflags
, xxfd
, addrdesc
->groups
,
190 sfd
->dtype
= XIOREAD_RECV
|XIOWRITE_SENDTO
;
191 if (addrdesc
->arg1
== PF_INET
) {
192 sfd
->dtype
|= XIOREAD_RECV_SKIPIP
;
195 sfd
->para
.socket
.la
.soa
.sa_family
= sfd
->peersa
.soa
.sa_family
;
197 _xio_openlate(sfd
, opts
);
202 /* Retrieves the interface flags related to sockfd */
203 int _xiointerface_get_iff(
210 memset(&ifr
, 0, sizeof(ifr
));
211 strncpy(ifr
.ifr_name
, name
, sizeof(ifr
.ifr_name
));
212 if (Ioctl(sockfd
, SIOCGIFFLAGS
, &ifr
) < 0) {
213 Error3("ioctl(%d, SIOCGIFFLAGS, {\"%s\"}: %s",
214 sockfd
, ifr
.ifr_name
, strerror(errno
));
216 *save_iff
= ifr
.ifr_flags
;
220 /* Applies the interface flags to the socket FD.
221 Used by INTERFACE and TUN
223 int _xiointerface_set_iff(
230 memset(&ifr
, 0, sizeof(ifr
));
231 strncpy(ifr
.ifr_name
, name
, sizeof(ifr
.ifr_name
));
232 if (Ioctl(sockfd
, SIOCGIFFLAGS
, &ifr
) < 0) {
233 Error3("ioctl(%d, SIOCGIFFLAGS, {\"%s\"}: %s",
234 sockfd
, ifr
.ifr_name
, strerror(errno
));
236 ifr
.ifr_flags
= new_iff
;
237 if (Ioctl(sockfd
, SIOCSIFFLAGS
, &ifr
) < 0) {
238 Error4("ioctl(%d, SIOCSIFFLAGS, {\"%s\", %hd}: %s",
239 sockfd
, ifr
.ifr_name
, ifr
.ifr_flags
, strerror(errno
));
244 /* Applies the interface flags to the socket FD
245 Used by INTERFACE and TUN
247 int _xiointerface_apply_iff(
254 memset(&ifr
, 0, sizeof(ifr
));
255 strncpy(ifr
.ifr_name
, name
, sizeof(ifr
.ifr_name
));
256 if (Ioctl(sockfd
, SIOCGIFFLAGS
, &ifr
) < 0) {
257 Error3("ioctl(%d, SIOCGIFFLAGS, {\"%s\"}: %s",
258 sockfd
, ifr
.ifr_name
, strerror(errno
));
260 Debug2("\"%s\": system set flags: 0x%hx", ifr
.ifr_name
, ifr
.ifr_flags
);
261 ifr
.ifr_flags
|= iff_opts
[0];
262 ifr
.ifr_flags
&= ~iff_opts
[1];
263 Debug2("\"%s\": xio merged flags: 0x%hx", ifr
.ifr_name
, ifr
.ifr_flags
);
264 if (Ioctl(sockfd
, SIOCSIFFLAGS
, &ifr
) < 0) {
265 Error4("ioctl(%d, SIOCSIFFLAGS, {\"%s\", %hd}: %s",
266 sockfd
, ifr
.ifr_name
, ifr
.ifr_flags
, strerror(errno
));
269 if (Ioctl(sockfd
, SIOCGIFFLAGS
, &ifr
) < 0) {
270 Error3("ioctl(%d, SIOCGIFFLAGS, {\"%s\"}: %s",
271 sockfd
, ifr
.ifr_name
, strerror(errno
));
273 Debug2("\"%s\": resulting flags: 0x%hx", ifr
.ifr_name
, ifr
.ifr_flags
);
278 #if HAVE_STRUCT_CMSGHDR && HAVE_STRUCT_TPACKET_AUXDATA
279 /* Converts the ancillary message in *cmsg into a form useable for further
280 processing. Knows the specifics of common message types.
281 On PACKET_AUXDATA it stored the ancillary data in the XFD.
283 returns the number of resulting syntax elements in *num,
284 returns a sequence of \0 terminated type strings in *typbuff,
285 returns a sequence of \0 terminated name strings in *nambuff,
286 returns a sequence of \0 terminated value strings in *valbuff,
287 the respective len parameters specify the available space in the buffers
288 returns STAT_OK or other STAT_*
291 xiolog_ancillary_packet(struct single
*sfd
,
292 struct cmsghdr
*cmsg
, int *num
,
293 char *typbuff
, int typlen
,
294 char *nambuff
, int namlen
,
295 char *envbuff
, int envlen
,
296 char *valbuff
, int vallen
) {
298 const char *cmsgtype
, *cmsgname
, *cmsgenvn
;
301 struct tpacket_auxdata
*auxp
;
306 #if defined(CMSG_DATA)
309 msglen
= cmsg
->cmsg_len
-((char *)CMSG_DATA(cmsg
)-(char *)cmsg
);
311 switch (cmsg
->cmsg_type
) {
312 #if HAVE_STRUCT_TPACKET_AUXDATA_TP_VLAN_TPID
315 cmsgname
= "packet_auxdata";
316 cmsgtype
= "auxdata";
317 cmsgenvn
= "AUXDATA";
319 auxp
= (struct tpacket_auxdata
*)CMSG_DATA(cmsg
);
320 Info8("%s(): Ancillary message: PACKET_AUXDATA: status="F_uint32_t
", len="F_uint32_t
", snaplen="F_uint32_t
", mac="F_uint16_t
", net="F_uint16_t
", vlan_tci="F_uint16_t
", vlan_tpid="F_uint16_t
"", __func__
, auxp
->tp_status
, auxp
->tp_len
, auxp
->tp_snaplen
, auxp
->tp_mac
, auxp
->tp_net
, auxp
->tp_vlan_tci
, auxp
->tp_vlan_tpid
);
321 sfd
->para
.socket
.ancill_data_packet_auxdata
= *auxp
;
322 sfd
->para
.socket
.ancill_flag
.packet_auxdata
= 1;
323 snprintf(typbuff
, typlen
, "PACKET.%u", cmsg
->cmsg_type
);
324 nambuff
[0] = '\0'; strncat(nambuff
, "vlan", namlen
-1);
325 snprintf(strchr(valbuff
, '\0')-1/*def \n*/, vallen
-strlen(valbuff
)+1, ", %d", auxp
->tp_vlan_tci
);
327 #endif /* HAVE_STRUCT_TPACKET_AUXDATA_TP_VLAN_TPID */
328 default: /* binary data */
329 Warn1("xiolog_ancillary_packet(): INTERNAL: cmsg_type=%d not handled", cmsg
->cmsg_type
);
334 #else /* !defined(CMSG_DATA) */
338 #endif /* !defined(CMSG_DATA) */
340 #endif /* HAVE_STRUCT_CMSGHDR && HAVE_STRUCT_TPACKET_AUXDATA */
342 #endif /* _WITH_INTERFACE */