1145519Sdarrenr/* $FreeBSD$ */ 2145510Sdarrenr 3145510Sdarrenr/* 4145510Sdarrenr * Copyright (C) 2000-2003 by Darren Reed 5145510Sdarrenr * 6145510Sdarrenr * See the IPFILTER.LICENCE file for details on licencing. 7145510Sdarrenr * 8145510Sdarrenr * Simple DCE transparent proxy for MSN RPC. 9145510Sdarrenr * 10145510Sdarrenr * ******* NOTE: THIS PROXY DOES NOT DO ADDRESS TRANSLATION ******** 11145510Sdarrenr * 12145510Sdarrenr * Id: ip_msnrpc_pxy.c,v 2.17.2.1 2005/02/04 10:22:55 darrenr Exp 13145510Sdarrenr */ 14145510Sdarrenr 15145510Sdarrenr#define IPF_MSNRPC_PROXY 16145510Sdarrenr 17145510Sdarrenr#define IPF_MINMSNRPCLEN 24 18145510Sdarrenr#define IPF_MSNRPCSKIP (2 + 19 + 2 + 2 + 2 + 19 + 2 + 2) 19145510Sdarrenr 20145510Sdarrenr 21145510Sdarrenrtypedef struct msnrpchdr { 22145510Sdarrenr u_char mrh_major; /* major # == 5 */ 23145510Sdarrenr u_char mrh_minor; /* minor # == 0 */ 24145510Sdarrenr u_char mrh_type; 25145510Sdarrenr u_char mrh_flags; 26145510Sdarrenr u_32_t mrh_endian; 27145510Sdarrenr u_short mrh_dlen; /* data size */ 28145510Sdarrenr u_short mrh_alen; /* authentication length */ 29145510Sdarrenr u_32_t mrh_cid; /* call identifier */ 30145510Sdarrenr u_32_t mrh_hint; /* allocation hint */ 31145510Sdarrenr u_short mrh_ctxt; /* presentation context hint */ 32145510Sdarrenr u_char mrh_ccnt; /* cancel count */ 33145510Sdarrenr u_char mrh_ans; 34145510Sdarrenr} msnrpchdr_t; 35145510Sdarrenr 36145510Sdarrenrint ippr_msnrpc_init __P((void)); 37145510Sdarrenrvoid ippr_msnrpc_fini __P((void)); 38145510Sdarrenrint ippr_msnrpc_new __P((fr_info_t *, ap_session_t *, nat_t *)); 39145510Sdarrenrint ippr_msnrpc_out __P((fr_info_t *, ap_session_t *, nat_t *)); 40145510Sdarrenrint ippr_msnrpc_in __P((fr_info_t *, ap_session_t *, nat_t *)); 41145510Sdarrenrint ippr_msnrpc_check __P((ip_t *, msnrpchdr_t *)); 42145510Sdarrenr 43145510Sdarrenrstatic frentry_t msnfr; 44145510Sdarrenr 45145510Sdarrenrint msn_proxy_init = 0; 46145510Sdarrenr 47145510Sdarrenr/* 48145510Sdarrenr * Initialize local structures. 49145510Sdarrenr */ 50145510Sdarrenrint ippr_msnrpc_init() 51145510Sdarrenr{ 52145510Sdarrenr bzero((char *)&msnfr, sizeof(msnfr)); 53145510Sdarrenr msnfr.fr_ref = 1; 54145510Sdarrenr msnfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; 55145510Sdarrenr MUTEX_INIT(&msnfr.fr_lock, "MSN RPC proxy rule lock"); 56145510Sdarrenr msn_proxy_init = 1; 57145510Sdarrenr 58145510Sdarrenr return 0; 59145510Sdarrenr} 60145510Sdarrenr 61145510Sdarrenr 62145510Sdarrenrvoid ippr_msnrpc_fini() 63145510Sdarrenr{ 64145510Sdarrenr if (msn_proxy_init == 1) { 65145510Sdarrenr MUTEX_DESTROY(&msnfr.fr_lock); 66145510Sdarrenr msn_proxy_init = 0; 67145510Sdarrenr } 68145510Sdarrenr} 69145510Sdarrenr 70145510Sdarrenr 71145510Sdarrenrint ippr_msnrpc_new(fin, aps, nat) 72145510Sdarrenrfr_info_t *fin; 73145510Sdarrenrap_session_t *aps; 74145510Sdarrenrnat_t *nat; 75145510Sdarrenr{ 76145510Sdarrenr msnrpcinfo_t *mri; 77145510Sdarrenr 78145510Sdarrenr KMALLOC(mri, msnrpcinfo_t *); 79145510Sdarrenr if (mri == NULL) 80145510Sdarrenr return -1; 81145510Sdarrenr aps->aps_data = mri; 82145510Sdarrenr aps->aps_psiz = sizeof(msnrpcinfo_t); 83145510Sdarrenr 84145510Sdarrenr bzero((char *)mri, sizeof(*mri)); 85145510Sdarrenr mri->mri_cmd[0] = 0xff; 86145510Sdarrenr mri->mri_cmd[1] = 0xff; 87145510Sdarrenr return 0; 88145510Sdarrenr} 89145510Sdarrenr 90145510Sdarrenr 91145510Sdarrenrint ippr_msnrpc_check(ip, mrh) 92145510Sdarrenrip_t *ip; 93145510Sdarrenrmsnrpchdr_t *mrh; 94145510Sdarrenr{ 95145510Sdarrenr if (mrh->mrh_major != 5) 96145510Sdarrenr return -1; 97145510Sdarrenr if (mrh->mrh_minor != 0) 98145510Sdarrenr return -1; 99145510Sdarrenr if (mrh->mrh_alen != 0) 100145510Sdarrenr return -1; 101145510Sdarrenr if (mrh->mrh_endian == 0x10) { 102145510Sdarrenr /* Both gateway and packet match endian */ 103145510Sdarrenr if (mrh->mrh_dlen > ip->ip_len) 104145510Sdarrenr return -1; 105145510Sdarrenr if (mrh->mrh_type == 0 || mrh->mrh_type == 2) 106145510Sdarrenr if (mrh->mrh_hint > ip->ip_len) 107145510Sdarrenr return -1; 108145510Sdarrenr } else if (mrh->mrh_endian == 0x10000000) { 109145510Sdarrenr /* XXX - Endian mismatch - should be swapping! */ 110145510Sdarrenr return -1; 111145510Sdarrenr } else { 112145510Sdarrenr return -1; 113145510Sdarrenr } 114145510Sdarrenr return 0; 115145510Sdarrenr} 116145510Sdarrenr 117145510Sdarrenr 118145510Sdarrenrint ippr_msnrpc_out(fin, ip, aps, nat) 119145510Sdarrenrfr_info_t *fin; 120145510Sdarrenrip_t *ip; 121145510Sdarrenrap_session_t *aps; 122145510Sdarrenrnat_t *nat; 123145510Sdarrenr{ 124145510Sdarrenr msnrpcinfo_t *mri; 125145510Sdarrenr msnrpchdr_t *mrh; 126145510Sdarrenr tcphdr_t *tcp; 127145510Sdarrenr int dlen; 128145510Sdarrenr 129145510Sdarrenr mri = aps->aps_data; 130145510Sdarrenr if (mri == NULL) 131145510Sdarrenr return 0; 132145510Sdarrenr 133145510Sdarrenr tcp = (tcphdr_t *)fin->fin_dp; 134145510Sdarrenr dlen = fin->fin_dlen - (TCP_OFF(tcp) << 2); 135145510Sdarrenr if (dlen < IPF_MINMSNRPCLEN) 136145510Sdarrenr return 0; 137145510Sdarrenr 138145510Sdarrenr mrh = (msnrpchdr_t *)((char *)tcp + (TCP_OFF(tcp) << 2)); 139145510Sdarrenr if (ippr_msnrpc_check(ip, mrh)) 140145510Sdarrenr return 0; 141145510Sdarrenr 142145510Sdarrenr mri->mri_valid++; 143145510Sdarrenr 144145510Sdarrenr switch (mrh->mrh_type) 145145510Sdarrenr { 146145510Sdarrenr case 0x0b : /* BIND */ 147145510Sdarrenr case 0x00 : /* REQUEST */ 148145510Sdarrenr break; 149145510Sdarrenr case 0x0c : /* BIND ACK */ 150145510Sdarrenr case 0x02 : /* RESPONSE */ 151145510Sdarrenr default: 152145510Sdarrenr return 0; 153145510Sdarrenr } 154145510Sdarrenr mri->mri_cmd[1] = mrh->mrh_type; 155145510Sdarrenr return 0; 156145510Sdarrenr} 157145510Sdarrenr 158145510Sdarrenr 159145510Sdarrenrint ippr_msnrpc_in(fin, ip, aps, nat) 160145510Sdarrenrfr_info_t *fin; 161145510Sdarrenrip_t *ip; 162145510Sdarrenrap_session_t *aps; 163145510Sdarrenrnat_t *nat; 164145510Sdarrenr{ 165145510Sdarrenr tcphdr_t *tcp, tcph, *tcp2 = &tcph; 166145510Sdarrenr int dlen, sz, sz2, i; 167145510Sdarrenr msnrpcinfo_t *mri; 168145510Sdarrenr msnrpchdr_t *mrh; 169145510Sdarrenr fr_info_t fi; 170145510Sdarrenr u_short len; 171145510Sdarrenr char *s; 172145510Sdarrenr 173145510Sdarrenr mri = aps->aps_data; 174145510Sdarrenr if (mri == NULL) 175145510Sdarrenr return 0; 176145510Sdarrenr tcp = (tcphdr_t *)fin->fin_dp; 177145510Sdarrenr dlen = fin->fin_dlen - (TCP_OFF(tcp) << 2); 178145510Sdarrenr if (dlen < IPF_MINMSNRPCLEN) 179145510Sdarrenr return 0; 180145510Sdarrenr 181145510Sdarrenr mrh = (msnrpchdr_t *)((char *)tcp + (TCP_OFF(tcp) << 2)); 182145510Sdarrenr if (ippr_msnrpc_check(ip, mrh)) 183145510Sdarrenr return 0; 184145510Sdarrenr 185145510Sdarrenr mri->mri_valid++; 186145510Sdarrenr 187145510Sdarrenr switch (mrh->mrh_type) 188145510Sdarrenr { 189145510Sdarrenr case 0x0c : /* BIND ACK */ 190145510Sdarrenr if (mri->mri_cmd[1] != 0x0b) 191145510Sdarrenr return 0; 192145510Sdarrenr break; 193145510Sdarrenr case 0x02 : /* RESPONSE */ 194145510Sdarrenr if (mri->mri_cmd[1] != 0x00) 195145510Sdarrenr return 0; 196145510Sdarrenr break; 197145510Sdarrenr case 0x0b : /* BIND */ 198145510Sdarrenr case 0x00 : /* REQUEST */ 199145510Sdarrenr default: 200145510Sdarrenr return 0; 201145510Sdarrenr } 202145510Sdarrenr mri->mri_cmd[0] = mrh->mrh_type; 203145510Sdarrenr dlen -= sizeof(*mrh); 204145510Sdarrenr 205145510Sdarrenr /* 206145510Sdarrenr * Only processes RESPONSE's 207145510Sdarrenr */ 208145510Sdarrenr if (mrh->mrh_type != 0x02) 209145510Sdarrenr return 0; 210145510Sdarrenr 211145510Sdarrenr /* 212145510Sdarrenr * Skip over some bytes...what are these really ? 213145510Sdarrenr */ 214145510Sdarrenr if (dlen <= 44) 215145510Sdarrenr return 0; 216145510Sdarrenr s = (char *)(mrh + 1) + 20; 217145510Sdarrenr dlen -= 20; 218145510Sdarrenr bcopy(s, (char *)&len, sizeof(len)); 219145510Sdarrenr if (len == 1) { 220145510Sdarrenr s += 20; 221145510Sdarrenr dlen -= 20; 222145510Sdarrenr } else if (len == 2) { 223145510Sdarrenr s += 24; 224145510Sdarrenr dlen -= 24; 225145510Sdarrenr } else 226145510Sdarrenr return 0; 227145510Sdarrenr 228145510Sdarrenr if (dlen <= 10) 229145510Sdarrenr return 0; 230145510Sdarrenr dlen -= 10; 231145510Sdarrenr bcopy(s, (char *)&sz, sizeof(sz)); 232145510Sdarrenr s += sizeof(sz); 233145510Sdarrenr bcopy(s, (char *)&sz2, sizeof(sz2)); 234145510Sdarrenr s += sizeof(sz2); 235145510Sdarrenr if (sz2 != sz) 236145510Sdarrenr return 0; 237145510Sdarrenr if (sz > dlen) 238145510Sdarrenr return 0; 239145510Sdarrenr if (*s++ != 5) 240145510Sdarrenr return 0; 241145510Sdarrenr if (*s++ != 0) 242145510Sdarrenr return 0; 243145510Sdarrenr sz -= IPF_MSNRPCSKIP; 244145510Sdarrenr s += IPF_MSNRPCSKIP; 245145510Sdarrenr dlen -= IPF_MSNRPCSKIP; 246145510Sdarrenr 247145510Sdarrenr do { 248145510Sdarrenr if (sz < 7 || dlen < 7) 249145510Sdarrenr break; 250145510Sdarrenr bcopy(s, (char *)&len, sizeof(len)); 251145510Sdarrenr if (dlen < len) 252145510Sdarrenr break; 253145510Sdarrenr if (sz < len) 254145510Sdarrenr break; 255145510Sdarrenr 256145510Sdarrenr if (len != 1) 257145510Sdarrenr break; 258145510Sdarrenr sz -= 3; 259145510Sdarrenr i = *(s + 2); 260145510Sdarrenr s += 3; 261145510Sdarrenr dlen -= 3; 262145510Sdarrenr 263145510Sdarrenr bcopy(s, (char *)&len, sizeof(len)); 264145510Sdarrenr if (dlen < len) 265145510Sdarrenr break; 266145510Sdarrenr if (sz < len) 267145510Sdarrenr break; 268145510Sdarrenr s += sizeof(len); 269145510Sdarrenr 270145510Sdarrenr switch (i) 271145510Sdarrenr { 272145510Sdarrenr case 7 : 273145510Sdarrenr if (len == 2) { 274145510Sdarrenr bcopy(s, (char *)&mri->mri_rport, 2); 275145510Sdarrenr mri->mri_flags |= 1; 276145510Sdarrenr } 277145510Sdarrenr break; 278145510Sdarrenr case 9 : 279145510Sdarrenr if (len == 4) { 280145510Sdarrenr bcopy(s, (char *)&mri->mri_raddr, 4); 281145510Sdarrenr mri->mri_flags |= 2; 282145510Sdarrenr } 283145510Sdarrenr break; 284145510Sdarrenr default : 285145510Sdarrenr break; 286145510Sdarrenr } 287145510Sdarrenr sz -= len; 288145510Sdarrenr s += len; 289145510Sdarrenr dlen -= len; 290145510Sdarrenr } while (sz > 0); 291145510Sdarrenr 292145510Sdarrenr if (mri->mri_flags == 3) { 293145510Sdarrenr int slen; 294145510Sdarrenr 295145510Sdarrenr bcopy((char *)fin, (char *)&fi, sizeof(fi)); 296145510Sdarrenr bzero((char *)tcp2, sizeof(*tcp2)); 297145510Sdarrenr 298145510Sdarrenr slen = ip->ip_len; 299145510Sdarrenr ip->ip_len = fin->fin_hlen + sizeof(*tcp2); 300145510Sdarrenr bcopy((char *)fin, (char *)&fi, sizeof(fi)); 301145510Sdarrenr bzero((char *)tcp2, sizeof(*tcp2)); 302145510Sdarrenr tcp2->th_win = htons(8192); 303145510Sdarrenr TCP_OFF_A(tcp2, 5); 304145510Sdarrenr fi.fin_data[0] = htons(mri->mri_rport); 305145510Sdarrenr tcp2->th_sport = mri->mri_rport; 306145510Sdarrenr fi.fin_data[1] = 0; 307145510Sdarrenr tcp2->th_dport = 0; 308145510Sdarrenr fi.fin_state = NULL; 309145510Sdarrenr fi.fin_nat = NULL; 310145510Sdarrenr fi.fin_dlen = sizeof(*tcp2); 311145510Sdarrenr fi.fin_plen = fi.fin_hlen + sizeof(*tcp2); 312145510Sdarrenr fi.fin_dp = (char *)tcp2; 313145510Sdarrenr fi.fin_fi.fi_daddr = ip->ip_dst.s_addr; 314145510Sdarrenr fi.fin_fi.fi_saddr = mri->mri_raddr.s_addr; 315145510Sdarrenr if (!fi.fin_fr) 316145510Sdarrenr fi.fin_fr = &msnfr; 317145510Sdarrenr if (fr_stlookup(&fi, NULL, NULL)) { 318145510Sdarrenr RWLOCK_EXIT(&ipf_state); 319145510Sdarrenr } else { 320145510Sdarrenr (void) fr_addstate(&fi, NULL, SI_W_DPORT|SI_CLONE); 321145510Sdarrenr if (fi.fin_state != NULL) 322145510Sdarrenr fr_statederef(&fi, (ipstate_t **)&fi.fin_state); 323145510Sdarrenr } 324145510Sdarrenr ip->ip_len = slen; 325145510Sdarrenr } 326145510Sdarrenr mri->mri_flags = 0; 327145510Sdarrenr return 0; 328145510Sdarrenr} 329