ip_vs_pe_sip.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. #define KMSG_COMPONENT "IPVS"
  2. #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
  3. #include <linux/module.h>
  4. #include <linux/kernel.h>
  5. #include <net/ip_vs.h>
  6. #include <net/netfilter/nf_conntrack.h>
  7. #include <linux/netfilter/nf_conntrack_sip.h>
  8. #ifdef CONFIG_IP_VS_DEBUG
  9. static const char *ip_vs_dbg_callid(char *buf, size_t buf_len,
  10. const char *callid, size_t callid_len,
  11. int *idx)
  12. {
  13. size_t max_len = 64;
  14. size_t len = min3(max_len, callid_len, buf_len - *idx - 1);
  15. memcpy(buf + *idx, callid, len);
  16. buf[*idx+len] = '\0';
  17. *idx += len + 1;
  18. return buf + *idx - len;
  19. }
  20. #define IP_VS_DEBUG_CALLID(callid, len) \
  21. ip_vs_dbg_callid(ip_vs_dbg_buf, sizeof(ip_vs_dbg_buf), \
  22. callid, len, &ip_vs_dbg_idx)
  23. #endif
  24. static int get_callid(const char *dptr, unsigned int dataoff,
  25. unsigned int datalen,
  26. unsigned int *matchoff, unsigned int *matchlen)
  27. {
  28. /* Find callid */
  29. while (1) {
  30. int ret = ct_sip_get_header(NULL, dptr, dataoff, datalen,
  31. SIP_HDR_CALL_ID, matchoff,
  32. matchlen);
  33. if (ret > 0)
  34. break;
  35. if (!ret)
  36. return -EINVAL;
  37. dataoff += *matchoff;
  38. }
  39. /* Too large is useless */
  40. if (*matchlen > IP_VS_PEDATA_MAXLEN)
  41. return -EINVAL;
  42. /* SIP headers are always followed by a line terminator */
  43. if (*matchoff + *matchlen == datalen)
  44. return -EINVAL;
  45. /* RFC 2543 allows lines to be terminated with CR, LF or CRLF,
  46. * RFC 3261 allows only CRLF, we support both. */
  47. if (*(dptr + *matchoff + *matchlen) != '\r' &&
  48. *(dptr + *matchoff + *matchlen) != '\n')
  49. return -EINVAL;
  50. IP_VS_DBG_BUF(9, "SIP callid %s (%d bytes)\n",
  51. IP_VS_DEBUG_CALLID(dptr + *matchoff, *matchlen),
  52. *matchlen);
  53. return 0;
  54. }
  55. static int
  56. ip_vs_sip_fill_param(struct ip_vs_conn_param *p, struct sk_buff *skb)
  57. {
  58. struct ip_vs_iphdr iph;
  59. unsigned int dataoff, datalen, matchoff, matchlen;
  60. const char *dptr;
  61. int retc;
  62. retc = ip_vs_fill_iph_skb(p->af, skb, false, &iph);
  63. /* Only useful with UDP */
  64. if (!retc || iph.protocol != IPPROTO_UDP)
  65. return -EINVAL;
  66. /* todo: IPv6 fragments:
  67. * I think this only should be done for the first fragment. /HS
  68. */
  69. dataoff = iph.len + sizeof(struct udphdr);
  70. if (dataoff >= skb->len)
  71. return -EINVAL;
  72. retc = skb_linearize(skb);
  73. if (retc < 0)
  74. return retc;
  75. dptr = skb->data + dataoff;
  76. datalen = skb->len - dataoff;
  77. if (get_callid(dptr, 0, datalen, &matchoff, &matchlen))
  78. return -EINVAL;
  79. /* N.B: pe_data is only set on success,
  80. * this allows fallback to the default persistence logic on failure
  81. */
  82. p->pe_data = kmemdup(dptr + matchoff, matchlen, GFP_ATOMIC);
  83. if (!p->pe_data)
  84. return -ENOMEM;
  85. p->pe_data_len = matchlen;
  86. return 0;
  87. }
  88. static bool ip_vs_sip_ct_match(const struct ip_vs_conn_param *p,
  89. struct ip_vs_conn *ct)
  90. {
  91. bool ret = false;
  92. if (ct->af == p->af &&
  93. ip_vs_addr_equal(p->af, p->caddr, &ct->caddr) &&
  94. /* protocol should only be IPPROTO_IP if
  95. * d_addr is a fwmark */
  96. ip_vs_addr_equal(p->protocol == IPPROTO_IP ? AF_UNSPEC : p->af,
  97. p->vaddr, &ct->vaddr) &&
  98. ct->vport == p->vport &&
  99. ct->flags & IP_VS_CONN_F_TEMPLATE &&
  100. ct->protocol == p->protocol &&
  101. ct->pe_data && ct->pe_data_len == p->pe_data_len &&
  102. !memcmp(ct->pe_data, p->pe_data, p->pe_data_len))
  103. ret = true;
  104. IP_VS_DBG_BUF(9, "SIP template match %s %s->%s:%d %s\n",
  105. ip_vs_proto_name(p->protocol),
  106. IP_VS_DEBUG_CALLID(p->pe_data, p->pe_data_len),
  107. IP_VS_DBG_ADDR(p->af, p->vaddr), ntohs(p->vport),
  108. ret ? "hit" : "not hit");
  109. return ret;
  110. }
  111. static u32 ip_vs_sip_hashkey_raw(const struct ip_vs_conn_param *p,
  112. u32 initval, bool inverse)
  113. {
  114. return jhash(p->pe_data, p->pe_data_len, initval);
  115. }
  116. static int ip_vs_sip_show_pe_data(const struct ip_vs_conn *cp, char *buf)
  117. {
  118. memcpy(buf, cp->pe_data, cp->pe_data_len);
  119. return cp->pe_data_len;
  120. }
  121. static struct ip_vs_pe ip_vs_sip_pe =
  122. {
  123. .name = "sip",
  124. .refcnt = ATOMIC_INIT(0),
  125. .module = THIS_MODULE,
  126. .n_list = LIST_HEAD_INIT(ip_vs_sip_pe.n_list),
  127. .fill_param = ip_vs_sip_fill_param,
  128. .ct_match = ip_vs_sip_ct_match,
  129. .hashkey_raw = ip_vs_sip_hashkey_raw,
  130. .show_pe_data = ip_vs_sip_show_pe_data,
  131. };
  132. static int __init ip_vs_sip_init(void)
  133. {
  134. return register_ip_vs_pe(&ip_vs_sip_pe);
  135. }
  136. static void __exit ip_vs_sip_cleanup(void)
  137. {
  138. unregister_ip_vs_pe(&ip_vs_sip_pe);
  139. synchronize_rcu();
  140. }
  141. module_init(ip_vs_sip_init);
  142. module_exit(ip_vs_sip_cleanup);
  143. MODULE_LICENSE("GPL");