diff options
Diffstat (limited to 'net/ipv4/ip_sockglue.c')
-rw-r--r-- | net/ipv4/ip_sockglue.c | 170 |
1 files changed, 150 insertions, 20 deletions
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 2bf8d782f678..12e0bf19f24a 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c | |||
@@ -50,6 +50,7 @@ | |||
50 | #define IP_CMSG_TOS 4 | 50 | #define IP_CMSG_TOS 4 |
51 | #define IP_CMSG_RECVOPTS 8 | 51 | #define IP_CMSG_RECVOPTS 8 |
52 | #define IP_CMSG_RETOPTS 16 | 52 | #define IP_CMSG_RETOPTS 16 |
53 | #define IP_CMSG_PASSSEC 32 | ||
53 | 54 | ||
54 | /* | 55 | /* |
55 | * SOL_IP control messages. | 56 | * SOL_IP control messages. |
@@ -109,6 +110,19 @@ static void ip_cmsg_recv_retopts(struct msghdr *msg, struct sk_buff *skb) | |||
109 | put_cmsg(msg, SOL_IP, IP_RETOPTS, opt->optlen, opt->__data); | 110 | put_cmsg(msg, SOL_IP, IP_RETOPTS, opt->optlen, opt->__data); |
110 | } | 111 | } |
111 | 112 | ||
113 | static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb) | ||
114 | { | ||
115 | char *secdata; | ||
116 | u32 seclen; | ||
117 | int err; | ||
118 | |||
119 | err = security_socket_getpeersec_dgram(skb, &secdata, &seclen); | ||
120 | if (err) | ||
121 | return; | ||
122 | |||
123 | put_cmsg(msg, SOL_IP, SCM_SECURITY, seclen, secdata); | ||
124 | } | ||
125 | |||
112 | 126 | ||
113 | void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb) | 127 | void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb) |
114 | { | 128 | { |
@@ -138,6 +152,11 @@ void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb) | |||
138 | 152 | ||
139 | if (flags & 1) | 153 | if (flags & 1) |
140 | ip_cmsg_recv_retopts(msg, skb); | 154 | ip_cmsg_recv_retopts(msg, skb); |
155 | if ((flags>>=1) == 0) | ||
156 | return; | ||
157 | |||
158 | if (flags & 1) | ||
159 | ip_cmsg_recv_security(msg, skb); | ||
141 | } | 160 | } |
142 | 161 | ||
143 | int ip_cmsg_send(struct msghdr *msg, struct ipcm_cookie *ipc) | 162 | int ip_cmsg_send(struct msghdr *msg, struct ipcm_cookie *ipc) |
@@ -380,20 +399,19 @@ out: | |||
380 | * an IP socket. | 399 | * an IP socket. |
381 | */ | 400 | */ |
382 | 401 | ||
383 | int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval, int optlen) | 402 | static int do_ip_setsockopt(struct sock *sk, int level, |
403 | int optname, char __user *optval, int optlen) | ||
384 | { | 404 | { |
385 | struct inet_sock *inet = inet_sk(sk); | 405 | struct inet_sock *inet = inet_sk(sk); |
386 | int val=0,err; | 406 | int val=0,err; |
387 | 407 | ||
388 | if (level != SOL_IP) | ||
389 | return -ENOPROTOOPT; | ||
390 | |||
391 | if (((1<<optname) & ((1<<IP_PKTINFO) | (1<<IP_RECVTTL) | | 408 | if (((1<<optname) & ((1<<IP_PKTINFO) | (1<<IP_RECVTTL) | |
392 | (1<<IP_RECVOPTS) | (1<<IP_RECVTOS) | | 409 | (1<<IP_RECVOPTS) | (1<<IP_RECVTOS) | |
393 | (1<<IP_RETOPTS) | (1<<IP_TOS) | | 410 | (1<<IP_RETOPTS) | (1<<IP_TOS) | |
394 | (1<<IP_TTL) | (1<<IP_HDRINCL) | | 411 | (1<<IP_TTL) | (1<<IP_HDRINCL) | |
395 | (1<<IP_MTU_DISCOVER) | (1<<IP_RECVERR) | | 412 | (1<<IP_MTU_DISCOVER) | (1<<IP_RECVERR) | |
396 | (1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND))) || | 413 | (1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND) | |
414 | (1<<IP_PASSSEC))) || | ||
397 | optname == IP_MULTICAST_TTL || | 415 | optname == IP_MULTICAST_TTL || |
398 | optname == IP_MULTICAST_LOOP) { | 416 | optname == IP_MULTICAST_LOOP) { |
399 | if (optlen >= sizeof(int)) { | 417 | if (optlen >= sizeof(int)) { |
@@ -478,6 +496,12 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval, | |||
478 | else | 496 | else |
479 | inet->cmsg_flags &= ~IP_CMSG_RETOPTS; | 497 | inet->cmsg_flags &= ~IP_CMSG_RETOPTS; |
480 | break; | 498 | break; |
499 | case IP_PASSSEC: | ||
500 | if (val) | ||
501 | inet->cmsg_flags |= IP_CMSG_PASSSEC; | ||
502 | else | ||
503 | inet->cmsg_flags &= ~IP_CMSG_PASSSEC; | ||
504 | break; | ||
481 | case IP_TOS: /* This sets both TOS and Precedence */ | 505 | case IP_TOS: /* This sets both TOS and Precedence */ |
482 | if (sk->sk_type == SOCK_STREAM) { | 506 | if (sk->sk_type == SOCK_STREAM) { |
483 | val &= ~3; | 507 | val &= ~3; |
@@ -849,12 +873,7 @@ mc_msf_out: | |||
849 | break; | 873 | break; |
850 | 874 | ||
851 | default: | 875 | default: |
852 | #ifdef CONFIG_NETFILTER | ||
853 | err = nf_setsockopt(sk, PF_INET, optname, optval, | ||
854 | optlen); | ||
855 | #else | ||
856 | err = -ENOPROTOOPT; | 876 | err = -ENOPROTOOPT; |
857 | #endif | ||
858 | break; | 877 | break; |
859 | } | 878 | } |
860 | release_sock(sk); | 879 | release_sock(sk); |
@@ -865,12 +884,68 @@ e_inval: | |||
865 | return -EINVAL; | 884 | return -EINVAL; |
866 | } | 885 | } |
867 | 886 | ||
887 | int ip_setsockopt(struct sock *sk, int level, | ||
888 | int optname, char __user *optval, int optlen) | ||
889 | { | ||
890 | int err; | ||
891 | |||
892 | if (level != SOL_IP) | ||
893 | return -ENOPROTOOPT; | ||
894 | |||
895 | err = do_ip_setsockopt(sk, level, optname, optval, optlen); | ||
896 | #ifdef CONFIG_NETFILTER | ||
897 | /* we need to exclude all possible ENOPROTOOPTs except default case */ | ||
898 | if (err == -ENOPROTOOPT && optname != IP_HDRINCL && | ||
899 | optname != IP_IPSEC_POLICY && optname != IP_XFRM_POLICY | ||
900 | #ifdef CONFIG_IP_MROUTE | ||
901 | && (optname < MRT_BASE || optname > (MRT_BASE + 10)) | ||
902 | #endif | ||
903 | ) { | ||
904 | lock_sock(sk); | ||
905 | err = nf_setsockopt(sk, PF_INET, optname, optval, optlen); | ||
906 | release_sock(sk); | ||
907 | } | ||
908 | #endif | ||
909 | return err; | ||
910 | } | ||
911 | |||
912 | #ifdef CONFIG_COMPAT | ||
913 | int compat_ip_setsockopt(struct sock *sk, int level, int optname, | ||
914 | char __user *optval, int optlen) | ||
915 | { | ||
916 | int err; | ||
917 | |||
918 | if (level != SOL_IP) | ||
919 | return -ENOPROTOOPT; | ||
920 | |||
921 | err = do_ip_setsockopt(sk, level, optname, optval, optlen); | ||
922 | #ifdef CONFIG_NETFILTER | ||
923 | /* we need to exclude all possible ENOPROTOOPTs except default case */ | ||
924 | if (err == -ENOPROTOOPT && optname != IP_HDRINCL && | ||
925 | optname != IP_IPSEC_POLICY && optname != IP_XFRM_POLICY | ||
926 | #ifdef CONFIG_IP_MROUTE | ||
927 | && (optname < MRT_BASE || optname > (MRT_BASE + 10)) | ||
928 | #endif | ||
929 | ) { | ||
930 | lock_sock(sk); | ||
931 | err = compat_nf_setsockopt(sk, PF_INET, optname, | ||
932 | optval, optlen); | ||
933 | release_sock(sk); | ||
934 | } | ||
935 | #endif | ||
936 | return err; | ||
937 | } | ||
938 | |||
939 | EXPORT_SYMBOL(compat_ip_setsockopt); | ||
940 | #endif | ||
941 | |||
868 | /* | 942 | /* |
869 | * Get the options. Note for future reference. The GET of IP options gets the | 943 | * Get the options. Note for future reference. The GET of IP options gets the |
870 | * _received_ ones. The set sets the _sent_ ones. | 944 | * _received_ ones. The set sets the _sent_ ones. |
871 | */ | 945 | */ |
872 | 946 | ||
873 | int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen) | 947 | static int do_ip_getsockopt(struct sock *sk, int level, int optname, |
948 | char __user *optval, int __user *optlen) | ||
874 | { | 949 | { |
875 | struct inet_sock *inet = inet_sk(sk); | 950 | struct inet_sock *inet = inet_sk(sk); |
876 | int val; | 951 | int val; |
@@ -932,6 +1007,9 @@ int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval, | |||
932 | case IP_RETOPTS: | 1007 | case IP_RETOPTS: |
933 | val = (inet->cmsg_flags & IP_CMSG_RETOPTS) != 0; | 1008 | val = (inet->cmsg_flags & IP_CMSG_RETOPTS) != 0; |
934 | break; | 1009 | break; |
1010 | case IP_PASSSEC: | ||
1011 | val = (inet->cmsg_flags & IP_CMSG_PASSSEC) != 0; | ||
1012 | break; | ||
935 | case IP_TOS: | 1013 | case IP_TOS: |
936 | val = inet->tos; | 1014 | val = inet->tos; |
937 | break; | 1015 | break; |
@@ -1051,17 +1129,8 @@ int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval, | |||
1051 | val = inet->freebind; | 1129 | val = inet->freebind; |
1052 | break; | 1130 | break; |
1053 | default: | 1131 | default: |
1054 | #ifdef CONFIG_NETFILTER | ||
1055 | val = nf_getsockopt(sk, PF_INET, optname, optval, | ||
1056 | &len); | ||
1057 | release_sock(sk); | ||
1058 | if (val >= 0) | ||
1059 | val = put_user(len, optlen); | ||
1060 | return val; | ||
1061 | #else | ||
1062 | release_sock(sk); | 1132 | release_sock(sk); |
1063 | return -ENOPROTOOPT; | 1133 | return -ENOPROTOOPT; |
1064 | #endif | ||
1065 | } | 1134 | } |
1066 | release_sock(sk); | 1135 | release_sock(sk); |
1067 | 1136 | ||
@@ -1082,6 +1151,67 @@ int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval, | |||
1082 | return 0; | 1151 | return 0; |
1083 | } | 1152 | } |
1084 | 1153 | ||
1154 | int ip_getsockopt(struct sock *sk, int level, | ||
1155 | int optname, char __user *optval, int __user *optlen) | ||
1156 | { | ||
1157 | int err; | ||
1158 | |||
1159 | err = do_ip_getsockopt(sk, level, optname, optval, optlen); | ||
1160 | #ifdef CONFIG_NETFILTER | ||
1161 | /* we need to exclude all possible ENOPROTOOPTs except default case */ | ||
1162 | if (err == -ENOPROTOOPT && optname != IP_PKTOPTIONS | ||
1163 | #ifdef CONFIG_IP_MROUTE | ||
1164 | && (optname < MRT_BASE || optname > MRT_BASE+10) | ||
1165 | #endif | ||
1166 | ) { | ||
1167 | int len; | ||
1168 | |||
1169 | if(get_user(len,optlen)) | ||
1170 | return -EFAULT; | ||
1171 | |||
1172 | lock_sock(sk); | ||
1173 | err = nf_getsockopt(sk, PF_INET, optname, optval, | ||
1174 | &len); | ||
1175 | release_sock(sk); | ||
1176 | if (err >= 0) | ||
1177 | err = put_user(len, optlen); | ||
1178 | return err; | ||
1179 | } | ||
1180 | #endif | ||
1181 | return err; | ||
1182 | } | ||
1183 | |||
1184 | #ifdef CONFIG_COMPAT | ||
1185 | int compat_ip_getsockopt(struct sock *sk, int level, int optname, | ||
1186 | char __user *optval, int __user *optlen) | ||
1187 | { | ||
1188 | int err = do_ip_getsockopt(sk, level, optname, optval, optlen); | ||
1189 | #ifdef CONFIG_NETFILTER | ||
1190 | /* we need to exclude all possible ENOPROTOOPTs except default case */ | ||
1191 | if (err == -ENOPROTOOPT && optname != IP_PKTOPTIONS | ||
1192 | #ifdef CONFIG_IP_MROUTE | ||
1193 | && (optname < MRT_BASE || optname > MRT_BASE+10) | ||
1194 | #endif | ||
1195 | ) { | ||
1196 | int len; | ||
1197 | |||
1198 | if (get_user(len, optlen)) | ||
1199 | return -EFAULT; | ||
1200 | |||
1201 | lock_sock(sk); | ||
1202 | err = compat_nf_getsockopt(sk, PF_INET, optname, optval, &len); | ||
1203 | release_sock(sk); | ||
1204 | if (err >= 0) | ||
1205 | err = put_user(len, optlen); | ||
1206 | return err; | ||
1207 | } | ||
1208 | #endif | ||
1209 | return err; | ||
1210 | } | ||
1211 | |||
1212 | EXPORT_SYMBOL(compat_ip_getsockopt); | ||
1213 | #endif | ||
1214 | |||
1085 | EXPORT_SYMBOL(ip_cmsg_recv); | 1215 | EXPORT_SYMBOL(ip_cmsg_recv); |
1086 | 1216 | ||
1087 | EXPORT_SYMBOL(ip_getsockopt); | 1217 | EXPORT_SYMBOL(ip_getsockopt); |