ip_msnrpc_pxy.c revision 369245
1/* $FreeBSD: stable/11/contrib/ipfilter/ip_msnrpc_pxy.c 369245 2021-02-09 13:47:46Z git2svn $ */ 2 3/* 4 * Copyright (C) 2000-2003 by Darren Reed 5 * 6 * See the IPFILTER.LICENCE file for details on licencing. 7 * 8 * Simple DCE transparent proxy for MSN RPC. 9 * 10 * ******* NOTE: THIS PROXY DOES NOT DO ADDRESS TRANSLATION ******** 11 * 12 * Id: ip_msnrpc_pxy.c,v 2.17.2.1 2005/02/04 10:22:55 darrenr Exp 13 */ 14 15#define IPF_MSNRPC_PROXY 16 17#define IPF_MINMSNRPCLEN 24 18#define IPF_MSNRPCSKIP (2 + 19 + 2 + 2 + 2 + 19 + 2 + 2) 19 20 21typedef struct msnrpchdr { 22 u_char mrh_major; /* major # == 5 */ 23 u_char mrh_minor; /* minor # == 0 */ 24 u_char mrh_type; 25 u_char mrh_flags; 26 u_32_t mrh_endian; 27 u_short mrh_dlen; /* data size */ 28 u_short mrh_alen; /* authentication length */ 29 u_32_t mrh_cid; /* call identifier */ 30 u_32_t mrh_hint; /* allocation hint */ 31 u_short mrh_ctxt; /* presentation context hint */ 32 u_char mrh_ccnt; /* cancel count */ 33 u_char mrh_ans; 34} msnrpchdr_t; 35 36int ippr_msnrpc_init(void); 37void ippr_msnrpc_fini(void); 38int ippr_msnrpc_new(fr_info_t *, ap_session_t *, nat_t *); 39int ippr_msnrpc_out(fr_info_t *, ap_session_t *, nat_t *); 40int ippr_msnrpc_in(fr_info_t *, ap_session_t *, nat_t *); 41int ippr_msnrpc_check(ip_t *, msnrpchdr_t *); 42 43static frentry_t msnfr; 44 45int msn_proxy_init = 0; 46 47/* 48 * Initialize local structures. 49 */ 50int ippr_msnrpc_init() 51{ 52 bzero((char *)&msnfr, sizeof(msnfr)); 53 msnfr.fr_ref = 1; 54 msnfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; 55 MUTEX_INIT(&msnfr.fr_lock, "MSN RPC proxy rule lock"); 56 msn_proxy_init = 1; 57 58 return 0; 59} 60 61 62void ippr_msnrpc_fini() 63{ 64 if (msn_proxy_init == 1) { 65 MUTEX_DESTROY(&msnfr.fr_lock); 66 msn_proxy_init = 0; 67 } 68} 69 70 71int ippr_msnrpc_new(fin, aps, nat) 72fr_info_t *fin; 73ap_session_t *aps; 74nat_t *nat; 75{ 76 msnrpcinfo_t *mri; 77 78 KMALLOC(mri, msnrpcinfo_t *); 79 if (mri == NULL) 80 return -1; 81 aps->aps_data = mri; 82 aps->aps_psiz = sizeof(msnrpcinfo_t); 83 84 bzero((char *)mri, sizeof(*mri)); 85 mri->mri_cmd[0] = 0xff; 86 mri->mri_cmd[1] = 0xff; 87 return 0; 88} 89 90 91int ippr_msnrpc_check(ip, mrh) 92ip_t *ip; 93msnrpchdr_t *mrh; 94{ 95 if (mrh->mrh_major != 5) 96 return -1; 97 if (mrh->mrh_minor != 0) 98 return -1; 99 if (mrh->mrh_alen != 0) 100 return -1; 101 if (mrh->mrh_endian == 0x10) { 102 /* Both gateway and packet match endian */ 103 if (mrh->mrh_dlen > ip->ip_len) 104 return -1; 105 if (mrh->mrh_type == 0 || mrh->mrh_type == 2) 106 if (mrh->mrh_hint > ip->ip_len) 107 return -1; 108 } else if (mrh->mrh_endian == 0x10000000) { 109 /* XXX - Endian mismatch - should be swapping! */ 110 return -1; 111 } else { 112 return -1; 113 } 114 return 0; 115} 116 117 118int ippr_msnrpc_out(fin, ip, aps, nat) 119fr_info_t *fin; 120ip_t *ip; 121ap_session_t *aps; 122nat_t *nat; 123{ 124 msnrpcinfo_t *mri; 125 msnrpchdr_t *mrh; 126 tcphdr_t *tcp; 127 int dlen; 128 129 mri = aps->aps_data; 130 if (mri == NULL) 131 return 0; 132 133 tcp = (tcphdr_t *)fin->fin_dp; 134 dlen = fin->fin_dlen - (TCP_OFF(tcp) << 2); 135 if (dlen < IPF_MINMSNRPCLEN) 136 return 0; 137 138 mrh = (msnrpchdr_t *)((char *)tcp + (TCP_OFF(tcp) << 2)); 139 if (ippr_msnrpc_check(ip, mrh)) 140 return 0; 141 142 mri->mri_valid++; 143 144 switch (mrh->mrh_type) 145 { 146 case 0x0b : /* BIND */ 147 case 0x00 : /* REQUEST */ 148 break; 149 case 0x0c : /* BIND ACK */ 150 case 0x02 : /* RESPONSE */ 151 default: 152 return 0; 153 } 154 mri->mri_cmd[1] = mrh->mrh_type; 155 return 0; 156} 157 158 159int ippr_msnrpc_in(fin, ip, aps, nat) 160fr_info_t *fin; 161ip_t *ip; 162ap_session_t *aps; 163nat_t *nat; 164{ 165 tcphdr_t *tcp, tcph, *tcp2 = &tcph; 166 int dlen, sz, sz2, i; 167 msnrpcinfo_t *mri; 168 msnrpchdr_t *mrh; 169 fr_info_t fi; 170 u_short len; 171 char *s; 172 173 mri = aps->aps_data; 174 if (mri == NULL) 175 return 0; 176 tcp = (tcphdr_t *)fin->fin_dp; 177 dlen = fin->fin_dlen - (TCP_OFF(tcp) << 2); 178 if (dlen < IPF_MINMSNRPCLEN) 179 return 0; 180 181 mrh = (msnrpchdr_t *)((char *)tcp + (TCP_OFF(tcp) << 2)); 182 if (ippr_msnrpc_check(ip, mrh)) 183 return 0; 184 185 mri->mri_valid++; 186 187 switch (mrh->mrh_type) 188 { 189 case 0x0c : /* BIND ACK */ 190 if (mri->mri_cmd[1] != 0x0b) 191 return 0; 192 break; 193 case 0x02 : /* RESPONSE */ 194 if (mri->mri_cmd[1] != 0x00) 195 return 0; 196 break; 197 case 0x0b : /* BIND */ 198 case 0x00 : /* REQUEST */ 199 default: 200 return 0; 201 } 202 mri->mri_cmd[0] = mrh->mrh_type; 203 dlen -= sizeof(*mrh); 204 205 /* 206 * Only processes RESPONSE's 207 */ 208 if (mrh->mrh_type != 0x02) 209 return 0; 210 211 /* 212 * Skip over some bytes...what are these really ? 213 */ 214 if (dlen <= 44) 215 return 0; 216 s = (char *)(mrh + 1) + 20; 217 dlen -= 20; 218 bcopy(s, (char *)&len, sizeof(len)); 219 if (len == 1) { 220 s += 20; 221 dlen -= 20; 222 } else if (len == 2) { 223 s += 24; 224 dlen -= 24; 225 } else 226 return 0; 227 228 if (dlen <= 10) 229 return 0; 230 dlen -= 10; 231 bcopy(s, (char *)&sz, sizeof(sz)); 232 s += sizeof(sz); 233 bcopy(s, (char *)&sz2, sizeof(sz2)); 234 s += sizeof(sz2); 235 if (sz2 != sz) 236 return 0; 237 if (sz > dlen) 238 return 0; 239 if (*s++ != 5) 240 return 0; 241 if (*s++ != 0) 242 return 0; 243 sz -= IPF_MSNRPCSKIP; 244 s += IPF_MSNRPCSKIP; 245 dlen -= IPF_MSNRPCSKIP; 246 247 do { 248 if (sz < 7 || dlen < 7) 249 break; 250 bcopy(s, (char *)&len, sizeof(len)); 251 if (dlen < len) 252 break; 253 if (sz < len) 254 break; 255 256 if (len != 1) 257 break; 258 sz -= 3; 259 i = *(s + 2); 260 s += 3; 261 dlen -= 3; 262 263 bcopy(s, (char *)&len, sizeof(len)); 264 if (dlen < len) 265 break; 266 if (sz < len) 267 break; 268 s += sizeof(len); 269 270 switch (i) 271 { 272 case 7 : 273 if (len == 2) { 274 bcopy(s, (char *)&mri->mri_rport, 2); 275 mri->mri_flags |= 1; 276 } 277 break; 278 case 9 : 279 if (len == 4) { 280 bcopy(s, (char *)&mri->mri_raddr, 4); 281 mri->mri_flags |= 2; 282 } 283 break; 284 default : 285 break; 286 } 287 sz -= len; 288 s += len; 289 dlen -= len; 290 } while (sz > 0); 291 292 if (mri->mri_flags == 3) { 293 int slen; 294 295 bcopy((char *)fin, (char *)&fi, sizeof(fi)); 296 bzero((char *)tcp2, sizeof(*tcp2)); 297 298 slen = ip->ip_len; 299 ip->ip_len = fin->fin_hlen + sizeof(*tcp2); 300 bcopy((char *)fin, (char *)&fi, sizeof(fi)); 301 bzero((char *)tcp2, sizeof(*tcp2)); 302 tcp2->th_win = htons(8192); 303 TCP_OFF_A(tcp2, 5); 304 fi.fin_data[0] = htons(mri->mri_rport); 305 tcp2->th_sport = mri->mri_rport; 306 fi.fin_data[1] = 0; 307 tcp2->th_dport = 0; 308 fi.fin_state = NULL; 309 fi.fin_nat = NULL; 310 fi.fin_dlen = sizeof(*tcp2); 311 fi.fin_plen = fi.fin_hlen + sizeof(*tcp2); 312 fi.fin_dp = (char *)tcp2; 313 fi.fin_fi.fi_daddr = ip->ip_dst.s_addr; 314 fi.fin_fi.fi_saddr = mri->mri_raddr.s_addr; 315 if (!fi.fin_fr) 316 fi.fin_fr = &msnfr; 317 if (fr_stlookup(&fi, NULL, NULL)) { 318 RWLOCK_EXIT(&ipf_state); 319 } else { 320 (void) fr_addstate(&fi, NULL, SI_W_DPORT|SI_CLONE); 321 if (fi.fin_state != NULL) 322 fr_statederef(&fi, (ipstate_t **)&fi.fin_state); 323 } 324 ip->ip_len = slen; 325 } 326 mri->mri_flags = 0; 327 return 0; 328} 329