背景:
我们这个项目需要做软件的网络地址转换NAT,由于是嵌入式产品,且只需要操作NAT表,且SDK中没有提供NAT相关的库。
故没有考虑使用现成的库,该用直接使用socket接口操作kernel的NAT表。
socketId = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
getsockopt(g_IptableSocketId, IPPROTO_IP, IPT_SO_GET_REVISION_MATCH, &g_stUdpMatchRevision, &dwOptLen);
现象:
程序交叉编译后,下到目标板运行时,上述的getsockopt返回失败,errno=92. why?
原因分析:
1.当socket()创建socket时,
SYSCALL_DEFINE3(socket) --->sock_create()--->__sock_create()--(AF_INET)-> inet_create()
inet_create()
{
//关注该函数所挂载在socket上的ops和prot。在我的程序里,这里挂载的分别是inet_sockraw_ops和raw_prot
}
2.当getsockopt()时,
SYSCALL_DEFINE5(getsockopt)--->sock_common_getsockopt()--->raw_getsockopt()
static int raw_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen)
{
if (level != SOL_RAW)
return ip_getsockopt(sk, level, optname, optval, optlen);
return do_raw_getsockopt(sk, level, optname, optval, optlen);
}
我们的level是IPROTO_IP,故这里进入ip_getsockopt()
int ip_getsockopt(struct sock *sk, int level,
int optname, char __user *optval, int __user *optlen)
{
int err;
err = do_ip_getsockopt(sk, level, optname, optval, optlen);
#ifdef CONFIG_NETFILTER
/* we need to exclude all possible ENOPROTOOPTs except default case */
if (err == -ENOPROTOOPT && optname != IP_PKTOPTIONS &&
!ip_mroute_opt(optname)) {
int len;
if (get_user(len, optlen))
return -EFAULT;
lock_sock(sk);
err = nf_getsockopt(sk, PF_INET, optname, optval,
&len);
release_sock(sk);
if (err >= 0)
err = put_user(len, optlen);
return err;
}
#endif
return err;
}
函数do_ip_getsockopt()的switch...case中没有我们的IPT_SO_GET_REVISION_MATCH,故进入default后会返回-ENOPROTOOPT(92)。
假设我们打开了CONFIG_NETFILTER,则会进入nf_getsockopt()去处理我们的IPT_SO_GET_REVISION_MATCH请求。
所以,基本上已经看出来了问题所在。很可能就是kernel的CONFIG_NETFILTER没有配置。
于是返回linux kernel source中查看.config文件。果然,这个CONFIG_NETFILTER没有配置。
至此,该问题已经解决。