* This function gets called when we receive an ACK for a * socket in the LISTEN state. We look up the connection * in the syncache, and if its there, we pull it out of * the cache and turn it into a full-blown connection in * the SYN-RECEIVED state. * * On syncache_socket() success the newly created socket * has its underlying inp locked. */
| 1137 | * has its underlying inp locked. |
| 1138 | */ |
| 1139 | int |
| 1140 | syncache_expand(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th, |
| 1141 | struct socket **lsop, struct mbuf *m) |
| 1142 | { |
| 1143 | struct syncache *sc; |
| 1144 | struct syncache_head *sch; |
| 1145 | struct syncache scs; |
| 1146 | char *s; |
| 1147 | bool locked; |
| 1148 | |
| 1149 | NET_EPOCH_ASSERT(); |
| 1150 | KASSERT((th->th_flags & (TH_RST|TH_ACK|TH_SYN)) == TH_ACK, |
| 1151 | ("%s: can handle only ACK", __func__)); |
| 1152 | |
| 1153 | if (syncache_cookiesonly()) { |
| 1154 | sc = NULL; |
| 1155 | sch = syncache_hashbucket(inc); |
| 1156 | locked = false; |
| 1157 | } else { |
| 1158 | sc = syncache_lookup(inc, &sch); /* returns locked sch */ |
| 1159 | locked = true; |
| 1160 | SCH_LOCK_ASSERT(sch); |
| 1161 | } |
| 1162 | |
| 1163 | #ifdef INVARIANTS |
| 1164 | /* |
| 1165 | * Test code for syncookies comparing the syncache stored |
| 1166 | * values with the reconstructed values from the cookie. |
| 1167 | */ |
| 1168 | if (sc != NULL) |
| 1169 | syncookie_cmp(inc, sch, sc, th, to, *lsop); |
| 1170 | #endif |
| 1171 | |
| 1172 | if (sc == NULL) { |
| 1173 | /* |
| 1174 | * There is no syncache entry, so see if this ACK is |
| 1175 | * a returning syncookie. To do this, first: |
| 1176 | * A. Check if syncookies are used in case of syncache |
| 1177 | * overflows |
| 1178 | * B. See if this socket has had a syncache entry dropped in |
| 1179 | * the recent past. We don't want to accept a bogus |
| 1180 | * syncookie if we've never received a SYN or accept it |
| 1181 | * twice. |
| 1182 | * C. check that the syncookie is valid. If it is, then |
| 1183 | * cobble up a fake syncache entry, and return. |
| 1184 | */ |
| 1185 | if (locked && !V_tcp_syncookies) { |
| 1186 | SCH_UNLOCK(sch); |
| 1187 | if ((s = tcp_log_addrs(inc, th, NULL, NULL))) |
| 1188 | log(LOG_DEBUG, "%s; %s: Spurious ACK, " |
| 1189 | "segment rejected (syncookies disabled)\n", |
| 1190 | s, __func__); |
| 1191 | goto failed; |
| 1192 | } |
| 1193 | if (locked && !V_tcp_syncookiesonly && |
| 1194 | sch->sch_last_overflow < time_uptime - SYNCOOKIE_LIFETIME) { |
| 1195 | SCH_UNLOCK(sch); |
| 1196 | if ((s = tcp_log_addrs(inc, th, NULL, NULL))) |
no test coverage detected